4#include <rapidjson/document.h>
5#include <rapidjson/stringbuffer.h>
6#include <rapidjson/writer.h>
21#define JSONIPC_ISLIKELY(expr) __builtin_expect (bool (expr), 1)
22#define JSONIPC_UNLIKELY(expr) __builtin_expect (bool (expr), 0)
23#define JSONIPC_WARNING(fmt,...) do { fprintf (stderr, "%s:%d: warning: ", __FILE__, __LINE__); fprintf (stderr, fmt, __VA_ARGS__); fputs ("\n", stderr); } while (0)
24#define JSONIPC_ASSERT_RETURN(expr,...) do { if (JSONIPC_ISLIKELY (expr)) break; fprintf (stderr, "%s:%d: assertion failed: %s\n", __FILE__, __LINE__, #expr); return __VA_ARGS__; } while (0)
28#ifdef JSONIPC_CUSTOM_SHARED_BASE
29using SharedBase = JSONIPC_CUSTOM_SHARED_BASE;
39using JsonValue = rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >;
40using JsonAllocator = rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>;
41using StringBufferWriter = rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>, rapidjson::UTF8<>, rapidjson::CrtAllocator, rapidjson::kWriteNanAndInfNullFlag>;
42static constexpr const unsigned rapidjson_parse_flags =
43 rapidjson::kParseFullPrecisionFlag |
44 rapidjson::kParseCommentsFlag |
45 rapidjson::kParseTrailingCommasFlag |
46 rapidjson::kParseNanAndInfFlag |
47 rapidjson::kParseEscapedApostropheFlag;
52string_format (
const char *format, ...)
56 static locale_t posix_c_locale =
newlocale (LC_ALL_MASK,
"C", NULL);
57 locale_t saved_locale =
uselocale (posix_c_locale);
58 constexpr const size_t maxlen = 8192;
59 char buffer[maxlen + 1 + 1] = { 0, };
60 vsnprintf (buffer, maxlen, format, vargs);
68template<
bool value>
using REQUIRES = typename ::std::enable_if<value, bool>::type;
71template<
bool value>
using REQUIRESv = typename ::std::enable_if<value, void>::type;
78static inline constexpr bool
79constexpr_equals (
const char *a,
const char *b,
size_t n)
81 return n == 0 || (a[0] == b[0] && (a[0] == 0 || constexpr_equals (a + 1, b + 1, n - 1)));
89string_demangle_cxx (
const char *mangled_identifier)
92 char *malloced_result = abi::__cxa_demangle (mangled_identifier, NULL, NULL, &status);
93 std::string result = malloced_result && !status ? malloced_result : mangled_identifier;
95 free (malloced_result);
132template<typename T, REQUIRES< Has___typename__<T>::value > =
true>
static inline std::string
133get___typename__ (
const T &o)
135 return o.__typename__();
137template<typename T, REQUIRES< !Has___typename__<T>::value > =
true>
static inline std::string
138get___typename__ (
const T &o)
140 return rtti_typename (o);
145 const char* what ()
const noexcept override {
return reason_; }
146 int code ()
const noexcept {
return code_; }
147 explicit bad_invocation (
int code,
const char *staticreason) noexcept :
148 reason_ (staticreason), code_ (code) {}
150 const char *
const reason_;
156template<
typename>
struct Class;
176 auto &stack_ = stack();
177 return stack_.empty() ? nullptr : stack_.back();
183 Scope *scope = head();
185 throw std::logic_error (
"Jsonipc::Scope::make_shared(): invalid Scope: nullptr");
190 scope->localsp_->push_back (sptr);
197 Scope *scope = head();
199 throw std::logic_error (
"Jsonipc::Scope::instance_map(): invalid Scope: nullptr");
200 return scope ? &scope->instance_map_ :
nullptr;
205 auto &stack_ = stack();
206 stack_.erase (std::remove (stack_.begin(), stack_.end(),
this), stack_.end());
212template<
typename T,
typename Enable =
void>
219 from_json (
const JsonValue &value, T fallback = T())
221 if (value.IsBool())
return value.GetBool();
222 else if (value.IsInt())
return value.GetInt();
223 else if (value.IsUint())
return value.GetUint();
224 else if (value.IsInt64())
return value.GetInt64();
225 else if (value.IsUint64())
return value.GetUint64();
226 else if (value.IsDouble())
return value.GetDouble();
227 else return fallback;
230 to_json (T i, JsonAllocator &allocator)
232 return JsonValue (i);
240 from_json (
const JsonValue &value,
bool fallback =
bool())
245 to_json (
bool b, JsonAllocator &allocator)
247 return JsonValue (b);
255 from_json (
const JsonValue &value, T fallback = T())
257 if (value.IsBool())
return value.GetBool();
258 else if (value.IsInt())
return value.GetInt();
259 else if (value.IsUint())
return value.GetUint();
260 else if (value.IsInt64())
return value.GetInt64();
261 else if (value.IsUint64())
return value.GetUint64();
262 else if (value.IsDouble())
return value.GetDouble();
263 else return fallback;
266 to_json (T f, JsonAllocator &allocator)
268 return JsonValue (f);
276 from_json (
const JsonValue &value,
const char *fallback =
"")
278 return value.IsString() ? value.GetString() : fallback;
281 to_json (
const char *str,
size_t l, JsonAllocator &allocator)
283 return str ? JsonValue (str, l, allocator) : JsonValue();
286 to_json (
const char *str, JsonAllocator &allocator)
288 return str ? JsonValue (str,
strlen (str), allocator) : JsonValue();
298 return value.IsString() ?
std::string (value.GetString(), value.GetStringLength()) : fallback;
301 to_json (
const std::string &s, JsonAllocator &allocator)
303 return JsonValue (s.
data(), s.
size(), allocator);
310template<
class T>
struct DerivesVector<T,
std::void_t< typename T::value_type, typename T::allocator_type >> :
311 std::is_base_of< std::vector<typename T::value_type, typename T::allocator_type>, T > {};
316template<
class T>
struct DerivesPair<T,
std::void_t< typename T::first_type, typename T::second_type >> :
317 std::is_base_of< std::pair<typename T::first_type, typename T::second_type>, T > {};
323 from_json (
const JsonValue &jarray)
326 if (jarray.IsArray())
328 vec.reserve (jarray.Size());
329 for (
size_t i = 0; i < jarray.Size(); i++)
335 to_json (
const T &vec, JsonAllocator &allocator)
337 JsonValue jarray (rapidjson::kArrayType);
338 jarray.Reserve (vec.size(), allocator);
339 for (
size_t i = 0; i < vec.size(); ++i)
349 from_json (
const JsonValue &jarray)
352 if (jarray.IsArray() && jarray.Size() >= 2)
360 to_json (
const T &pair, JsonAllocator &allocator)
362 JsonValue jarray (rapidjson::kArrayType);
363 jarray.Reserve (2, allocator);
379template<
typename T>
static inline auto
380from_json (
const JsonValue &value)
387template<
typename T>
static inline auto
388from_json (
const JsonValue &value,
const T &fallback)
389 ->
decltype (Convert<T>::from_json (value, fallback))
391 return Convert<T>::from_json (value, fallback);
395template<
typename T>
static inline JsonValue
396to_json (
const T &value, JsonAllocator &allocator)
398 return Convert<T>::to_json (value, allocator);
402template<>
inline JsonValue
403to_json<const char*> (
const char *
const &value, JsonAllocator &allocator)
409template<
size_t N>
static inline auto
410to_json (
const char (&c)[N], JsonAllocator &allocator)
412 return Convert<const char*>::to_json (c, N - 1, allocator);
414template<
size_t N>
static inline auto
415to_json (
const char (&c)[N],
size_t l, JsonAllocator &allocator)
417 return Convert<const char*>::to_json (c, l, allocator);
422jsonvalue_to_string (
const JsonValue &value)
424 rapidjson::StringBuffer buffer;
425 StringBufferWriter writer (buffer);
426 value.Accept (writer);
427 const std::string output { buffer.GetString(), buffer.GetSize() };
432template<
class T1,
class T2 =
bool,
class T3 =
bool,
class T4 =
bool>
static inline std::string
433jsonobject_to_string (
const char *m1, T1 &&v1,
const char *m2 = 0, T2 &&v2 = {},
434 const char *m3 = 0, T3 &&v3 = {},
const char *m4 = 0, T4 &&v4 = {})
436 rapidjson::Document doc (rapidjson::kObjectType);
437 auto &a = doc.GetAllocator();
438 if (m1 && m1[0]) doc.AddMember (JsonValue (m1, a), to_json (v1, a), a);
439 if (m2 && m2[0]) doc.AddMember (JsonValue (m2, a), to_json (v2, a), a);
440 if (m3 && m3[0]) doc.AddMember (JsonValue (m3, a), to_json (v3, a), a);
441 if (m4 && m4[0]) doc.AddMember (JsonValue (m4, a), to_json (v4, a), a);
442 return jsonvalue_to_string (doc);
451 explicit CallbackInfo (
const JsonValue &args, JsonAllocator *allocator =
nullptr) :
452 args_ (args), doc_ (allocator)
454 const JsonValue& ntharg (
size_t index)
const {
static JsonValue
j0;
return index < args_.Size() ? args_[index] :
j0; }
455 size_t n_args ()
const {
return args_.Size(); }
456 Closure* find_closure (
const char *methodname);
458 JsonAllocator& allocator () {
return doc_.GetAllocator(); }
459 void set_result (JsonValue &result) { result_ = result; have_result_ =
true; }
460 JsonValue& get_result () {
return result_; }
461 bool have_result ()
const {
return have_result_; }
462 rapidjson::Document& document () {
return doc_; }
464 const JsonValue &args_;
466 bool have_result_ =
false;
467 rapidjson::Document doc_;
474 using ReturnType = R;
479template<
typename C,
typename R,
typename ...Args>
485template<
typename C,
typename R,
typename ...Args>
497template<
typename C,
typename R>
499 template<
typename D = C>
using PointerType = R (D::*);
513 template<
size_t INDEX>
struct TupleElement<INDEX, false> {
using Type = void; };
514 template<
size_t INDEX>
using ArgType =
typename TupleElement<HAS_THIS + INDEX, (INDEX < N_ARGS)>::Type;
517 template<
size_t INDEX>
static ConvertType<INDEX>
525 return (obj.*func) (arg_from_json<INDICES> (args)...);
530template<
typename T,
typename F>
static inline typename FunctionTraits<F>::ReturnType
531call_from_json (T &obj,
const F &func,
const CallbackInfo &args)
533 using CallTraits = CallTraits<F>;
544 operator< (
const TypeidKey &other)
const noexcept
546 return tindex < other.tindex || (tindex == other.tindex && ptr < other.ptr);
551 virtual TypeidKey typeid_key () = 0;
555 virtual Closure* lookup_closure (
const char *method) = 0;
556 virtual void try_upcast (
const std::string &baseclass,
void *sptrB) = 0;
562 register_wrapper (CreateWrapper createwrapper)
564 wrapper_creators().push_back (createwrapper);
577 TypeidKey typeid_key ()
override {
return create_typeid_key (sptr_); }
578 void try_upcast (
const std::string &baseclass,
void *sptrB)
override
583 return {
typeid (T), sptr.get() };
596 IdSet *idset_ =
nullptr;
597 static size_t next_counter() {
static size_t counter_ = 0;
return ++counter_; }
599 delete_id (
size_t thisid)
601 const auto w = wmap_.
find (thisid);
602 if (w != wmap_.
end())
604 Wrapper *wrapper = w->second;
606 const auto t = typeid_map_.
find (wrapper->typeid_key());
607 if (t != typeid_map_.
end())
608 typeid_map_.
erase (t);
611 idset_->
erase (thisid);
622 idset_ =
new IdSet();
631 idset_->
swap (preserve);
635 auto contains = [] (
const auto &c,
const auto &e) {
636 return c.end() != c.find (e);
638 size_t preserved = 0;
639 for (
const size_t id : unused)
649 return wmap_.
empty();
657 clear (
const bool printdebug =
false)
667 for (
auto &pair : old)
669 Wrapper *wrapper = pair.second;
671 fprintf (stderr,
"Jsonipc::~Wrapper: %s: $id=%zu\n", string_demangle_cxx (wrapper->typeid_key().tindex.name()).c_str(), pair.first);
679 JSONIPC_ASSERT_RETURN (wmap_.
size() == 0);
680 JSONIPC_ASSERT_RETURN (typeid_map_.
size() == 0);
683 wrapper_to_json (Wrapper *wrapper,
const size_t thisid, JsonAllocator &allocator)
687 JsonValue jobject (rapidjson::kObjectType);
688 jobject.AddMember (
"$id", thisid, allocator);
689 jobject.AddMember (
"$class", JsonValue (wrapper->classname().c_str(), allocator), allocator);
692 template<
typename T>
static JsonValue
695 InstanceMap *imap = Scope::instance_map();
697 Wrapper *wrapper =
nullptr;
700 const TypeidKey tkey = InstanceWrapper<T>::create_typeid_key (sptr);
701 auto it = imap->typeid_map_.find (tkey);
702 if (it == imap->typeid_map_.end())
704 thisid = next_counter();
707 size_t basedepth = 0;
708 for (
size_t i = 0; i < wcreators.size(); i++) {
709 Wrapper *w = wcreators[i] (sptr, basedepth);
717 wrapper =
new InstanceWrapper<T> (sptr);
718 imap->wmap_[thisid] = wrapper;
719 imap->typeid_map_[tkey] = thisid;
724 auto wt = imap->wmap_.find (thisid);
725 wrapper = wt != imap->wmap_.end() ? wt->second :
nullptr;
729 imap->idset_->insert (thisid);
736 return imap->wrapper_to_json (wrapper, thisid, allocator);
739 wrapper_from_json (
const JsonValue &value)
741 if (value.IsObject())
743 auto it = value.FindMember (
"$id");
744 if (it != value.MemberEnd())
746 const size_t thisid = Convert<size_t>::from_json (it->value);
749 auto tit = wmap_.
find (thisid);
750 if (tit != wmap_.
end())
758 scope_lookup_wrapper (
const JsonValue &value)
760 InstanceMap *imap = Scope::instance_map();
761 return imap ? imap->wrapper_from_json (value) :
nullptr;
764 scope_forget_id (
size_t thisid)
766 InstanceMap *imap = Scope::instance_map();
767 return imap->delete_id (thisid);
772CallbackInfo::find_closure (
const char *methodname)
774 const JsonValue &value = ntharg (0);
775 InstanceMap::Wrapper *iw = InstanceMap::scope_lookup_wrapper (value);
776 return iw ? iw->lookup_closure (methodname) :
nullptr;
780CallbackInfo::classname (
const std::string &fallback)
const
782 const JsonValue &value = ntharg (0);
783 InstanceMap::Wrapper *iw = InstanceMap::scope_lookup_wrapper (value);
784 return iw ? iw->classname() : fallback;
788Scope::Scope (InstanceMap &instance_map, ScopeLocalsP localsp) :
789 instance_map_ (instance_map), localsp_ (localsp ? localsp : ScopeLocalsP (&scope_locals_, [] (ScopeLocals*) {}))
791 auto &stack_ = stack();
792 stack_.push_back (
this);
808 template<typename T, REQUIRES< std::is_same<T, std::nullptr_t>::value> =
true>
819 auto is_identifier_char = [] (
int ch) {
820 return ( (ch >=
'A' && ch <=
'Z') ||
821 (ch >=
'a' && ch <=
'z') ||
822 (ch >=
'0' && ch <=
'9') ||
823 ch ==
'_' || ch ==
'$' );
825 for (
size_t i = 0; i <
string.size() &&
string[i]; ++i)
826 if (is_identifier_char (
string[i]))
827 normalized +=
string[i];
828 else if (normalized.
size() && normalized[normalized.
size() - 1] !=
'.')
835template<
class V>
static inline unsigned
836js_initializer_index ()
845 if constexpr (DerivesVector<T>::value)
return 5;
846 if constexpr (DerivesPair<T>::value)
return 5;
850static constexpr const char *
const js_initializers[] = {
"null",
"0",
"0.0",
"false",
"''",
"[]",
"{}" };
856 const size_t last_colon = full_name.
rfind (
"::");
857 return last_colon == std::string::npos ? full_name : full_name.
substr (last_colon + 2);
860 static std::string name() {
return short_name (rtti_typename<T>()); }
869template<
typename T1,
typename T2>
885#define JSONIPC_MAP_TO_TYPESCRIPT(CXXTYPE,TSTYPE) \
886 template<> struct ::Jsonipc::typescript_name< CXXTYPE > { static std::string name() { return TSTYPE; } }
893 auto print_one_arg = [&] (
const std::string &type_name) {
894 if (i > 0) s +=
", ";
895 s += string_format (
"arg%d: %s", ++i, type_name.c_str());
897 (print_one_arg (typescript_name<Args>::name()), ...);
901typescript_arg_names_list()
905 auto append_arg_name = [&] (
const std::string &type_name) {
908 (append_arg_name (typescript_name<Args>::name()), ...);
911template<
typename C,
typename R,
typename... Args>
std::string
912typescript_call_impl (
const std::string &method_name)
916 s += typescript_arg_list<Args...>();
917 s +=
string_format (
"): Promise<%s>\n", typescript_name<R>::name().c_str());
918 s +=
string_format (
" { return Jsonipc.send (\"%s\", [this%s]); }\n",
919 method_name.
c_str(), typescript_arg_names_list<Args...>().c_str());
922template<
typename T,
typename Ret,
typename... Args>
std::string
923typescript_call (
const std::string &method_name, Ret (T::*func) (Args...))
925 return typescript_call_impl<T, Ret, Args...> (method_name);
927template<
typename T,
typename Ret,
typename... Args>
std::string
928typescript_call (
const std::string &method_name, Ret (T::*func) (Args...) const)
930 return typescript_call_impl<T, Ret, Args...> (method_name);
935 enum Kind { ANY, ENUM, VALUE, RECORD, FIELD, CLASS, METHOD };
939 size_t class_inherit_pos_ = 0;
943 if (open_enum_.
size())
945 if (open_record_.
size())
947 if (open_class_.
size())
950 template<
class,
class =
void>
struct has_nested_T :
std::false_type {};
951 template<
typename U>
struct has_nested_T<U,
std::void_t<typename U::T>> :
std::true_type {};
952 template<
typename M>
struct typescript_call_from_type;
953 template<
typename C,
typename R,
typename... Args>
954 struct typescript_call_from_type<R (C::*)(Args...)> {
958 return typescript_call_impl<C, R, Args...> (method_name);
961 template<
typename C,
typename R,
typename... Args>
962 struct typescript_call_from_type<R (C::*)(Args...) const> {
966 return typescript_call_impl<C, R, Args...>(method_name);
971 template<
typename T>
void
975 open_enum_ = rtti_typename<typename std::decay<T>::type>();
976 b_ +=
"export const " + short_name (open_enum_) +
" = { // " + open_enum_ +
"\n";
978 template<
typename T>
void
983 b_ +=
" " + name +
": \"" + full_js_name +
"\", // " +
std::to_string(
static_cast<underlying
>(v)) +
"\n";
988 b_ +=
"} as const;\n";
989 const std::string shortname = short_name (open_enum_);
990 b_ +=
"export type " + shortname +
" = typeof " + shortname +
"[keyof typeof " + shortname +
"];\n";
991 b_ +=
"Jsonipc.classes[\"" + open_enum_ +
"\"] = " + shortname +
";\n\n";
994 template<
typename T>
void
998 open_record_ = rtti_typename<typename std::decay<T>::type>();
999 b_ +=
"export class " + short_name (open_record_) +
" { // " + open_record_ +
"\n";
1001 template<
typename T,
typename A>
void
1005 const std::string default_value = js_initializers[js_initializer_index<A>()];
1007 record_fields_.emplace_back (name, ts_type_name, default_value, as_cast);
1012 for (
const auto &[field_name, ts_type_name, default_value, as_cast] : record_fields_)
1013 b_ +=
" " + field_name +
": " + ts_type_name +
";\n";
1014 b_ +=
" constructor (";
1015 for (
size_t i = 0; i < record_fields_.size(); i++) {
1016 const auto &[field_name, ts_type_name, default_value, as_cast] = record_fields_[i];
1017 b_ += (i ?
", " :
"") + field_name +
": " + ts_type_name +
" = " + default_value;
1019 b_ +=
" as " + as_cast;
1022 for (
const auto &[field_name, ts_type_name, default_value, as_cast] : record_fields_)
1023 b_ +=
" this." + field_name +
" = " + field_name +
";\n";
1026 const std::string shortname = short_name (open_record_);
1027 b_ +=
"Jsonipc.classes[\"" + open_record_ +
"\"] = " + shortname +
";\n\n";
1028 record_fields_.clear();
1029 open_record_.
clear();
1031 template<
typename T>
void
1035 open_class_ = rtti_typename<typename std::decay<T>::type>();
1036 const std::string shortname = short_name (open_class_);
1037 b_ +=
"export class " + shortname +
" // " + open_class_ +
"\n";
1038 class_inherit_pos_ = b_.
size();
1040 b_ +=
" constructor ($id)\n";
1041 b_ +=
" { super ($id); if (new.target === " + shortname +
") Jsonipc.ofreeze (this); }\n";
1043 template<
typename B>
void
1046 const std::string base_class_ = rtti_typename<typename std::decay<B>::type>();
1047 b_.
insert (class_inherit_pos_,
" extends Jsonipc.classes[\"" + base_class_ +
"\"]\n");
1049 template<
typename T,
typename M>
void
1052 b_ += typescript_call_from_type<M>::generate (name);
1054 template<
typename T,
typename R,
typename A>
void
1058 b_ +=
" { return Jsonipc.get_reactive_prop.call (this, \"" + name +
"\", " + js_initializers[js_initializer_index<R>()] +
"); }\n";
1060 b_ +=
" { Jsonipc.send ('set/' + '" + name +
"', [this, v]); }\n";
1066 const std::string shortname = short_name (open_class_);
1067 b_ +=
"Jsonipc.classes[\"" + open_class_ +
"\"] = " + shortname +
";\n\n";
1068 open_class_.
clear();
1086 if (JSONIPC_UNLIKELY (g_binding_printer))
1087 g_binding_printer->enum_type<T> ();
1091 set (T v,
const char *valuename)
1094 auto &entries_ = entries();
1096 Entry e { normalized_typename, v };
1097 entries_.push_back (e);
1098 if (JSONIPC_UNLIKELY (g_binding_printer))
1099 g_binding_printer->enum_value<T> (valuename, v);
1105 return !entries().empty();
1110 const auto &entries_ = entries();
1111 for (
const auto &e : entries_)
1120 auto c_isalnum = [] (
char c) {
1121 return (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9');
1123 const auto &entries_ = entries();
1124 for (
const auto &e : entries_)
1125 if (name == e.name ||
1126 (name.
size() < e.name.size() &&
1127 !c_isalnum (e.name[e.name.size() - name.
size() - 1]) &&
1128 e.name.compare (e.name.size() - name.
size(), name.
size(), name) == 0))
1137 const auto &entries_ = entries();
1138 for (
const auto &e : entries_)
1139 enumvalues.push_back ({
int64_t (e.value), e.name });
1143 struct Entry {
const std::string name; T value; };
1149 return rtti_typename<Type>();
1158 from_json (
const JsonValue &value, T fallback = T())
1160 if (value.IsString())
1164 return EnumType::get_value (
string, fallback);
1169 to_json (T evalue, JsonAllocator &allocator)
1172 if (EnumType::has_names())
1174 const std::string &name = EnumType::get_name (evalue);
1189 make_serializable<T>();
1190 if (JSONIPC_UNLIKELY (g_binding_printer))
1191 g_binding_printer->record_type<T>();
1194 template<typename A, REQUIRES< std::is_member_object_pointer<A>::value > =
true>
Serializable&
1195 set (
const char *name, A attribute)
1198 Accessors accessors;
1199 accessors.setter = [attribute] (T &obj,
const JsonValue &value) ->
void { obj.*attribute = from_json<SetterAttributeType> (value); };
1200 accessors.getter = [attribute] (
const T &obj, JsonAllocator &a) -> JsonValue {
return to_json (obj.*attribute, a); };
1202 auto it = amap.find (name);
1203 if (it != amap.end())
1206 const std::string class_name = rtti_typename<T>();
1207 if (JSONIPC_UNLIKELY (g_binding_printer))
1208 g_binding_printer->field_member<T,SetterAttributeType> (name);
1211 static bool is_serializable () {
return serialize_from_json_() && serialize_to_json_(); }
1212 static JsonValue serialize_to_json (
const T &o, JsonAllocator &a) {
return serialize_to_json_() (o, a); }
1221 static AccessorMap& accessormap() {
static AccessorMap amap;
return amap; }
1222 template<
typename U>
static void
1230 AccessorMap &amap = accessormap();
1231 for (
const auto &field : value.GetObject())
1233 const std::string field_name = field.name.GetString();
1234 auto it = amap.
find (field_name);
1235 if (it == amap.end())
1237 Accessors &accessors = it->second;
1238 accessors.setter (*obj, field.value);
1242 serialize_from_json_() = sfj;
1244 SerializeToJson stj = [] (
const T &object, JsonAllocator &allocator) -> JsonValue {
1245 JsonValue jobject (rapidjson::kObjectType);
1246 AccessorMap &amap = accessormap();
1247 for (
auto &it : amap)
1250 Accessors &accessors = it.second;
1251 JsonValue result = accessors.getter (
object, allocator);
1252 jobject.AddMember (JsonValue (field_name.
c_str(), allocator), result, allocator);
1256 serialize_to_json_() = stj;
1259 using SerializeToJson =
std::function<JsonValue (
const T&, JsonAllocator&)>;
1260 static SerializeFromJson& serialize_from_json_ () {
static SerializeFromJson impl;
return impl; }
1261 static SerializeToJson& serialize_to_json_ () {
static SerializeToJson impl;
return impl; }
1267 Class (
bool internal =
false)
1275 const size_t class_depth = Class::base_depth();
1276 if (class_depth > basedepth) {
1278 if (derived_sptr.get()) {
1279 basedepth = class_depth;
1285 InstanceMap::register_wrapper (create_wrapper);
1286 if (!internal && JSONIPC_UNLIKELY (g_binding_printer))
1287 g_binding_printer->class_type<T>();
1290 template<
typename B>
Class&
1294 if (JSONIPC_UNLIKELY (g_binding_printer))
1295 g_binding_printer->inherit_type<B>();
1299 template<typename F, REQUIRES< std::is_member_function_pointer<F>::value > =
true>
Class&
1300 set (
const char *name,
const F &method)
1302 add_member_function_closure (name, make_closure (method));
1303 if (JSONIPC_UNLIKELY (g_binding_printer))
1304 g_binding_printer->method_member<T,F> (name);
1308 template<
typename R,
typename A,
typename C,
typename VB>
Class&
1309 set (
const char *name, R (C::*get) () const, VB (C::*
set) (A))
1312 JSONIPC_ASSERT_RETURN (get &&
set, *
this);
1313 add_member_function_closure (
std::string (
"get/") + name, make_closure (get));
1314 add_member_function_closure (
std::string (
"set/") + name, make_closure (
set));
1315 if (JSONIPC_UNLIKELY (g_binding_printer))
1316 g_binding_printer->field_accessor<T,R,A> (name);
1319 template<typename F, REQUIRES< std::is_member_function_pointer<F>::value > =
true>
Class&
1320 set_d (
const char *name,
const F &method,
const DefaultsList &dflts)
1323 JSONIPC_ASSERT_RETURN (dflts.size() <= N_ARGS, *
this);
1324 add_member_function_closure (name, make_closure (method));
1325 if (JSONIPC_UNLIKELY (g_binding_printer))
1326 g_binding_printer->method_member<T,F> (name);
1332 return typename_of<T>();
1335 object_from_json (
const JsonValue &value)
1337 InstanceMap::Wrapper *iw = InstanceMap::scope_lookup_wrapper (value);
1341 iw->try_upcast (classname(), &base_sptr);
1352 return rtti_typename<Type>();
1354 template<
typename F>
1356 template<typename F, REQUIRES< HasVoidReturn<F>::value > =
true> Closure
1357 make_closure (
const F &method)
1359 return [method] (
const CallbackInfo &cbi) {
1360 const bool HAS_THIS =
true;
1361 if (HAS_THIS + CallTraits<F>::N_ARGS != cbi.n_args())
1366 call_from_json (*instance, method, cbi);
1369 template<typename F, REQUIRES< !HasVoidReturn<F>::value > =
true> Closure
1370 make_closure (
const F &method)
1372 return [method] (CallbackInfo &cbi) {
1373 const bool HAS_THIS =
true;
1374 if (HAS_THIS + CallTraits<F>::N_ARGS != cbi.n_args())
1380 rv = to_json (call_from_json (*instance, method, cbi), cbi.allocator());
1381 cbi.set_result (rv);
1385 add_member_function_closure (
const std::string &name, Closure &&closure)
1387 MethodMap &
mmap = methodmap();
1388 auto it =
mmap.find (name);
1389 if (it !=
mmap.end())
1394 static MethodMap& methodmap() {
static MethodMap methodmap_;
return methodmap_; }
1399 Closure* (*lookup_closure) (
const char*) = NULL;
1402 template<
typename B>
void
1405 BaseVec &bvec = basevec();
1406 BaseInfo binfo { typename_of<B>(), Class<B>::base_depth, &upcast_impl<B>, &Class<B>::lookup_closure, };
1407 for (
const auto &it : bvec)
1408 if (it.basetypename == binfo.basetypename)
1409 throw
std::runtime_error (
"duplicate base registration: " + binfo.basetypename);
1410 bvec.push_back (binfo);
1411 Class<B> bclass (
true);
1413 static BaseVec& basevec () {
static BaseVec basevec_;
return basevec_; }
1414 template<
typename B>
static bool
1418 return Class<B>::try_upcast (bptr, baseclass, sptrB);
1424 const BaseVec &bvec = basevec();
1426 for (
const auto &binfo : bvec)
1428 const size_t b = binfo.base_depth();
1435 lookup_closure (
const char *methodname)
1437 MethodMap &
mmap = methodmap();
1438 auto it =
mmap.find (methodname);
1439 if (it !=
mmap.end())
1441 const BaseVec &bvec = basevec();
1442 for (
const auto &base : bvec)
1444 Closure *closure = base.lookup_closure (methodname);
1453 if (classname() == baseclass)
1459 const BaseVec &bvec = basevec();
1460 for (
const auto &it : bvec)
1461 if (it.upcast_impl (sptr, baseclass, sptrB))
1468template<
typename T,
typename Enable =
void>
1487 from_json (
const JsonValue &value)
1502 const std::string impltype = rtti_typename (*sptr);
1503 JsonValue result = InstanceMap::scope_wrap_object<ClassType> (sptr, allocator);
1512forget_json_id (
size_t id)
1514 InstanceMap::scope_forget_id (
id);
1522 from_json (
const JsonValue &value)
1527 to_json (
const T *obj, JsonAllocator &allocator)
1548 from_json (
const JsonValue &value)
1556 to_json (
const T &
object, JsonAllocator &allocator)
1567 extra_methods[methodname] = closure;
1573 rapidjson::Document document;
1574 document.Parse<rapidjson_parse_flags> (message.
data(), message.
size());
1577 if (document.HasParseError())
1578 return create_error (
id, -32700,
"Parse error");
1579 const char *methodname =
nullptr;
1580 const JsonValue *args =
nullptr;
1581 for (
const auto &m : document.GetObject())
1583 id = from_json<size_t> (m.value, 0);
1584 else if (m.name ==
"method")
1585 methodname = from_json<const char*> (m.value);
1586 else if (m.name ==
"params" && m.value.IsArray())
1588 if (!
id || !methodname || !args || !args->IsArray())
1589 return create_error (
id, -32600,
"Invalid Request");
1591 Closure *closure = cbi.find_closure (methodname);
1594 const auto it = extra_methods.find (methodname);
1595 if (it != extra_methods.end())
1596 closure = &it->second;
1597 else if (
strcmp (methodname,
"Jsonipc/handshake") == 0)
1600 closure = &initialize;
1604 return create_error (
id, -32601,
"Method not found: " + cbi.classname (
"<unknown-this>") +
"['" + methodname +
"']");
1606 return create_reply (
id, cbi.get_result(), !cbi.have_result(), cbi.document());
1608 return create_error (
id, exc.code(), exc.what());
1614 create_reply (
size_t id, JsonValue &result,
bool skip_result, rapidjson::Document &d)
1616 auto &a = d.GetAllocator();
1618 d.AddMember (
"id",
id, a);
1619 d.AddMember (
"result", result, a);
1620 rapidjson::StringBuffer buffer;
1621 StringBufferWriter writer (buffer);
1623 std::string output { buffer.GetString(), buffer.GetSize() };
1627 create_error (
size_t id,
int errorcode,
const std::string &message)
1629 rapidjson::Document d (rapidjson::kObjectType);
1630 auto &a = d.GetAllocator();
1631 d.AddMember (
"id",
id ? JsonValue (
id) : JsonValue(), a);
1632 JsonValue error (rapidjson::kObjectType);
1633 error.AddMember (
"code", errorcode, a);
1634 error.AddMember (
"message", JsonValue (message.
c_str(), a).Move(), a);
1635 d.AddMember (
"error", error, a);
1636 rapidjson::StringBuffer buffer;
1637 rapidjson::Writer<rapidjson::StringBuffer> writer (buffer);
1639 std::string output { buffer.GetString(), buffer.GetSize() };
1645 cbi.set_result (to_json (0x00000001, cbi.allocator()).Move());
1652JSONIPC_MAP_TO_TYPESCRIPT (
void,
"void");
1653JSONIPC_MAP_TO_TYPESCRIPT (
bool,
"boolean");
1654JSONIPC_MAP_TO_TYPESCRIPT (::int8_t,
"number");
1655JSONIPC_MAP_TO_TYPESCRIPT (::uint8_t,
"number");
1656JSONIPC_MAP_TO_TYPESCRIPT (::int32_t,
"number");
1657JSONIPC_MAP_TO_TYPESCRIPT (::uint32_t,
"number");
1658JSONIPC_MAP_TO_TYPESCRIPT (::int64_t,
"number");
1659JSONIPC_MAP_TO_TYPESCRIPT (::uint64_t,
"number");
1660JSONIPC_MAP_TO_TYPESCRIPT (
float,
"number");
1661JSONIPC_MAP_TO_TYPESCRIPT (
double,
"number");
1662JSONIPC_MAP_TO_TYPESCRIPT (
const char*,
"string");
Keep track of temporary instances during IpcDispatcher::dispatch_message().
std::string normalize_typename(const std::string &string)
Yield the Javascript identifier name by substituting ':+' with '.'.
typename ::std::enable_if< value, bool >::type REQUIRES
REQUIRES<value> - Simplified version of std::enable_if<cond,bool>::type to use SFINAE in function tem...
typename ::std::enable_if< value, void >::type REQUIRESv
REQUIRESv<value> - Simplified version of std::enable_if<cond,void>::type to use SFINAE in struct temp...
bool contains(const C &container, const std::function< bool(typename C::value_type const &value)> &pred)
Returns true if container element for which pred() is true.
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
const char * string_demangle_cxx(const char *mangled_identifier) noexcept
Demangle identifier via libcc.
Template class providing conversion helpers for JsonValue to indexed C++ function argument.
Context for calling C++ functions from Json.
Class & set(const char *name, R(C::*get)() const, VB(C::*set)(A))
Add a member object accessors.
Class & set(const char *name, const F &method)
Add a member function pointer.
Template class providing C++ <-> JsonValue conversions for various types.
Wrapper for function argument default value constants.
DerivesPair<T> - Check if T derives from std::pair<>.
DerivesSharedPtr<T> - Check if T derives from std::shared_ptr<>.
DerivesVector<T> - Check if T derives from std::vector<>.
Template class providing return type and argument type information for functions.
Has___typename__<T> - Check if T provides a __typename__() method.
Has_setget<T> - Check if type T provides methods set() and get()
Has_shared_from_this<T> - Check if t.shared_from_this() yields a std::shared_ptr<>.
Template class to identify std::shared_ptr<> classes.
Template class to identify wrappable classes.
Common base type for polymorphic classes managed by std::shared_ptr<>.
Jsonipc wrapper type for objects that support field-wise serialization to/from JSON.
Serializable & set(const char *name, A attribute)
Add a member object pointer.
Serializable()
Allow object handles to be streamed to/from Javascript, needs a Scope for temporaries.
Jsonipc exception that is relayed to caller when thrown during invocations.