#ifndef PEP_JSON_SERVER_INOUT_HH #define PEP_JSON_SERVER_INOUT_HH #include "json_spirit/json_spirit_value.h" #include "context.hh" #include #include // Just for debugging: #include // is a bitfield that controls the In<> / Out<> parameter types enum class ParamFlag : unsigned { Default = 0, NoInput = 1, // has no input parameter in the JSON API. Value comes from Context. DontOwn = 2, // parameter holds a "shared resource". Don't free() it in destructor. NullOkay = 4, // JSON 'null' value accepted, will become a C NULL pointer. }; inline constexpr ParamFlag operator|(ParamFlag a, ParamFlag b) { return ParamFlag( unsigned(a) | unsigned(b) ); } inline constexpr ParamFlag operator&(ParamFlag a, ParamFlag b) { return ParamFlag( unsigned(a) & unsigned(b) ); } inline constexpr bool operator!(ParamFlag pf) { return !unsigned(pf); } namespace js = json_spirit; template T from_json(const js::Value& v); template js::Value to_json(const T& t); // common stuff in base class template struct InBase { typedef T c_type; // the according type in C function parameter enum { is_output = false, need_input = !(PF & ParamFlag::NoInput) }; InBase(const InBase& other) = delete; InBase(InBase&& victim) = delete; void operator=(const InBase&) = delete; js::Value to_json() const { throw std::logic_error( std::string("Never call to_json() for a In<") + typeid(T).name() + "> data type! fn=" + __PRETTY_FUNCTION__ ); } c_type get_value() const { return value; } T value; protected: explicit InBase(T&& t) : value(t) {} }; // helper classes to specify in- and out-parameters template struct In : public InBase { typedef InBase Base; ~In(); // default implementation: In(const js::Value& v, Context*, unsigned param_nr) : Base( from_json(v) ) { } }; template struct In : public InBase { typedef InBase Base; ~In() {} // default implementation: ignore all parameters In(const js::Value&, Context*, unsigned param_nr) : Base{ T{} } { } }; class JsonAdapter; template<> struct In : public InBase { typedef InBase Base; ~In() {} // defined in json-adapter.cc In(const js::Value&, Context*, unsigned param_nr); }; // to call functions that operate directly on the JSON data type template struct InRaw : public InBase { ~InRaw() = default; // default implementation: InRaw(const js::Value& v, Context*, unsigned param_nr) : InBase(v) { } }; // helper classes to specify in- and out-parameters whose output is in-place. // Use InOutP for in/out parameters where the function might change the object and expects a pointer template struct InOut : public In { typedef In Base; enum { is_output = true, need_input = !(PF & ParamFlag::NoInput) }; InOut(const js::Value& v, Context* ctx, unsigned param_nr) : Base(v, ctx, param_nr) { } js::Value to_json() const { return ::to_json(Base::value); } }; template struct Out { typedef T* c_type; // the according type in C function parameter enum { is_output = true, need_input = !(PF & ParamFlag::NoInput) }; // if need_input=false it would no longer consume an element in the input parameter array. explicit Out() : value{} { } explicit Out(const T& t) : value{t} { } ~Out(); Out(const Out& other) = delete; Out(Out&& victim) = delete; // just to be sure they are not implicitly defined: Out& operator=(const Out& other) = delete; Out& operator=(Out&& victim) = delete; // dummy Value v is ignored for output parameters Out(const js::Value& v, Context*, unsigned param_nr) : Out() { } js::Value to_json() const { return ::to_json(value); } c_type get_value() const { return &value; } mutable T value; /* friend std::ostream& operator<<(std::ostream& o, const Out& out) { o << (const void*)out; o << ", value=" << (const void*)out.value; return o; } */ }; // helper classes to specify in- and out-parameters whose output might change by the called function. // Use InOut for in/out parameters where the function only makes in-place changes. template struct InOutP : public Out { typedef Out Base; enum { is_output = true, need_input = !(PF & ParamFlag::NoInput) }; explicit InOutP(const T& t) : Base(t) {} InOutP& operator=(const InOutP&) = delete; // default implementation: InOutP(const js::Value& v, Context*, unsigned param_nr) : Base( from_json(v) ) { } }; template js::Value to_json(const Out& o) { return ::to_json(o.value); } template js::Value to_json(const InOut& o) { return ::to_json(o.value); } // Type2String template struct Type2String { static js::Value get(); }; template struct Type2String> { static js::Value get() { js::Object ret; ret.emplace_back("direction", "In"); ret.emplace_back("type", Type2String::get() ); return ret; } }; template struct Type2String> { static js::Value get() { throw std::logic_error("Stupid MSVC compiler requiring this!"); } }; template struct Type2String> { static js::Value get() { js::Object ret; ret.emplace_back("direction", "In"); ret.emplace_back("type", Type2String::get() ); return ret; } }; template struct Type2String> { static js::Value get() { js::Object ret; ret.emplace_back("direction", "Out"); ret.emplace_back("type", Type2String::get() ); return ret; } }; template struct Type2String> { static js::Value get() { js::Object ret; ret.emplace_back("direction", "InOut"); ret.emplace_back("type", Type2String::get() ); return ret; } }; template struct Type2String> { static js::Value get() { js::Object ret; ret.emplace_back("direction", "InOut"); ret.emplace_back("type", Type2String::get() ); return ret; } }; template struct Type2Json; template struct Type2Json { static js::Array& get(js::Array& a) { if(T::need_input) { a.push_back( Type2String::get() ); } Type2Json::get(a); return a; } }; template<> struct Type2Json<> { static js::Array& get(js::Array& a) { return a; } }; #endif // PEP_JSON_SERVER_INOUT_HH