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); abort(); } 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);
103 return string_demangle_cxx (
typeid (T).name());
110 return string_demangle_cxx (
typeid (o).name());
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>;
545 operator< (
const TypeidKey &other)
const noexcept
547 return tindex < other.tindex || (tindex == other.tindex && ptr < other.ptr);
552 virtual TypeidKey typeid_key () = 0;
556 virtual Closure* lookup_closure (
const char *method) = 0;
558 virtual void try_upcast (
const std::string &baseclass,
void *sptrB) = 0;
564 register_wrapper (CreateWrapper createwrapper)
566 wrapper_creators().push_back (createwrapper);
580 TypeidKey typeid_key ()
override {
return create_typeid_key (sptr_); }
581 void try_upcast (
const std::string &baseclass,
void *sptrB)
override
586 return {
typeid (T), sptr.get() };
599 IdSet *idset_ =
nullptr;
600 static size_t next_counter() {
static size_t counter_ = 0;
return ++counter_; }
602 delete_id (
size_t thisid)
604 const auto w = wmap_.
find (thisid);
605 if (w != wmap_.
end())
607 Wrapper *wrapper = w->second;
609 const auto t = typeid_map_.
find (wrapper->typeid_key());
610 if (t != typeid_map_.
end())
611 typeid_map_.
erase (t);
614 idset_->
erase (thisid);
625 idset_ =
new IdSet();
634 idset_->
swap (preserve);
638 auto contains = [] (
const auto &c,
const auto &e) {
639 return c.end() != c.find (e);
641 size_t preserved = 0;
642 for (
const size_t id : unused)
652 return wmap_.
empty();
660 clear (
const bool printdebug =
false)
670 for (
auto &pair : old)
672 Wrapper *wrapper = pair.second;
674 fprintf (stderr,
"Jsonipc::~Wrapper: %s: $id=%zu\n", string_demangle_cxx (wrapper->typeid_key().tindex.name()).c_str(), pair.first);
682 JSONIPC_ASSERT_RETURN (wmap_.
size() == 0);
683 JSONIPC_ASSERT_RETURN (typeid_map_.
size() == 0);
686 wrapper_to_json (Wrapper *wrapper,
const size_t thisid, JsonAllocator &allocator)
690 JsonValue jobject (rapidjson::kObjectType);
691 jobject.AddMember (
"$id", thisid, allocator);
692 jobject.AddMember (
"$class", JsonValue (wrapper->classname().c_str(), allocator), allocator);
695 template<
typename T>
static JsonValue
698 InstanceMap *imap = Scope::instance_map();
700 Wrapper *wrapper =
nullptr;
703 const TypeidKey tkey = InstanceWrapper<T>::create_typeid_key (sptr);
704 auto it = imap->typeid_map_.find (tkey);
705 if (it == imap->typeid_map_.end())
707 thisid = next_counter();
710 size_t basedepth = 0;
711 for (
size_t i = 0; i < wcreators.size(); i++) {
712 Wrapper *w = wcreators[i] (sptr, basedepth);
720 wrapper =
new InstanceWrapper<T> (sptr);
721 imap->wmap_[thisid] = wrapper;
722 imap->typeid_map_[tkey] = thisid;
727 auto wt = imap->wmap_.find (thisid);
728 wrapper = wt != imap->wmap_.end() ? wt->second :
nullptr;
732 imap->idset_->insert (thisid);
739 return imap->wrapper_to_json (wrapper, thisid, allocator);
742 wrapper_from_json (
const JsonValue &value)
744 if (value.IsObject())
746 auto it = value.FindMember (
"$id");
747 if (it != value.MemberEnd())
749 const size_t thisid = Convert<size_t>::from_json (it->value);
752 auto tit = wmap_.
find (thisid);
753 if (tit != wmap_.
end())
761 scope_lookup_wrapper (
const JsonValue &value)
763 InstanceMap *imap = Scope::instance_map();
764 return imap ? imap->wrapper_from_json (value) :
nullptr;
767 scope_forget_id (
size_t thisid)
769 InstanceMap *imap = Scope::instance_map();
770 return imap->delete_id (thisid);
775CallbackInfo::find_closure (
const char *methodname)
777 const JsonValue &value = ntharg (0);
778 InstanceMap::Wrapper *iw = InstanceMap::scope_lookup_wrapper (value);
779 return iw ? iw->lookup_closure (methodname) :
nullptr;
783CallbackInfo::classname (
const std::string &fallback)
const
785 const JsonValue &value = ntharg (0);
786 InstanceMap::Wrapper *iw = InstanceMap::scope_lookup_wrapper (value);
787 return iw ? iw->classname() : fallback;
791Scope::Scope (InstanceMap &instance_map, ScopeLocalsP localsp) :
792 instance_map_ (instance_map), localsp_ (localsp ? localsp : ScopeLocalsP (&scope_locals_, [] (ScopeLocals*) {}))
794 auto &stack_ = stack();
795 stack_.push_back (
this);
811 template<typename T, REQUIRES< std::is_same<T, std::nullptr_t>::value> =
true>
822 auto is_identifier_char = [] (
int ch) {
823 return ( (ch >=
'A' && ch <=
'Z') ||
824 (ch >=
'a' && ch <=
'z') ||
825 (ch >=
'0' && ch <=
'9') ||
826 ch ==
'_' || ch ==
'$' );
828 for (
size_t i = 0; i <
string.size() &&
string[i]; ++i)
829 if (is_identifier_char (
string[i]))
830 normalized +=
string[i];
831 else if (normalized.
size() && normalized[normalized.
size() - 1] !=
'.')
838template<
class V>
static inline unsigned
839js_initializer_index ()
848 if constexpr (DerivesVector<T>::value)
return 5;
849 if constexpr (DerivesPair<T>::value)
return 5;
853static constexpr const char *
const js_initializers[] = {
"null",
"0",
"0.0",
"false",
"''",
"[]",
"{}" };
859 const size_t last_colon = full_name.
rfind (
"::");
860 return last_colon == std::string::npos ? full_name : full_name.
substr (last_colon + 2);
863 static std::string name() {
return short_name (rtti_typename<T>()); }
872template<
typename T1,
typename T2>
888#define JSONIPC_MAP_TO_TYPESCRIPT(CXXTYPE,TSTYPE) \
889 template<> struct Jsonipc::typescript_name< CXXTYPE > { static std::string name() { return TSTYPE; } }
896 auto print_one_arg = [&] (
const std::string &type_name) {
897 if (i > 0) s +=
", ";
898 s += string_format (
"arg%d: %s", ++i, type_name.c_str());
900 (print_one_arg (typescript_name<Args>::name()), ...);
904typescript_arg_names_list()
908 auto append_arg_name = [&] (
const std::string &type_name) {
911 (append_arg_name (typescript_name<Args>::name()), ...);
914template<
typename C,
typename R,
typename... Args>
std::string
915typescript_call_impl (
const std::string &method_name)
919 s += typescript_arg_list<Args...>();
920 s +=
string_format (
"): Promise<%s>\n", typescript_name<R>::name().c_str());
921 s +=
string_format (
" { return this.$rpc (\"%s\", [this%s]); }\n",
922 method_name.
c_str(), typescript_arg_names_list<Args...>().c_str());
925template<
typename T,
typename Ret,
typename... Args>
std::string
926typescript_call (
const std::string &method_name, Ret (T::*func) (Args...))
928 return typescript_call_impl<T, Ret, Args...> (method_name);
930template<
typename T,
typename Ret,
typename... Args>
std::string
931typescript_call (
const std::string &method_name, Ret (T::*func) (Args...) const)
933 return typescript_call_impl<T, Ret, Args...> (method_name);
938 enum Kind { ANY, ENUM, VALUE, RECORD, FIELD, CLASS, METHOD };
945 size_t class_inherit_opos_ = 0;
949 if (open_enum_.
size())
951 if (open_record_.
size())
953 if (open_class_.
size())
956 template<
class,
class =
void>
struct has_nested_T :
std::false_type {};
957 template<
typename U>
struct has_nested_T<U,
std::void_t<typename U::T>> :
std::true_type {};
958 template<
typename M>
struct typescript_call_from_type;
959 template<
typename C,
typename R,
typename... Args>
960 struct typescript_call_from_type<R (C::*)(Args...)> {
964 return typescript_call_impl<C, R, Args...> (method_name);
967 template<
typename C,
typename R,
typename... Args>
968 struct typescript_call_from_type<R (C::*)(Args...) const> {
972 return typescript_call_impl<C, R, Args...>(method_name);
981 for (
auto it = initializers_opos_.rbegin(); it != initializers_opos_.rend(); ++it)
983 const auto &[pos, type, index] = *it;
984 const std::string value = index == 6 && record_types_.count (type) ?
"new " + type +
"()" : js_initializers[index];
987 initializers_opos_.clear();
990 template<
typename T>
void
994 open_enum_ = rtti_typename<typename std::decay<T>::type>();
995 b_ +=
"export const " + short_name (open_enum_) +
" = { // " + open_enum_ +
"\n";
997 template<
typename T>
void
1002 b_ +=
" " + name +
": \"" + full_js_name +
"\", // " +
std::to_string(
static_cast<underlying
>(v)) +
"\n";
1007 b_ +=
"} as const;\n";
1008 const std::string shortname = short_name (open_enum_);
1009 b_ +=
"export type " + shortname +
" = typeof " + shortname +
"[keyof typeof " + shortname +
"];\n";
1010 b_ +=
"Jsonipc.classes[\"" + open_enum_ +
"\"] = " + shortname +
";\n\n";
1013 template<
typename T>
void
1017 open_record_ = rtti_typename<typename std::decay<T>::type>();
1018 record_types_.insert (short_name (open_record_));
1019 b_ +=
"export class " + short_name (open_record_) +
" { // " + open_record_ +
"\n";
1021 template<
typename T,
typename A>
void
1026 record_fields_.emplace_back (name, ts_type_name, js_initializer_index<A>(), as_cast);
1031 for (
const auto &[field_name, ts_type_name, default_index, as_cast] : record_fields_)
1032 b_ +=
" " + field_name +
": " + ts_type_name +
";\n";
1033 b_ +=
" constructor (";
1034 for (
size_t i = 0; i < record_fields_.size(); i++) {
1035 const auto &[field_name, ts_type_name, default_index, as_cast] = record_fields_[i];
1036 b_ += (i ?
", " :
"") + field_name +
": " + ts_type_name +
" = ";
1037 initializers_opos_.emplace_back (b_.
size(), ts_type_name, default_index);
1039 b_ +=
" as " + as_cast;
1042 for (
const auto &[field_name, ts_type_name, default_index, as_cast] : record_fields_)
1043 b_ +=
" this." + field_name +
" = " + field_name +
";\n";
1046 const std::string shortname = short_name (open_record_);
1047 b_ +=
"Jsonipc.classes[\"" + open_record_ +
"\"] = " + shortname +
";\n\n";
1048 record_fields_.clear();
1049 open_record_.
clear();
1051 template<
typename T>
void
1055 open_class_ = rtti_typename<typename std::decay<T>::type>();
1056 const std::string shortname = short_name (open_class_);
1057 b_ +=
"export class " + shortname +
" // " + open_class_ +
"\n";
1058 class_inherit_opos_ = b_.
size();
1060 b_ +=
" constructor ($id)\n";
1061 b_ +=
" { super ($id); if (new.target === " + shortname +
") Jsonipc.ofreeze (this); }\n";
1063 template<
typename B>
void
1066 const std::string base_class_ = rtti_typename<typename std::decay<B>::type>();
1067 const std::string inheritance =
" extends Jsonipc.classes[\"" + base_class_ +
"\"]\n";
1068 b_.
insert (class_inherit_opos_, inheritance);
1069 for (
auto &[pos, type, index] : initializers_opos_)
1070 if (pos >= class_inherit_opos_)
1071 pos += inheritance.size();
1073 template<
typename T,
typename M>
void
1076 b_ += typescript_call_from_type<M>::generate (name);
1078 template<
typename T,
typename R,
typename A>
void
1082 b_ +=
" get " + name +
" (): " + ts_type +
"\n";
1083 b_ +=
" { return this.$get (\"" + name +
"\", ";
1084 initializers_opos_.emplace_back (b_.
size(), ts_type, js_initializer_index<R>());
1085 b_ +=
") as " + ts_type +
"; }\n";
1086 b_ +=
" set " + name +
" (v: " + ts_type +
")\n";
1087 b_ +=
" { this.$set (\"" + name +
"\", v); }\n";
1093 const std::string shortname = short_name (open_class_);
1094 b_ +=
"Jsonipc.classes[\"" + open_class_ +
"\"] = " + shortname +
";\n\n";
1095 open_class_.
clear();
1115 if (JSONIPC_UNLIKELY (g_binding_printer))
1116 g_binding_printer->enum_type<T> ();
1120 set (T v,
const char *valuename)
1123 auto &entries_ = entries();
1125 Entry e { normalized_typename, v };
1126 entries_.push_back (e);
1127 if (JSONIPC_UNLIKELY (g_binding_printer))
1128 g_binding_printer->enum_value<T> (valuename, v);
1134 return !entries().empty();
1139 const auto &entries_ = entries();
1140 for (
const auto &e : entries_)
1149 auto c_isalnum = [] (
char c) {
1150 return (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9');
1152 const auto &entries_ = entries();
1153 for (
const auto &e : entries_)
1154 if (name == e.name ||
1155 (name.
size() < e.name.size() &&
1156 !c_isalnum (e.name[e.name.size() - name.
size() - 1]) &&
1157 e.name.compare (e.name.size() - name.
size(), name.
size(), name) == 0))
1166 const auto &entries_ = entries();
1167 for (
const auto &e : entries_)
1168 enumvalues.push_back ({
int64_t (e.value), e.name });
1172 struct Entry {
const std::string name; T value; };
1178 return rtti_typename<Type>();
1187 from_json (
const JsonValue &value, T fallback = T())
1189 if (value.IsString())
1193 return EnumType::get_value (
string, fallback);
1198 to_json (T evalue, JsonAllocator &allocator)
1201 if (EnumType::has_names())
1203 const std::string &name = EnumType::get_name (evalue);
1218 make_serializable<T>();
1219 if (JSONIPC_UNLIKELY (g_binding_printer))
1220 g_binding_printer->record_type<T>();
1223 template<typename A, REQUIRES< std::is_member_object_pointer<A>::value > =
true>
Serializable&
1224 set (
const char *name, A attribute)
1227 Accessors accessors;
1228 accessors.setter = [attribute] (T &obj,
const JsonValue &value) ->
void { obj.*attribute = from_json<SetterAttributeType> (value); };
1229 accessors.getter = [attribute] (
const T &obj, JsonAllocator &a) -> JsonValue {
return to_json (obj.*attribute, a); };
1231 auto it = amap.find (name);
1232 if (it != amap.end())
1235 const std::string class_name = rtti_typename<T>();
1236 if (JSONIPC_UNLIKELY (g_binding_printer))
1237 g_binding_printer->field_member<T,SetterAttributeType> (name);
1240 static bool is_serializable () {
return serialize_from_json_() && serialize_to_json_(); }
1241 static JsonValue serialize_to_json (
const T &o, JsonAllocator &a) {
return serialize_to_json_() (o, a); }
1250 static AccessorMap& accessormap() {
static AccessorMap amap;
return amap; }
1251 template<
typename U>
static void
1259 AccessorMap &amap = accessormap();
1260 for (
const auto &field : value.GetObject())
1262 const std::string field_name = field.name.GetString();
1263 auto it = amap.
find (field_name);
1264 if (it == amap.end())
1266 Accessors &accessors = it->second;
1267 accessors.setter (*obj, field.value);
1271 serialize_from_json_() = sfj;
1273 SerializeToJson stj = [] (
const T &object, JsonAllocator &allocator) -> JsonValue {
1274 JsonValue jobject (rapidjson::kObjectType);
1275 AccessorMap &amap = accessormap();
1276 for (
auto &it : amap)
1279 Accessors &accessors = it.second;
1280 JsonValue result = accessors.getter (
object, allocator);
1281 jobject.AddMember (JsonValue (field_name.
c_str(), allocator), result, allocator);
1285 serialize_to_json_() = stj;
1288 using SerializeToJson =
std::function<JsonValue (
const T&, JsonAllocator&)>;
1289 static SerializeFromJson& serialize_from_json_ () {
static SerializeFromJson impl;
return impl; }
1290 static SerializeToJson& serialize_to_json_ () {
static SerializeToJson impl;
return impl; }
1296 Class (
bool internal =
false)
1304 const size_t class_depth = Class::base_depth();
1305 if (class_depth > basedepth) {
1307 if (derived_sptr.get()) {
1308 basedepth = class_depth;
1314 InstanceMap::register_wrapper (create_wrapper);
1315 if (!internal && JSONIPC_UNLIKELY (g_binding_printer))
1316 g_binding_printer->class_type<T>();
1319 template<
typename B>
Class&
1323 if (JSONIPC_UNLIKELY (g_binding_printer))
1324 g_binding_printer->inherit_type<B>();
1328 template<typename F, REQUIRES< std::is_member_function_pointer<F>::value > =
true>
Class&
1329 set (
const char *name,
const F &method)
1331 add_member_function_closure (name, make_closure (method));
1332 if (JSONIPC_UNLIKELY (g_binding_printer))
1333 g_binding_printer->method_member<T,F> (name);
1337 template<
typename R,
typename A,
typename C,
typename VB>
Class&
1338 set (
const char *name, R (C::*get) () const, VB (C::*
set) (A))
1341 JSONIPC_ASSERT_RETURN (get &&
set, *
this);
1342 add_member_function_closure (
std::string (
"get/") + name, make_closure (get));
1343 add_member_function_closure (
std::string (
"set/") + name, make_closure (
set));
1344 if (JSONIPC_UNLIKELY (g_binding_printer))
1345 g_binding_printer->field_accessor<T,R,A> (name);
1348 template<typename F, REQUIRES< std::is_member_function_pointer<F>::value > =
true>
Class&
1349 set_d (
const char *name,
const F &method,
const DefaultsList &dflts)
1352 JSONIPC_ASSERT_RETURN (dflts.size() <= N_ARGS, *
this);
1353 add_member_function_closure (name, make_closure (method));
1354 if (JSONIPC_UNLIKELY (g_binding_printer))
1355 g_binding_printer->method_member<T,F> (name);
1361 return typename_of<T>();
1364 object_from_json (
const JsonValue &value)
1366 InstanceMap::Wrapper *iw = InstanceMap::scope_lookup_wrapper (value);
1370 iw->try_upcast (classname(), &base_sptr);
1381 return rtti_typename<Type>();
1383 template<
typename F>
1385 template<typename F, REQUIRES< HasVoidReturn<F>::value > =
true> Closure
1386 make_closure (
const F &method)
1388 return [method] (
const CallbackInfo &cbi) {
1389 const bool HAS_THIS =
true;
1390 if (HAS_THIS + CallTraits<F>::N_ARGS != cbi.n_args())
1395 call_from_json (*instance, method, cbi);
1398 template<typename F, REQUIRES< !HasVoidReturn<F>::value > =
true> Closure
1399 make_closure (
const F &method)
1401 return [method] (CallbackInfo &cbi) {
1402 const bool HAS_THIS =
true;
1403 if (HAS_THIS + CallTraits<F>::N_ARGS != cbi.n_args())
1409 rv = to_json (call_from_json (*instance, method, cbi), cbi.allocator());
1410 cbi.set_result (rv);
1414 add_member_function_closure (
const std::string &name, Closure &&closure)
1416 MethodMap &
mmap = methodmap();
1417 auto it =
mmap.find (name);
1418 if (it !=
mmap.end())
1423 static MethodMap& methodmap() {
static MethodMap methodmap_;
return methodmap_; }
1428 Closure* (*lookup_closure) (
const char*) = NULL;
1432 template<
typename B>
void
1435 BaseVec &bvec = basevec();
1436 BaseInfo binfo { typename_of<B>(), Class<B>::base_depth, &upcast_impl<B>, &Class<B>::lookup_closure, &
Class<B>::list_methods, };
1437 for (
const auto &it : bvec)
1438 if (it.basetypename == binfo.basetypename)
1439 throw
std::runtime_error (
"duplicate base registration: " + binfo.basetypename);
1440 bvec.push_back (binfo);
1441 Class<B> bclass (
true);
1443 static BaseVec& basevec () {
static BaseVec basevec_;
return basevec_; }
1444 template<
typename B>
static bool
1448 return Class<B>::try_upcast (bptr, baseclass, sptrB);
1454 const BaseVec &bvec = basevec();
1456 for (
const auto &binfo : bvec)
1458 const size_t b = binfo.base_depth();
1465 lookup_closure (
const char *methodname)
1467 MethodMap &
mmap = methodmap();
1468 auto it =
mmap.find (methodname);
1469 if (it !=
mmap.end())
1471 const BaseVec &bvec = basevec();
1472 for (
const auto &base : bvec)
1474 Closure *closure = base.lookup_closure (methodname);
1485 for (
const auto &it : methodmap())
1486 names.push_back (it.first);
1487 for (
const auto &base : basevec())
1488 for (
const auto &name : base.list_methods())
1489 names.push_back (name);
1491 names.erase (
std::unique (names.begin(), names.end()), names.end());
1497 if (classname() == baseclass)
1503 const BaseVec &bvec = basevec();
1504 for (
const auto &it : bvec)
1505 if (it.upcast_impl (sptr, baseclass, sptrB))
1512template<
typename T,
typename Enable =
void>
1531 from_json (
const JsonValue &value)
1546 const std::string impltype = rtti_typename (*sptr);
1547 JsonValue result = InstanceMap::scope_wrap_object<ClassType> (sptr, allocator);
1556forget_json_id (
size_t id)
1558 InstanceMap::scope_forget_id (
id);
1566 from_json (
const JsonValue &value)
1571 to_json (
const T *obj, JsonAllocator &allocator)
1592 from_json (
const JsonValue &value)
1600 to_json (
const T &
object, JsonAllocator &allocator)
1611 extra_methods[methodname] = closure;
1617 rapidjson::Document document;
1618 document.Parse<rapidjson_parse_flags> (message.
data(), message.
size());
1621 if (document.HasParseError())
1622 return create_error (
id, -32700,
"Parse error");
1623 const char *methodname =
nullptr;
1624 const JsonValue *args =
nullptr;
1625 for (
const auto &m : document.GetObject())
1627 id = from_json<size_t> (m.value, 0);
1628 else if (m.name ==
"method")
1629 methodname = from_json<const char*> (m.value);
1630 else if (m.name ==
"params" && m.value.IsArray())
1632 if (!
id || !methodname || !args || !args->IsArray())
1633 return create_error (
id, -32600,
"Invalid Request");
1635 Closure *closure = cbi.find_closure (methodname);
1638 const auto it = extra_methods.find (methodname);
1639 if (it != extra_methods.end())
1640 closure = &it->second;
1641 else if (
strcmp (methodname,
"Jsonipc/handshake") == 0)
1644 closure = &initialize;
1648 return create_error (
id, -32601,
"Method not found: " + cbi.classname (
"<unknown-this>") +
"['" + methodname +
"']");
1650 return create_reply (
id, cbi.get_result(), !cbi.have_result(), cbi.document());
1652 return create_error (
id, exc.code(), exc.what());
1658 create_reply (
size_t id, JsonValue &result,
bool skip_result, rapidjson::Document &d)
1660 auto &a = d.GetAllocator();
1662 d.AddMember (
"id",
id, a);
1663 d.AddMember (
"result", result, a);
1664 rapidjson::StringBuffer buffer;
1665 StringBufferWriter writer (buffer);
1667 std::string output { buffer.GetString(), buffer.GetSize() };
1671 create_error (
size_t id,
int errorcode,
const std::string &message)
1673 rapidjson::Document d (rapidjson::kObjectType);
1674 auto &a = d.GetAllocator();
1675 d.AddMember (
"id",
id ? JsonValue (
id) : JsonValue(), a);
1676 JsonValue error (rapidjson::kObjectType);
1677 error.AddMember (
"code", errorcode, a);
1678 error.AddMember (
"message", JsonValue (message.
c_str(), a).Move(), a);
1679 d.AddMember (
"error", error, a);
1680 rapidjson::StringBuffer buffer;
1681 rapidjson::Writer<rapidjson::StringBuffer> writer (buffer);
1683 std::string output { buffer.GetString(), buffer.GetSize() };
1689 cbi.set_result (to_json (0x00000001, cbi.allocator()).Move());
1696JSONIPC_MAP_TO_TYPESCRIPT (
void,
"void");
1697JSONIPC_MAP_TO_TYPESCRIPT (
bool,
"boolean");
1698JSONIPC_MAP_TO_TYPESCRIPT (::int8_t,
"number");
1699JSONIPC_MAP_TO_TYPESCRIPT (::uint8_t,
"number");
1700JSONIPC_MAP_TO_TYPESCRIPT (::int32_t,
"number");
1701JSONIPC_MAP_TO_TYPESCRIPT (::uint32_t,
"number");
1702JSONIPC_MAP_TO_TYPESCRIPT (::int64_t,
"number");
1703JSONIPC_MAP_TO_TYPESCRIPT (::uint64_t,
"number");
1704JSONIPC_MAP_TO_TYPESCRIPT (
float,
"number");
1705JSONIPC_MAP_TO_TYPESCRIPT (
double,
"number");
1706JSONIPC_MAP_TO_TYPESCRIPT (
const char*,
"string");
Maps C++ shared_ptr instances to JSON-wrapped objects with unique IDs, supporting polymorphic upcasti...
Keep track of temporary instances during IpcDispatcher::dispatch_message().
Base class for type registration (Enum, Serializable, Class) that optionally generates TypeScript bin...
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...
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.
static std::vector< std::string > list_methods()
List the method names registered for T and its base classes, accessors as "get/name" and "set/name".
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<>.
Registers C++ enum values with string names for JSON serialization and TypeScript binding generation.
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.