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);
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;
557 virtual void try_upcast (
const std::string &baseclass,
void *sptrB) = 0;
563 register_wrapper (CreateWrapper createwrapper)
565 wrapper_creators().push_back (createwrapper);
578 TypeidKey typeid_key ()
override {
return create_typeid_key (sptr_); }
579 void try_upcast (
const std::string &baseclass,
void *sptrB)
override
584 return {
typeid (T), sptr.get() };
597 IdSet *idset_ =
nullptr;
598 static size_t next_counter() {
static size_t counter_ = 0;
return ++counter_; }
600 delete_id (
size_t thisid)
602 const auto w = wmap_.
find (thisid);
603 if (w != wmap_.
end())
605 Wrapper *wrapper = w->second;
607 const auto t = typeid_map_.
find (wrapper->typeid_key());
608 if (t != typeid_map_.
end())
609 typeid_map_.
erase (t);
612 idset_->
erase (thisid);
623 idset_ =
new IdSet();
632 idset_->
swap (preserve);
636 auto contains = [] (
const auto &c,
const auto &e) {
637 return c.end() != c.find (e);
639 size_t preserved = 0;
640 for (
const size_t id : unused)
650 return wmap_.
empty();
658 clear (
const bool printdebug =
false)
668 for (
auto &pair : old)
670 Wrapper *wrapper = pair.second;
672 fprintf (stderr,
"Jsonipc::~Wrapper: %s: $id=%zu\n", string_demangle_cxx (wrapper->typeid_key().tindex.name()).c_str(), pair.first);
680 JSONIPC_ASSERT_RETURN (wmap_.
size() == 0);
681 JSONIPC_ASSERT_RETURN (typeid_map_.
size() == 0);
684 wrapper_to_json (Wrapper *wrapper,
const size_t thisid, JsonAllocator &allocator)
688 JsonValue jobject (rapidjson::kObjectType);
689 jobject.AddMember (
"$id", thisid, allocator);
690 jobject.AddMember (
"$class", JsonValue (wrapper->classname().c_str(), allocator), allocator);
693 template<
typename T>
static JsonValue
696 InstanceMap *imap = Scope::instance_map();
698 Wrapper *wrapper =
nullptr;
701 const TypeidKey tkey = InstanceWrapper<T>::create_typeid_key (sptr);
702 auto it = imap->typeid_map_.find (tkey);
703 if (it == imap->typeid_map_.end())
705 thisid = next_counter();
708 size_t basedepth = 0;
709 for (
size_t i = 0; i < wcreators.size(); i++) {
710 Wrapper *w = wcreators[i] (sptr, basedepth);
718 wrapper =
new InstanceWrapper<T> (sptr);
719 imap->wmap_[thisid] = wrapper;
720 imap->typeid_map_[tkey] = thisid;
725 auto wt = imap->wmap_.find (thisid);
726 wrapper = wt != imap->wmap_.end() ? wt->second :
nullptr;
730 imap->idset_->insert (thisid);
737 return imap->wrapper_to_json (wrapper, thisid, allocator);
740 wrapper_from_json (
const JsonValue &value)
742 if (value.IsObject())
744 auto it = value.FindMember (
"$id");
745 if (it != value.MemberEnd())
747 const size_t thisid = Convert<size_t>::from_json (it->value);
750 auto tit = wmap_.
find (thisid);
751 if (tit != wmap_.
end())
759 scope_lookup_wrapper (
const JsonValue &value)
761 InstanceMap *imap = Scope::instance_map();
762 return imap ? imap->wrapper_from_json (value) :
nullptr;
765 scope_forget_id (
size_t thisid)
767 InstanceMap *imap = Scope::instance_map();
768 return imap->delete_id (thisid);
773CallbackInfo::find_closure (
const char *methodname)
775 const JsonValue &value = ntharg (0);
776 InstanceMap::Wrapper *iw = InstanceMap::scope_lookup_wrapper (value);
777 return iw ? iw->lookup_closure (methodname) :
nullptr;
781CallbackInfo::classname (
const std::string &fallback)
const
783 const JsonValue &value = ntharg (0);
784 InstanceMap::Wrapper *iw = InstanceMap::scope_lookup_wrapper (value);
785 return iw ? iw->classname() : fallback;
789Scope::Scope (InstanceMap &instance_map, ScopeLocalsP localsp) :
790 instance_map_ (instance_map), localsp_ (localsp ? localsp : ScopeLocalsP (&scope_locals_, [] (ScopeLocals*) {}))
792 auto &stack_ = stack();
793 stack_.push_back (
this);
809 template<typename T, REQUIRES< std::is_same<T, std::nullptr_t>::value> =
true>
820 auto is_identifier_char = [] (
int ch) {
821 return ( (ch >=
'A' && ch <=
'Z') ||
822 (ch >=
'a' && ch <=
'z') ||
823 (ch >=
'0' && ch <=
'9') ||
824 ch ==
'_' || ch ==
'$' );
826 for (
size_t i = 0; i <
string.size() &&
string[i]; ++i)
827 if (is_identifier_char (
string[i]))
828 normalized +=
string[i];
829 else if (normalized.
size() && normalized[normalized.
size() - 1] !=
'.')
836template<
class V>
static inline unsigned
837js_initializer_index ()
846 if constexpr (DerivesVector<T>::value)
return 5;
847 if constexpr (DerivesPair<T>::value)
return 5;
851static constexpr const char *
const js_initializers[] = {
"null",
"0",
"0.0",
"false",
"''",
"[]",
"{}" };
857 const size_t last_colon = full_name.
rfind (
"::");
858 return last_colon == std::string::npos ? full_name : full_name.
substr (last_colon + 2);
861 static std::string name() {
return short_name (rtti_typename<T>()); }
870template<
typename T1,
typename T2>
886#define JSONIPC_MAP_TO_TYPESCRIPT(CXXTYPE,TSTYPE) \
887 template<> struct ::Jsonipc::typescript_name< CXXTYPE > { static std::string name() { return TSTYPE; } }
894 auto print_one_arg = [&] (
const std::string &type_name) {
895 if (i > 0) s +=
", ";
896 s += string_format (
"arg%d: %s", ++i, type_name.c_str());
898 (print_one_arg (typescript_name<Args>::name()), ...);
902typescript_arg_names_list()
906 auto append_arg_name = [&] (
const std::string &type_name) {
909 (append_arg_name (typescript_name<Args>::name()), ...);
912template<
typename C,
typename R,
typename... Args>
std::string
913typescript_call_impl (
const std::string &method_name)
917 s += typescript_arg_list<Args...>();
918 s +=
string_format (
"): Promise<%s>\n", typescript_name<R>::name().c_str());
919 s +=
string_format (
" { return this.$rpc (\"%s\", [this%s]); }\n",
920 method_name.
c_str(), typescript_arg_names_list<Args...>().c_str());
923template<
typename T,
typename Ret,
typename... Args>
std::string
924typescript_call (
const std::string &method_name, Ret (T::*func) (Args...))
926 return typescript_call_impl<T, Ret, Args...> (method_name);
928template<
typename T,
typename Ret,
typename... Args>
std::string
929typescript_call (
const std::string &method_name, Ret (T::*func) (Args...) const)
931 return typescript_call_impl<T, Ret, Args...> (method_name);
936 enum Kind { ANY, ENUM, VALUE, RECORD, FIELD, CLASS, METHOD };
940 size_t class_inherit_pos_ = 0;
944 if (open_enum_.
size())
946 if (open_record_.
size())
948 if (open_class_.
size())
951 template<
class,
class =
void>
struct has_nested_T :
std::false_type {};
952 template<
typename U>
struct has_nested_T<U,
std::void_t<typename U::T>> :
std::true_type {};
953 template<
typename M>
struct typescript_call_from_type;
954 template<
typename C,
typename R,
typename... Args>
955 struct typescript_call_from_type<R (C::*)(Args...)> {
959 return typescript_call_impl<C, R, Args...> (method_name);
962 template<
typename C,
typename R,
typename... Args>
963 struct typescript_call_from_type<R (C::*)(Args...) const> {
967 return typescript_call_impl<C, R, Args...>(method_name);
972 template<
typename T>
void
976 open_enum_ = rtti_typename<typename std::decay<T>::type>();
977 b_ +=
"export const " + short_name (open_enum_) +
" = { // " + open_enum_ +
"\n";
979 template<
typename T>
void
984 b_ +=
" " + name +
": \"" + full_js_name +
"\", // " +
std::to_string(
static_cast<underlying
>(v)) +
"\n";
989 b_ +=
"} as const;\n";
990 const std::string shortname = short_name (open_enum_);
991 b_ +=
"export type " + shortname +
" = typeof " + shortname +
"[keyof typeof " + shortname +
"];\n";
992 b_ +=
"Jsonipc.classes[\"" + open_enum_ +
"\"] = " + shortname +
";\n\n";
995 template<
typename T>
void
999 open_record_ = rtti_typename<typename std::decay<T>::type>();
1000 b_ +=
"export class " + short_name (open_record_) +
" { // " + open_record_ +
"\n";
1002 template<
typename T,
typename A>
void
1006 const std::string default_value = js_initializers[js_initializer_index<A>()];
1008 record_fields_.emplace_back (name, ts_type_name, default_value, as_cast);
1013 for (
const auto &[field_name, ts_type_name, default_value, as_cast] : record_fields_)
1014 b_ +=
" " + field_name +
": " + ts_type_name +
";\n";
1015 b_ +=
" constructor (";
1016 for (
size_t i = 0; i < record_fields_.size(); i++) {
1017 const auto &[field_name, ts_type_name, default_value, as_cast] = record_fields_[i];
1018 b_ += (i ?
", " :
"") + field_name +
": " + ts_type_name +
" = " + default_value;
1020 b_ +=
" as " + as_cast;
1023 for (
const auto &[field_name, ts_type_name, default_value, as_cast] : record_fields_)
1024 b_ +=
" this." + field_name +
" = " + field_name +
";\n";
1027 const std::string shortname = short_name (open_record_);
1028 b_ +=
"Jsonipc.classes[\"" + open_record_ +
"\"] = " + shortname +
";\n\n";
1029 record_fields_.clear();
1030 open_record_.
clear();
1032 template<
typename T>
void
1036 open_class_ = rtti_typename<typename std::decay<T>::type>();
1037 const std::string shortname = short_name (open_class_);
1038 b_ +=
"export class " + shortname +
" // " + open_class_ +
"\n";
1039 class_inherit_pos_ = b_.
size();
1041 b_ +=
" constructor ($id)\n";
1042 b_ +=
" { super ($id); if (new.target === " + shortname +
") Jsonipc.ofreeze (this); }\n";
1044 template<
typename B>
void
1047 const std::string base_class_ = rtti_typename<typename std::decay<B>::type>();
1048 b_.
insert (class_inherit_pos_,
" extends Jsonipc.classes[\"" + base_class_ +
"\"]\n");
1050 template<
typename T,
typename M>
void
1053 b_ += typescript_call_from_type<M>::generate (name);
1055 template<
typename T,
typename R,
typename A>
void
1059 b_ +=
" get " + name +
" (): " + ts_type +
"\n";
1060 b_ +=
" { return this.$get (\"" + name +
"\", " + js_initializers[js_initializer_index<R>()] +
") as " + ts_type +
"; }\n";
1061 b_ +=
" set " + name +
" (v: " + ts_type +
")\n";
1062 b_ +=
" { this.$set (\"" + name +
"\", v); }\n";
1068 const std::string shortname = short_name (open_class_);
1069 b_ +=
"Jsonipc.classes[\"" + open_class_ +
"\"] = " + shortname +
";\n\n";
1070 open_class_.
clear();
1090 if (JSONIPC_UNLIKELY (g_binding_printer))
1091 g_binding_printer->enum_type<T> ();
1095 set (T v,
const char *valuename)
1098 auto &entries_ = entries();
1100 Entry e { normalized_typename, v };
1101 entries_.push_back (e);
1102 if (JSONIPC_UNLIKELY (g_binding_printer))
1103 g_binding_printer->enum_value<T> (valuename, v);
1109 return !entries().empty();
1114 const auto &entries_ = entries();
1115 for (
const auto &e : entries_)
1124 auto c_isalnum = [] (
char c) {
1125 return (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9');
1127 const auto &entries_ = entries();
1128 for (
const auto &e : entries_)
1129 if (name == e.name ||
1130 (name.
size() < e.name.size() &&
1131 !c_isalnum (e.name[e.name.size() - name.
size() - 1]) &&
1132 e.name.compare (e.name.size() - name.
size(), name.
size(), name) == 0))
1141 const auto &entries_ = entries();
1142 for (
const auto &e : entries_)
1143 enumvalues.push_back ({
int64_t (e.value), e.name });
1147 struct Entry {
const std::string name; T value; };
1153 return rtti_typename<Type>();
1162 from_json (
const JsonValue &value, T fallback = T())
1164 if (value.IsString())
1168 return EnumType::get_value (
string, fallback);
1173 to_json (T evalue, JsonAllocator &allocator)
1176 if (EnumType::has_names())
1178 const std::string &name = EnumType::get_name (evalue);
1193 make_serializable<T>();
1194 if (JSONIPC_UNLIKELY (g_binding_printer))
1195 g_binding_printer->record_type<T>();
1198 template<typename A, REQUIRES< std::is_member_object_pointer<A>::value > =
true>
Serializable&
1199 set (
const char *name, A attribute)
1202 Accessors accessors;
1203 accessors.setter = [attribute] (T &obj,
const JsonValue &value) ->
void { obj.*attribute = from_json<SetterAttributeType> (value); };
1204 accessors.getter = [attribute] (
const T &obj, JsonAllocator &a) -> JsonValue {
return to_json (obj.*attribute, a); };
1206 auto it = amap.find (name);
1207 if (it != amap.end())
1210 const std::string class_name = rtti_typename<T>();
1211 if (JSONIPC_UNLIKELY (g_binding_printer))
1212 g_binding_printer->field_member<T,SetterAttributeType> (name);
1215 static bool is_serializable () {
return serialize_from_json_() && serialize_to_json_(); }
1216 static JsonValue serialize_to_json (
const T &o, JsonAllocator &a) {
return serialize_to_json_() (o, a); }
1225 static AccessorMap& accessormap() {
static AccessorMap amap;
return amap; }
1226 template<
typename U>
static void
1234 AccessorMap &amap = accessormap();
1235 for (
const auto &field : value.GetObject())
1237 const std::string field_name = field.name.GetString();
1238 auto it = amap.
find (field_name);
1239 if (it == amap.end())
1241 Accessors &accessors = it->second;
1242 accessors.setter (*obj, field.value);
1246 serialize_from_json_() = sfj;
1248 SerializeToJson stj = [] (
const T &object, JsonAllocator &allocator) -> JsonValue {
1249 JsonValue jobject (rapidjson::kObjectType);
1250 AccessorMap &amap = accessormap();
1251 for (
auto &it : amap)
1254 Accessors &accessors = it.second;
1255 JsonValue result = accessors.getter (
object, allocator);
1256 jobject.AddMember (JsonValue (field_name.
c_str(), allocator), result, allocator);
1260 serialize_to_json_() = stj;
1263 using SerializeToJson =
std::function<JsonValue (
const T&, JsonAllocator&)>;
1264 static SerializeFromJson& serialize_from_json_ () {
static SerializeFromJson impl;
return impl; }
1265 static SerializeToJson& serialize_to_json_ () {
static SerializeToJson impl;
return impl; }
1271 Class (
bool internal =
false)
1279 const size_t class_depth = Class::base_depth();
1280 if (class_depth > basedepth) {
1282 if (derived_sptr.get()) {
1283 basedepth = class_depth;
1289 InstanceMap::register_wrapper (create_wrapper);
1290 if (!internal && JSONIPC_UNLIKELY (g_binding_printer))
1291 g_binding_printer->class_type<T>();
1294 template<
typename B>
Class&
1298 if (JSONIPC_UNLIKELY (g_binding_printer))
1299 g_binding_printer->inherit_type<B>();
1303 template<typename F, REQUIRES< std::is_member_function_pointer<F>::value > =
true>
Class&
1304 set (
const char *name,
const F &method)
1306 add_member_function_closure (name, make_closure (method));
1307 if (JSONIPC_UNLIKELY (g_binding_printer))
1308 g_binding_printer->method_member<T,F> (name);
1312 template<
typename R,
typename A,
typename C,
typename VB>
Class&
1313 set (
const char *name, R (C::*get) () const, VB (C::*
set) (A))
1316 JSONIPC_ASSERT_RETURN (get &&
set, *
this);
1317 add_member_function_closure (
std::string (
"get/") + name, make_closure (get));
1318 add_member_function_closure (
std::string (
"set/") + name, make_closure (
set));
1319 if (JSONIPC_UNLIKELY (g_binding_printer))
1320 g_binding_printer->field_accessor<T,R,A> (name);
1323 template<typename F, REQUIRES< std::is_member_function_pointer<F>::value > =
true>
Class&
1324 set_d (
const char *name,
const F &method,
const DefaultsList &dflts)
1327 JSONIPC_ASSERT_RETURN (dflts.size() <= N_ARGS, *
this);
1328 add_member_function_closure (name, make_closure (method));
1329 if (JSONIPC_UNLIKELY (g_binding_printer))
1330 g_binding_printer->method_member<T,F> (name);
1336 return typename_of<T>();
1339 object_from_json (
const JsonValue &value)
1341 InstanceMap::Wrapper *iw = InstanceMap::scope_lookup_wrapper (value);
1345 iw->try_upcast (classname(), &base_sptr);
1356 return rtti_typename<Type>();
1358 template<
typename F>
1360 template<typename F, REQUIRES< HasVoidReturn<F>::value > =
true> Closure
1361 make_closure (
const F &method)
1363 return [method] (
const CallbackInfo &cbi) {
1364 const bool HAS_THIS =
true;
1365 if (HAS_THIS + CallTraits<F>::N_ARGS != cbi.n_args())
1370 call_from_json (*instance, method, cbi);
1373 template<typename F, REQUIRES< !HasVoidReturn<F>::value > =
true> Closure
1374 make_closure (
const F &method)
1376 return [method] (CallbackInfo &cbi) {
1377 const bool HAS_THIS =
true;
1378 if (HAS_THIS + CallTraits<F>::N_ARGS != cbi.n_args())
1384 rv = to_json (call_from_json (*instance, method, cbi), cbi.allocator());
1385 cbi.set_result (rv);
1389 add_member_function_closure (
const std::string &name, Closure &&closure)
1391 MethodMap &
mmap = methodmap();
1392 auto it =
mmap.find (name);
1393 if (it !=
mmap.end())
1398 static MethodMap& methodmap() {
static MethodMap methodmap_;
return methodmap_; }
1403 Closure* (*lookup_closure) (
const char*) = NULL;
1406 template<
typename B>
void
1409 BaseVec &bvec = basevec();
1410 BaseInfo binfo { typename_of<B>(), Class<B>::base_depth, &upcast_impl<B>, &Class<B>::lookup_closure, };
1411 for (
const auto &it : bvec)
1412 if (it.basetypename == binfo.basetypename)
1413 throw
std::runtime_error (
"duplicate base registration: " + binfo.basetypename);
1414 bvec.push_back (binfo);
1415 Class<B> bclass (
true);
1417 static BaseVec& basevec () {
static BaseVec basevec_;
return basevec_; }
1418 template<
typename B>
static bool
1422 return Class<B>::try_upcast (bptr, baseclass, sptrB);
1428 const BaseVec &bvec = basevec();
1430 for (
const auto &binfo : bvec)
1432 const size_t b = binfo.base_depth();
1439 lookup_closure (
const char *methodname)
1441 MethodMap &
mmap = methodmap();
1442 auto it =
mmap.find (methodname);
1443 if (it !=
mmap.end())
1445 const BaseVec &bvec = basevec();
1446 for (
const auto &base : bvec)
1448 Closure *closure = base.lookup_closure (methodname);
1457 if (classname() == baseclass)
1463 const BaseVec &bvec = basevec();
1464 for (
const auto &it : bvec)
1465 if (it.upcast_impl (sptr, baseclass, sptrB))
1472template<
typename T,
typename Enable =
void>
1491 from_json (
const JsonValue &value)
1506 const std::string impltype = rtti_typename (*sptr);
1507 JsonValue result = InstanceMap::scope_wrap_object<ClassType> (sptr, allocator);
1516forget_json_id (
size_t id)
1518 InstanceMap::scope_forget_id (
id);
1526 from_json (
const JsonValue &value)
1531 to_json (
const T *obj, JsonAllocator &allocator)
1552 from_json (
const JsonValue &value)
1560 to_json (
const T &
object, JsonAllocator &allocator)
1571 extra_methods[methodname] = closure;
1577 rapidjson::Document document;
1578 document.Parse<rapidjson_parse_flags> (message.
data(), message.
size());
1581 if (document.HasParseError())
1582 return create_error (
id, -32700,
"Parse error");
1583 const char *methodname =
nullptr;
1584 const JsonValue *args =
nullptr;
1585 for (
const auto &m : document.GetObject())
1587 id = from_json<size_t> (m.value, 0);
1588 else if (m.name ==
"method")
1589 methodname = from_json<const char*> (m.value);
1590 else if (m.name ==
"params" && m.value.IsArray())
1592 if (!
id || !methodname || !args || !args->IsArray())
1593 return create_error (
id, -32600,
"Invalid Request");
1595 Closure *closure = cbi.find_closure (methodname);
1598 const auto it = extra_methods.find (methodname);
1599 if (it != extra_methods.end())
1600 closure = &it->second;
1601 else if (
strcmp (methodname,
"Jsonipc/handshake") == 0)
1604 closure = &initialize;
1608 return create_error (
id, -32601,
"Method not found: " + cbi.classname (
"<unknown-this>") +
"['" + methodname +
"']");
1610 return create_reply (
id, cbi.get_result(), !cbi.have_result(), cbi.document());
1612 return create_error (
id, exc.code(), exc.what());
1618 create_reply (
size_t id, JsonValue &result,
bool skip_result, rapidjson::Document &d)
1620 auto &a = d.GetAllocator();
1622 d.AddMember (
"id",
id, a);
1623 d.AddMember (
"result", result, a);
1624 rapidjson::StringBuffer buffer;
1625 StringBufferWriter writer (buffer);
1627 std::string output { buffer.GetString(), buffer.GetSize() };
1631 create_error (
size_t id,
int errorcode,
const std::string &message)
1633 rapidjson::Document d (rapidjson::kObjectType);
1634 auto &a = d.GetAllocator();
1635 d.AddMember (
"id",
id ? JsonValue (
id) : JsonValue(), a);
1636 JsonValue error (rapidjson::kObjectType);
1637 error.AddMember (
"code", errorcode, a);
1638 error.AddMember (
"message", JsonValue (message.
c_str(), a).Move(), a);
1639 d.AddMember (
"error", error, a);
1640 rapidjson::StringBuffer buffer;
1641 rapidjson::Writer<rapidjson::StringBuffer> writer (buffer);
1643 std::string output { buffer.GetString(), buffer.GetSize() };
1649 cbi.set_result (to_json (0x00000001, cbi.allocator()).Move());
1656JSONIPC_MAP_TO_TYPESCRIPT (
void,
"void");
1657JSONIPC_MAP_TO_TYPESCRIPT (
bool,
"boolean");
1658JSONIPC_MAP_TO_TYPESCRIPT (::int8_t,
"number");
1659JSONIPC_MAP_TO_TYPESCRIPT (::uint8_t,
"number");
1660JSONIPC_MAP_TO_TYPESCRIPT (::int32_t,
"number");
1661JSONIPC_MAP_TO_TYPESCRIPT (::uint32_t,
"number");
1662JSONIPC_MAP_TO_TYPESCRIPT (::int64_t,
"number");
1663JSONIPC_MAP_TO_TYPESCRIPT (::uint64_t,
"number");
1664JSONIPC_MAP_TO_TYPESCRIPT (
float,
"number");
1665JSONIPC_MAP_TO_TYPESCRIPT (
double,
"number");
1666JSONIPC_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.
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.