WIP Node support

The JS engine details are mostly abstracted away. This breaks JSC support until the rest of the pieces are in place. The Node version builds and runs, but crashes when creating a Realm object.
This commit is contained in:
Scott Kyle 2016-03-30 14:11:57 -07:00
parent f80bcd882d
commit 05c432deb1
41 changed files with 3412 additions and 1319 deletions

43
binding.gyp Normal file
View File

@ -0,0 +1,43 @@
{
"targets": [
{
"target_name": "realm",
"sources": [
"src/js_realm.cpp",
"src/node/node_init.cpp",
"src/node/node_object_accessor.cpp",
"src/object-store/src/index_set.cpp",
"src/object-store/src/list.cpp",
"src/object-store/src/object_schema.cpp",
"src/object-store/src/object_store.cpp",
"src/object-store/src/results.cpp",
"src/object-store/src/schema.cpp",
"src/object-store/src/shared_realm.cpp",
"src/object-store/src/impl/async_query.cpp",
"src/object-store/src/impl/transact_log_handler.cpp",
"src/object-store/src/impl/realm_coordinator.cpp",
"src/object-store/src/impl/apple/external_commit_helper.cpp",
"src/object-store/src/impl/apple/weak_realm_notifier.cpp",
"src/object-store/src/parser/parser.cpp",
"src/object-store/src/parser/query_builder.cpp",
"src/ios/platform.mm"
],
"include_dirs": [
"core/include",
"node_modules/nan",
"src",
"src/object-store/src",
"src/object-store/src/impl",
"src/object-store/src/impl/apple",
"src/object-store/src/parser",
"src/object-store/external/pegtl"
],
"cflags_cc": ["-DREALM_HAVE_CONFIG", "-fexceptions", "-frtti", "-std=c++14", "-g", "-O0"],
"ldflags": ["-Lcore", "-lrealm"],
"xcode_settings": {
"OTHER_CFLAGS": ["-mmacosx-version-min=10.8", "-DREALM_HAVE_CONFIG", "-fexceptions", "-frtti", "-std=c++14", "-stdlib=libc++", "-g", "-O0", "-Wno-mismatched-tags"],
"OTHER_LDFLAGS": ["-mmacosx-version-min=10.8", "-framework", "Foundation", "-Lcore", "-lrealm", "-std=c++14"]
}
}
]
}

View File

@ -47,6 +47,9 @@
"prepublish": "scripts/prepublish.sh"
},
"dependencies": {
"bindings": "^1.2.1",
"nan": "^2.2.1",
"node-gyp": "^3.3.1",
"rnpm": "1.5.2",
"xcode": "0.8.4"
},

View File

@ -19,6 +19,6 @@
#ifndef REALM_JS_H
#define REALM_JS_H
#include <RealmJS/js_init.h>
#include <RealmJS/jsc_init.h>
#endif /* REALM_JS_H */

View File

@ -11,13 +11,13 @@
025678981CAB478800FB8501 /* jsc_realm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 025678961CAB478800FB8501 /* jsc_realm.cpp */; };
0270BC821B7D020100010E03 /* RealmJSTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC7B1B7D020100010E03 /* RealmJSTests.mm */; };
0270BC871B7D023200010E03 /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; };
029048121C0428DF00ABDED4 /* js_init.h in Headers */ = {isa = PBXBuildFile; fileRef = 029048021C0428DF00ABDED4 /* js_init.h */; settings = {ATTRIBUTES = (Public, ); }; };
029048121C0428DF00ABDED4 /* jsc_init.h in Headers */ = {isa = PBXBuildFile; fileRef = 029048021C0428DF00ABDED4 /* jsc_init.h */; settings = {ATTRIBUTES = (Public, ); }; };
029048141C0428DF00ABDED4 /* js_list.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029048041C0428DF00ABDED4 /* js_list.hpp */; };
029048161C0428DF00ABDED4 /* js_object.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029048061C0428DF00ABDED4 /* js_object.hpp */; };
029048181C0428DF00ABDED4 /* js_realm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029048081C0428DF00ABDED4 /* js_realm.hpp */; };
0290481A1C0428DF00ABDED4 /* js_results.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0290480A1C0428DF00ABDED4 /* js_results.hpp */; };
0290481C1C0428DF00ABDED4 /* js_schema.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0290480C1C0428DF00ABDED4 /* js_schema.hpp */; };
0290481E1C0428DF00ABDED4 /* js_util.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0290480E1C0428DF00ABDED4 /* js_util.hpp */; };
0290481E1C0428DF00ABDED4 /* jsc_util.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0290480E1C0428DF00ABDED4 /* jsc_util.hpp */; };
029048201C0428DF00ABDED4 /* rpc.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029048101C0428DF00ABDED4 /* rpc.hpp */; settings = {ATTRIBUTES = (Public, ); }; };
029048371C042A3C00ABDED4 /* platform.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029048351C042A3C00ABDED4 /* platform.hpp */; };
0290483B1C042EE200ABDED4 /* RealmJS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0290483A1C042EE200ABDED4 /* RealmJS.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -38,13 +38,33 @@
02F59EE11C88F2BB007F774C /* async_query.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59ED61C88F2BA007F774C /* async_query.cpp */; };
02F59EE21C88F2BB007F774C /* realm_coordinator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EDB1C88F2BA007F774C /* realm_coordinator.cpp */; };
02F59EE31C88F2BB007F774C /* transact_log_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EDD1C88F2BB007F774C /* transact_log_handler.cpp */; };
F60102D31CBB966E00EC01BA /* js_realm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048071C0428DF00ABDED4 /* js_realm.cpp */; };
F60102D41CBB96AB00EC01BA /* index_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EAF1C88F17D007F774C /* index_set.cpp */; };
F60102D51CBB96AE00EC01BA /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EB11C88F17D007F774C /* list.cpp */; };
F60102D61CBB96B400EC01BA /* object_schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EB41C88F17D007F774C /* object_schema.cpp */; };
F60102D71CBB96B800EC01BA /* object_store.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EB61C88F17D007F774C /* object_store.cpp */; };
F60102D81CBB96BD00EC01BA /* results.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EB91C88F17D007F774C /* results.cpp */; };
F60102D91CBB96C100EC01BA /* schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EBB1C88F17D007F774C /* schema.cpp */; };
F60102DA1CBB96C300EC01BA /* shared_realm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EBD1C88F17D007F774C /* shared_realm.cpp */; };
F60102DB1CBB96C600EC01BA /* parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EC61C88F190007F774C /* parser.cpp */; };
F60102DC1CBB96C900EC01BA /* query_builder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EC81C88F190007F774C /* query_builder.cpp */; };
F60102DD1CBB96CC00EC01BA /* external_commit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59ECF1C88F1B6007F774C /* external_commit_helper.cpp */; };
F60102DE1CBB96CF00EC01BA /* weak_realm_notifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59ED11C88F1B6007F774C /* weak_realm_notifier.cpp */; };
F60102DF1CBB96D300EC01BA /* async_query.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59ED61C88F2BA007F774C /* async_query.cpp */; };
F60102E01CBB96D900EC01BA /* realm_coordinator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EDB1C88F2BA007F774C /* realm_coordinator.cpp */; };
F60102E11CBB96DD00EC01BA /* transact_log_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EDD1C88F2BB007F774C /* transact_log_handler.cpp */; };
F60102E41CBBB19700EC01BA /* node_object_accessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F60102E21CBBB19700EC01BA /* node_object_accessor.cpp */; };
F60102E51CBBB19700EC01BA /* node_object_accessor.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F60102E31CBBB19700EC01BA /* node_object_accessor.hpp */; };
F60102E81CBBB36500EC01BA /* jsc_object_accessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F60102E61CBBB36500EC01BA /* jsc_object_accessor.cpp */; };
F60102E91CBCAEC500EC01BA /* platform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 029048381C042A8F00ABDED4 /* platform.mm */; };
F60102EA1CBCAFC300EC01BA /* node_dummy.c in Sources */ = {isa = PBXBuildFile; fileRef = F6267BCA1CADC49200AC36B1 /* node_dummy.c */; };
F61378791C18EAC5008BFC51 /* js in Resources */ = {isa = PBXBuildFile; fileRef = F61378781C18EAAC008BFC51 /* js */; };
F63FF2C61C12469E00B3B8E0 /* js_init.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048011C0428DF00ABDED4 /* js_init.cpp */; };
F63FF2C81C12469E00B3B8E0 /* js_object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048051C0428DF00ABDED4 /* js_object.cpp */; };
F620F0581CB766DA0082977B /* node_init.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F620F0571CB766DA0082977B /* node_init.cpp */; };
F620F0751CB9F60C0082977B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F620F0741CB9F60C0082977B /* CoreFoundation.framework */; };
F63FF2C61C12469E00B3B8E0 /* jsc_init.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048011C0428DF00ABDED4 /* jsc_init.cpp */; };
F63FF2C91C12469E00B3B8E0 /* js_realm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048071C0428DF00ABDED4 /* js_realm.cpp */; };
F63FF2CA1C12469E00B3B8E0 /* js_results.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048091C0428DF00ABDED4 /* js_results.cpp */; };
F63FF2CB1C12469E00B3B8E0 /* js_schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0290480B1C0428DF00ABDED4 /* js_schema.cpp */; };
F63FF2CC1C12469E00B3B8E0 /* js_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0290480D1C0428DF00ABDED4 /* js_util.cpp */; };
F63FF2CD1C12469E00B3B8E0 /* rpc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0290480F1C0428DF00ABDED4 /* rpc.cpp */; };
F63FF2DE1C1565EA00B3B8E0 /* RealmJS.mm in Sources */ = {isa = PBXBuildFile; fileRef = F63FF2DC1C15659A00B3B8E0 /* RealmJS.mm */; };
F63FF2E11C1591EC00B3B8E0 /* libRealmJS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F63FF2B11C1241E500B3B8E0 /* libRealmJS.a */; };
@ -66,8 +86,8 @@
F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */; };
F6BB7DF21BF681BC00D0A69E /* base64.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F6BB7DF01BF681BC00D0A69E /* base64.hpp */; };
F6BCCFE21C8380A400FE31AE /* lib in Resources */ = {isa = PBXBuildFile; fileRef = F6BCCFDF1C83809A00FE31AE /* lib */; };
F6CB31001C8EDDAB0070EF3F /* js_collection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6CB30FC1C8EDD760070EF3F /* js_collection.cpp */; };
F6CB31011C8EDDBB0070EF3F /* js_collection.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F6CB30FD1C8EDD760070EF3F /* js_collection.hpp */; };
F6CB31001C8EDDAB0070EF3F /* jsc_collection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6CB30FC1C8EDD760070EF3F /* jsc_collection.cpp */; };
F6CB31011C8EDDBB0070EF3F /* jsc_collection.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F6CB30FD1C8EDD760070EF3F /* jsc_collection.hpp */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -101,17 +121,16 @@
/* Begin PBXFileReference section */
02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RealmJSCoreTests.m; path = ios/RealmJSCoreTests.m; sourceTree = "<group>"; };
025678951CAB392000FB8501 /* types.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = types.hpp; path = jsc/types.hpp; sourceTree = "<group>"; };
025678961CAB478800FB8501 /* jsc_realm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsc_realm.cpp; path = jsc/jsc_realm.cpp; sourceTree = "<group>"; };
025678971CAB478800FB8501 /* jsc_realm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = jsc_realm.hpp; path = jsc/jsc_realm.hpp; sourceTree = "<group>"; };
025678951CAB392000FB8501 /* jsc_types.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_types.hpp; sourceTree = "<group>"; };
025678961CAB478800FB8501 /* jsc_realm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsc_realm.cpp; sourceTree = "<group>"; };
025678971CAB478800FB8501 /* jsc_realm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_realm.hpp; sourceTree = "<group>"; };
0270BC5A1B7CFC1300010E03 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0270BC781B7D020100010E03 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ios/Info.plist; sourceTree = "<group>"; };
0270BC7A1B7D020100010E03 /* RealmJSTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJSTests.h; path = ios/RealmJSTests.h; sourceTree = "<group>"; };
0270BC7B1B7D020100010E03 /* RealmJSTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmJSTests.mm; path = ios/RealmJSTests.mm; sourceTree = "<group>"; };
029048011C0428DF00ABDED4 /* js_init.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = js_init.cpp; sourceTree = "<group>"; };
029048021C0428DF00ABDED4 /* js_init.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = js_init.h; sourceTree = "<group>"; };
029048011C0428DF00ABDED4 /* jsc_init.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsc_init.cpp; sourceTree = "<group>"; };
029048021C0428DF00ABDED4 /* jsc_init.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsc_init.h; sourceTree = "<group>"; };
029048041C0428DF00ABDED4 /* js_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_list.hpp; sourceTree = "<group>"; };
029048051C0428DF00ABDED4 /* js_object.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = js_object.cpp; sourceTree = "<group>"; };
029048061C0428DF00ABDED4 /* js_object.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_object.hpp; sourceTree = "<group>"; };
029048071C0428DF00ABDED4 /* js_realm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = js_realm.cpp; sourceTree = "<group>"; };
029048081C0428DF00ABDED4 /* js_realm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_realm.hpp; sourceTree = "<group>"; };
@ -119,17 +138,15 @@
0290480A1C0428DF00ABDED4 /* js_results.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_results.hpp; sourceTree = "<group>"; };
0290480B1C0428DF00ABDED4 /* js_schema.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = js_schema.cpp; sourceTree = "<group>"; };
0290480C1C0428DF00ABDED4 /* js_schema.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_schema.hpp; sourceTree = "<group>"; };
0290480D1C0428DF00ABDED4 /* js_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = js_util.cpp; sourceTree = "<group>"; };
0290480E1C0428DF00ABDED4 /* js_util.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_util.hpp; sourceTree = "<group>"; };
0290480E1C0428DF00ABDED4 /* jsc_util.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_util.hpp; sourceTree = "<group>"; };
0290480F1C0428DF00ABDED4 /* rpc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rpc.cpp; sourceTree = "<group>"; };
029048101C0428DF00ABDED4 /* rpc.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = rpc.hpp; sourceTree = "<group>"; };
029048351C042A3C00ABDED4 /* platform.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = platform.hpp; sourceTree = "<group>"; };
029048381C042A8F00ABDED4 /* platform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = platform.mm; sourceTree = "<group>"; };
0290483A1C042EE200ABDED4 /* RealmJS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealmJS.h; sourceTree = "<group>"; };
02A3C7A41BC4341500B1A7BE /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
02AFE5871CA9B23400953DA3 /* jsc_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsc_list.cpp; path = jsc/jsc_list.cpp; sourceTree = "<group>"; };
02AFE5881CA9B23400953DA3 /* jsc_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = jsc_list.hpp; path = jsc/jsc_list.hpp; sourceTree = "<group>"; };
02AFE5B11CAB133500953DA3 /* js_compat.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = js_compat.hpp; path = jsc/js_compat.hpp; sourceTree = "<group>"; };
02AFE5871CA9B23400953DA3 /* jsc_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsc_list.cpp; sourceTree = "<group>"; };
02AFE5881CA9B23400953DA3 /* jsc_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_list.hpp; sourceTree = "<group>"; };
02B58CB11AE99CEC009B348C /* RealmJS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmJS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
02B58CBC1AE99CEC009B348C /* RealmJSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RealmJSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
@ -167,7 +184,22 @@
02F59EDE1C88F2BB007F774C /* transact_log_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = transact_log_handler.hpp; path = src/impl/transact_log_handler.hpp; sourceTree = "<group>"; };
02F59EDF1C88F2BB007F774C /* weak_realm_notifier_base.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = weak_realm_notifier_base.hpp; path = src/impl/weak_realm_notifier_base.hpp; sourceTree = "<group>"; };
02F59EE01C88F2BB007F774C /* weak_realm_notifier.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = weak_realm_notifier.hpp; path = src/impl/weak_realm_notifier.hpp; sourceTree = "<group>"; };
F60102CF1CBB814A00EC01BA /* node_init.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_init.hpp; sourceTree = "<group>"; };
F60102D11CBB865A00EC01BA /* jsc_init.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_init.hpp; sourceTree = "<group>"; };
F60102E21CBBB19700EC01BA /* node_object_accessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node_object_accessor.cpp; sourceTree = "<group>"; };
F60102E31CBBB19700EC01BA /* node_object_accessor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = node_object_accessor.hpp; sourceTree = "<group>"; };
F60102E61CBBB36500EC01BA /* jsc_object_accessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsc_object_accessor.cpp; sourceTree = "<group>"; };
F60102E71CBBB36500EC01BA /* jsc_object_accessor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_object_accessor.hpp; sourceTree = "<group>"; };
F61378781C18EAAC008BFC51 /* js */ = {isa = PBXFileReference; lastKnownFileType = folder; path = js; sourceTree = "<group>"; };
F620F0521CAF0B600082977B /* js_class.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_class.hpp; sourceTree = "<group>"; };
F620F0531CAF2EF70082977B /* jsc_class.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_class.hpp; sourceTree = "<group>"; };
F620F0551CB655A50082977B /* node_class.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_class.hpp; sourceTree = "<group>"; };
F620F0571CB766DA0082977B /* node_init.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node_init.cpp; sourceTree = "<group>"; };
F620F0591CB7B4C80082977B /* js_object_accessor.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_object_accessor.hpp; sourceTree = "<group>"; };
F620F0741CB9F60C0082977B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
F6267BC91CADC30000AC36B1 /* js_util.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_util.hpp; sourceTree = "<group>"; };
F6267BCA1CADC49200AC36B1 /* node_dummy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = node_dummy.c; sourceTree = "<group>"; };
F62BF8FB1CAC71780022BCDC /* libRealmNode.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libRealmNode.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
F63FF2B11C1241E500B3B8E0 /* libRealmJS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRealmJS.a; sourceTree = BUILT_PRODUCTS_DIR; };
F63FF2DC1C15659A00B3B8E0 /* RealmJS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RealmJS.mm; sourceTree = "<group>"; };
F63FF2F01C16405C00B3B8E0 /* libGCDWebServers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libGCDWebServers.a; sourceTree = BUILT_PRODUCTS_DIR; };
@ -204,14 +236,16 @@
F63FF32C1C16432E00B3B8E0 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
F63FF32E1C16433900B3B8E0 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = usr/lib/libxml2.tbd; sourceTree = SDKROOT; };
F63FF3301C16434400B3B8E0 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
F6874A351CAC792D00EEEE36 /* node_types.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_types.hpp; sourceTree = "<group>"; };
F6874A3E1CACA5A900EEEE36 /* js_types.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_types.hpp; sourceTree = "<group>"; };
F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RJSModuleLoader.h; path = ios/RJSModuleLoader.h; sourceTree = "<group>"; };
F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RJSModuleLoader.m; path = ios/RJSModuleLoader.m; sourceTree = "<group>"; };
F6BB7DEF1BF681BC00D0A69E /* base64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = base64.cpp; sourceTree = "<group>"; };
F6BB7DF01BF681BC00D0A69E /* base64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = base64.hpp; sourceTree = "<group>"; };
F6BCCFDF1C83809A00FE31AE /* lib */ = {isa = PBXFileReference; lastKnownFileType = folder; name = lib; path = ../../lib; sourceTree = SOURCE_ROOT; };
F6C3FBBC1BF680EC00E6FFD4 /* json.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json.hpp; sourceTree = "<group>"; };
F6CB30FC1C8EDD760070EF3F /* js_collection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = js_collection.cpp; sourceTree = "<group>"; };
F6CB30FD1C8EDD760070EF3F /* js_collection.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_collection.hpp; sourceTree = "<group>"; };
F6CB30FC1C8EDD760070EF3F /* jsc_collection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = jsc_collection.cpp; sourceTree = "<group>"; };
F6CB30FD1C8EDD760070EF3F /* jsc_collection.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_collection.hpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -233,6 +267,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
F62BF8F81CAC71780022BCDC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F620F0751CB9F60C0082977B /* CoreFoundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F63FF2ED1C16405C00B3B8E0 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -248,13 +290,11 @@
children = (
F6BCCFDF1C83809A00FE31AE /* lib */,
F62A35131C18E6E2004A917D /* iOS */,
F6874A441CAD2ACD00EEEE36 /* JSC */,
F62BF9001CAC72C40022BCDC /* Node */,
F62A35141C18E783004A917D /* Object Store */,
029048011C0428DF00ABDED4 /* js_init.cpp */,
029048021C0428DF00ABDED4 /* js_init.h */,
F6CB30FC1C8EDD760070EF3F /* js_collection.cpp */,
F6CB30FD1C8EDD760070EF3F /* js_collection.hpp */,
029048041C0428DF00ABDED4 /* js_list.hpp */,
029048051C0428DF00ABDED4 /* js_object.cpp */,
F620F0591CB7B4C80082977B /* js_object_accessor.hpp */,
029048061C0428DF00ABDED4 /* js_object.hpp */,
029048071C0428DF00ABDED4 /* js_realm.cpp */,
029048081C0428DF00ABDED4 /* js_realm.hpp */,
@ -262,14 +302,9 @@
0290480A1C0428DF00ABDED4 /* js_results.hpp */,
0290480B1C0428DF00ABDED4 /* js_schema.cpp */,
0290480C1C0428DF00ABDED4 /* js_schema.hpp */,
0290480D1C0428DF00ABDED4 /* js_util.cpp */,
0290480E1C0428DF00ABDED4 /* js_util.hpp */,
02AFE5B11CAB133500953DA3 /* js_compat.hpp */,
025678951CAB392000FB8501 /* types.hpp */,
02AFE5871CA9B23400953DA3 /* jsc_list.cpp */,
02AFE5881CA9B23400953DA3 /* jsc_list.hpp */,
025678961CAB478800FB8501 /* jsc_realm.cpp */,
025678971CAB478800FB8501 /* jsc_realm.hpp */,
F620F0521CAF0B600082977B /* js_class.hpp */,
F6874A3E1CACA5A900EEEE36 /* js_types.hpp */,
F6267BC91CADC30000AC36B1 /* js_util.hpp */,
029048351C042A3C00ABDED4 /* platform.hpp */,
0290480F1C0428DF00ABDED4 /* rpc.cpp */,
029048101C0428DF00ABDED4 /* rpc.hpp */,
@ -296,6 +331,7 @@
02B58CBC1AE99CEC009B348C /* RealmJSTests.xctest */,
F63FF2B11C1241E500B3B8E0 /* libRealmJS.a */,
F63FF2F01C16405C00B3B8E0 /* libGCDWebServers.a */,
F62BF8FB1CAC71780022BCDC /* libRealmNode.dylib */,
);
name = Products;
sourceTree = "<group>";
@ -318,6 +354,7 @@
02B58CCF1AE99D8C009B348C /* Frameworks */ = {
isa = PBXGroup;
children = (
F620F0741CB9F60C0082977B /* CoreFoundation.framework */,
02A3C7A41BC4341500B1A7BE /* libc++.tbd */,
F63FF3301C16434400B3B8E0 /* libz.tbd */,
F63FF32E1C16433900B3B8E0 /* libxml2.tbd */,
@ -383,6 +420,21 @@
path = "object-store";
sourceTree = "<group>";
};
F62BF9001CAC72C40022BCDC /* Node */ = {
isa = PBXGroup;
children = (
F6267BCA1CADC49200AC36B1 /* node_dummy.c */,
F60102CF1CBB814A00EC01BA /* node_init.hpp */,
F620F0571CB766DA0082977B /* node_init.cpp */,
F620F0551CB655A50082977B /* node_class.hpp */,
F6874A351CAC792D00EEEE36 /* node_types.hpp */,
F60102E31CBBB19700EC01BA /* node_object_accessor.hpp */,
F60102E21CBBB19700EC01BA /* node_object_accessor.cpp */,
);
name = Node;
path = node;
sourceTree = "<group>";
};
F63FF2FB1C1642BB00B3B8E0 /* GCDWebServer */ = {
isa = PBXGroup;
children = (
@ -443,6 +495,28 @@
path = Responses;
sourceTree = "<group>";
};
F6874A441CAD2ACD00EEEE36 /* JSC */ = {
isa = PBXGroup;
children = (
029048021C0428DF00ABDED4 /* jsc_init.h */,
F60102D11CBB865A00EC01BA /* jsc_init.hpp */,
029048011C0428DF00ABDED4 /* jsc_init.cpp */,
F620F0531CAF2EF70082977B /* jsc_class.hpp */,
025678951CAB392000FB8501 /* jsc_types.hpp */,
0290480E1C0428DF00ABDED4 /* jsc_util.hpp */,
F6CB30FD1C8EDD760070EF3F /* jsc_collection.hpp */,
F6CB30FC1C8EDD760070EF3F /* jsc_collection.cpp */,
02AFE5881CA9B23400953DA3 /* jsc_list.hpp */,
02AFE5871CA9B23400953DA3 /* jsc_list.cpp */,
025678971CAB478800FB8501 /* jsc_realm.hpp */,
025678961CAB478800FB8501 /* jsc_realm.cpp */,
F60102E71CBBB36500EC01BA /* jsc_object_accessor.hpp */,
F60102E61CBBB36500EC01BA /* jsc_object_accessor.cpp */,
);
name = JSC;
path = jsc;
sourceTree = "<group>";
};
F6C3FBB41BF680D000E6FFD4 /* Vendor */ = {
isa = PBXGroup;
children = (
@ -463,20 +537,28 @@
buildActionMask = 2147483647;
files = (
0290483B1C042EE200ABDED4 /* RealmJS.h in Headers */,
029048121C0428DF00ABDED4 /* js_init.h in Headers */,
029048121C0428DF00ABDED4 /* jsc_init.h in Headers */,
029048201C0428DF00ABDED4 /* rpc.hpp in Headers */,
0290481E1C0428DF00ABDED4 /* js_util.hpp in Headers */,
0290481E1C0428DF00ABDED4 /* jsc_util.hpp in Headers */,
0290481A1C0428DF00ABDED4 /* js_results.hpp in Headers */,
029048181C0428DF00ABDED4 /* js_realm.hpp in Headers */,
029048141C0428DF00ABDED4 /* js_list.hpp in Headers */,
F6BB7DF21BF681BC00D0A69E /* base64.hpp in Headers */,
F6CB31011C8EDDBB0070EF3F /* js_collection.hpp in Headers */,
F6CB31011C8EDDBB0070EF3F /* jsc_collection.hpp in Headers */,
0290481C1C0428DF00ABDED4 /* js_schema.hpp in Headers */,
029048161C0428DF00ABDED4 /* js_object.hpp in Headers */,
029048371C042A3C00ABDED4 /* platform.hpp in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F62BF8F91CAC71780022BCDC /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
F60102E51CBBB19700EC01BA /* node_object_accessor.hpp in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
@ -518,6 +600,23 @@
productReference = 02B58CBC1AE99CEC009B348C /* RealmJSTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
F62BF8FA1CAC71780022BCDC /* RealmNode */ = {
isa = PBXNativeTarget;
buildConfigurationList = F62BF8FF1CAC71780022BCDC /* Build configuration list for PBXNativeTarget "RealmNode" */;
buildPhases = (
F62BF8F71CAC71780022BCDC /* Sources */,
F62BF8F81CAC71780022BCDC /* Frameworks */,
F62BF8F91CAC71780022BCDC /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = RealmNode;
productName = RealmNode;
productReference = F62BF8FB1CAC71780022BCDC /* libRealmNode.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
F63FF2B01C1241E500B3B8E0 /* RealmJS static */ = {
isa = PBXNativeTarget;
buildConfigurationList = F63FF2C41C1241E500B3B8E0 /* Build configuration list for PBXNativeTarget "RealmJS static" */;
@ -566,6 +665,9 @@
02B58CBB1AE99CEC009B348C = {
CreatedOnToolsVersion = 6.3.1;
};
F62BF8FA1CAC71780022BCDC = {
CreatedOnToolsVersion = 7.3;
};
F63FF2B01C1241E500B3B8E0 = {
CreatedOnToolsVersion = 7.1.1;
};
@ -588,6 +690,7 @@
targets = (
F63FF2EF1C16405C00B3B8E0 /* GCDWebServers */,
F63FF2B01C1241E500B3B8E0 /* RealmJS static */,
F62BF8FA1CAC71780022BCDC /* RealmNode */,
02B58CB01AE99CEC009B348C /* RealmJS */,
02B58CBB1AE99CEC009B348C /* RealmJSTests */,
);
@ -655,20 +758,45 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
F62BF8F71CAC71780022BCDC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F60102D31CBB966E00EC01BA /* js_realm.cpp in Sources */,
F60102E41CBBB19700EC01BA /* node_object_accessor.cpp in Sources */,
F60102D61CBB96B400EC01BA /* object_schema.cpp in Sources */,
F60102D41CBB96AB00EC01BA /* index_set.cpp in Sources */,
F60102DB1CBB96C600EC01BA /* parser.cpp in Sources */,
F60102D51CBB96AE00EC01BA /* list.cpp in Sources */,
F60102DC1CBB96C900EC01BA /* query_builder.cpp in Sources */,
F60102DD1CBB96CC00EC01BA /* external_commit_helper.cpp in Sources */,
F60102E11CBB96DD00EC01BA /* transact_log_handler.cpp in Sources */,
F60102D71CBB96B800EC01BA /* object_store.cpp in Sources */,
F60102DA1CBB96C300EC01BA /* shared_realm.cpp in Sources */,
F60102E01CBB96D900EC01BA /* realm_coordinator.cpp in Sources */,
F60102EA1CBCAFC300EC01BA /* node_dummy.c in Sources */,
F60102D81CBB96BD00EC01BA /* results.cpp in Sources */,
F60102DE1CBB96CF00EC01BA /* weak_realm_notifier.cpp in Sources */,
F620F0581CB766DA0082977B /* node_init.cpp in Sources */,
F60102D91CBB96C100EC01BA /* schema.cpp in Sources */,
F60102E91CBCAEC500EC01BA /* platform.mm in Sources */,
F60102DF1CBB96D300EC01BA /* async_query.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F63FF2AD1C1241E500B3B8E0 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F6CB31001C8EDDAB0070EF3F /* js_collection.cpp in Sources */,
F6CB31001C8EDDAB0070EF3F /* jsc_collection.cpp in Sources */,
02F59EE31C88F2BB007F774C /* transact_log_handler.cpp in Sources */,
025678981CAB478800FB8501 /* jsc_realm.cpp in Sources */,
F63FF2E81C159C4B00B3B8E0 /* platform.mm in Sources */,
02F59EC31C88F17D007F774C /* results.cpp in Sources */,
02AFE5891CA9B23400953DA3 /* jsc_list.cpp in Sources */,
F63FF2E21C15921A00B3B8E0 /* base64.cpp in Sources */,
F63FF2C61C12469E00B3B8E0 /* js_init.cpp in Sources */,
F63FF2C61C12469E00B3B8E0 /* jsc_init.cpp in Sources */,
02F59ECA1C88F190007F774C /* parser.cpp in Sources */,
F63FF2C81C12469E00B3B8E0 /* js_object.cpp in Sources */,
02F59EE11C88F2BB007F774C /* async_query.cpp in Sources */,
02F59EC01C88F17D007F774C /* list.cpp in Sources */,
02F59EBF1C88F17D007F774C /* index_set.cpp in Sources */,
@ -677,8 +805,8 @@
F63FF2CA1C12469E00B3B8E0 /* js_results.cpp in Sources */,
02F59EC51C88F17D007F774C /* shared_realm.cpp in Sources */,
F63FF2CB1C12469E00B3B8E0 /* js_schema.cpp in Sources */,
F63FF2CC1C12469E00B3B8E0 /* js_util.cpp in Sources */,
02F59ECB1C88F190007F774C /* query_builder.cpp in Sources */,
F60102E81CBBB36500EC01BA /* jsc_object_accessor.cpp in Sources */,
02F59EE21C88F2BB007F774C /* realm_coordinator.cpp in Sources */,
02F59EC41C88F17D007F774C /* schema.cpp in Sources */,
F63FF2CD1C12469E00B3B8E0 /* rpc.cpp in Sources */,
@ -771,6 +899,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../object-store/external/pegtl",
"$(SRCROOT)/../object-store/src",
"$(SRCROOT)/../../vendor",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = ../../core;
MTL_ENABLE_DEBUG_INFO = YES;
@ -823,6 +956,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../object-store/external/pegtl",
"$(SRCROOT)/../object-store/src",
"$(SRCROOT)/../../vendor",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = ../../core;
MTL_ENABLE_DEBUG_INFO = NO;
@ -958,6 +1096,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../object-store/external/pegtl",
"$(SRCROOT)/../object-store/src",
"$(SRCROOT)/../../vendor",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = ../../core;
MTL_ENABLE_DEBUG_INFO = YES;
@ -1016,6 +1159,95 @@
};
name = GCov_Build;
};
F62BF8FC1CAC71780022BCDC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../../node_modules/nan",
/usr/local/include/node,
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
/usr/local/lib,
);
OTHER_CPLUSPLUSFLAGS = (
"$(inherited)",
"-ftemplate-backtrace-limit=0",
);
OTHER_LDFLAGS = (
"-lrealm",
"-lv8",
);
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
};
name = Debug;
};
F62BF8FD1CAC71780022BCDC /* GCov_Build */ = {
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_PREFIX = lib;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../../node_modules/nan",
/usr/local/include/node,
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
/usr/local/lib,
);
OTHER_CPLUSPLUSFLAGS = (
"$(inherited)",
"-ftemplate-backtrace-limit=0",
);
OTHER_LDFLAGS = (
"-lrealm",
"-lv8",
);
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
};
name = GCov_Build;
};
F62BF8FE1CAC71780022BCDC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_PREFIX = lib;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../../node_modules/nan",
/usr/local/include/node,
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
/usr/local/lib,
);
OTHER_CPLUSPLUSFLAGS = (
"$(inherited)",
"-ftemplate-backtrace-limit=0",
);
OTHER_LDFLAGS = (
"-lrealm",
"-lv8",
);
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
};
name = Release;
};
F63FF2B71C1241E500B3B8E0 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -1024,12 +1256,6 @@
"DEBUG=1",
"$(inherited)",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../object-store/external/pegtl",
"$(SRCROOT)/../object-store/src",
"$(SRCROOT)/../../vendor",
);
PRODUCT_NAME = RealmJS;
SKIP_INSTALL = YES;
};
@ -1038,12 +1264,6 @@
F63FF2B81C1241E500B3B8E0 /* GCov_Build */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../object-store/external/pegtl",
"$(SRCROOT)/../object-store/src",
"$(SRCROOT)/../../vendor",
);
PRODUCT_NAME = RealmJS;
SKIP_INSTALL = YES;
};
@ -1052,12 +1272,6 @@
F63FF2B91C1241E500B3B8E0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../object-store/external/pegtl",
"$(SRCROOT)/../object-store/src",
"$(SRCROOT)/../../vendor",
);
PRODUCT_NAME = RealmJS;
SKIP_INSTALL = YES;
};
@ -1071,6 +1285,7 @@
"DEBUG=1",
"$(inherited)",
);
HEADER_SEARCH_PATHS = "";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@ -1080,6 +1295,7 @@
F63FF2F71C16405D00B3B8E0 /* GCov_Build */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = "";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@ -1089,6 +1305,7 @@
F63FF2F81C16405D00B3B8E0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = "";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@ -1128,6 +1345,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F62BF8FF1CAC71780022BCDC /* Build configuration list for PBXNativeTarget "RealmNode" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F62BF8FC1CAC71780022BCDC /* Debug */,
F62BF8FD1CAC71780022BCDC /* GCov_Build */,
F62BF8FE1CAC71780022BCDC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F63FF2C41C1241E500B3B8E0 /* Build configuration list for PBXNativeTarget "RealmJS static" */ = {
isa = XCConfigurationList;
buildConfigurations = (

100
src/js_class.hpp Normal file
View File

@ -0,0 +1,100 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include <map>
#include <string>
#include <vector>
#include "js_types.hpp"
namespace realm {
namespace js {
template<typename T>
using ConstructorType = void(typename T::Context, typename T::Object, size_t, const typename T::Value[]);
template<typename T>
using MethodType = void(typename T::Context, typename T::Object, size_t, const typename T::Value[], ReturnValue<T> &);
template<typename T>
using PropertyGetterType = void(typename T::Context, typename T::Object, ReturnValue<T> &);
template<typename T>
using PropertySetterType = void(typename T::Context, typename T::Object, typename T::Value);
template<typename T>
using IndexPropertyGetterType = void(typename T::Context, typename T::Object, uint32_t, ReturnValue<T> &);
template<typename T>
using IndexPropertySetterType = bool(typename T::Context, typename T::Object, uint32_t, typename T::Value);
template<typename T>
using StringPropertyGetterType = void(typename T::Context, typename T::Object, const String<T> &, ReturnValue<T> &);
template<typename T>
using StringPropertySetterType = bool(typename T::Context, typename T::Object, const String<T> &, typename T::Value);
template<typename T>
using StringPropertyEnumeratorType = std::vector<String<T>>(typename T::Context, typename T::Object);
template<typename T>
struct PropertyType {
typename T::PropertyGetterCallback getter;
typename T::PropertySetterCallback setter;
};
template<typename T>
struct IndexPropertyType {
typename T::IndexPropertyGetterCallback getter;
typename T::IndexPropertySetterCallback setter;
};
template<typename T>
struct StringPropertyType {
typename T::StringPropertyGetterCallback getter;
typename T::StringPropertySetterCallback setter;
typename T::StringPropertyEnumeratorCallback enumerator;
};
template<typename T>
using MethodMap = std::map<std::string, typename T::FunctionCallback>;
template<typename T>
using PropertyMap = std::map<std::string, PropertyType<T>>;
template<typename T>
struct BaseObjectClass {
std::string name;
BaseObjectClass<T>* superclass;
ConstructorType<T>* constructor;
MethodMap<T> static_methods = MethodMap<T>();
PropertyMap<T> static_properties = PropertyMap<T>();
MethodMap<T> methods = MethodMap<T>();
PropertyMap<T> properties = PropertyMap<T>();
IndexPropertyType<T> index_accessor = {};
StringPropertyType<T> string_accessor = {};
};
template<typename T, typename U>
struct ObjectClass;
} // js
} // realm

View File

@ -18,20 +18,19 @@
#pragma once
#include "js_collection.hpp"
#include <cassert>
#include "js_class.hpp"
#include "js_object.hpp"
#include "js_results.hpp"
// TODO: #include "js_results.hpp"
#include "js_types.hpp"
#include "js_util.hpp"
#include "shared_realm.hpp"
#include "list.hpp"
#include "object_accessor.hpp"
#include "parser.hpp"
#include "query_builder.hpp"
#include <assert.h>
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
namespace realm {
namespace js {
@ -40,148 +39,203 @@ struct List {
using ContextType = typename T::Context;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
using ReturnType = typename T::Return;
using Object = Object<T>;
using Value = Value<T>;
using ReturnValue = ReturnValue<T>;
static void GetLength(ContextType ctx, ObjectType thisObject, ReturnType &ret);
static void GetIndex(ContextType ctx, ObjectType thisObject, size_t index, ReturnType &ret);
static void SetIndex(ContextType ctx, ObjectType thisObject, size_t index, ValueType value);
static ObjectType create(ContextType, realm::List &);
static void Push(ContextType ctx, ObjectType thisObject, size_t argCount, const ValueType args[], ReturnType &ret);
static void Pop(ContextType ctx, ObjectType thisObject, size_t argCount, const ValueType args[], ReturnType &ret);
static void Unshift(ContextType ctx, ObjectType thisObject, size_t argCount, const ValueType args[], ReturnType &ret);
static void Shift(ContextType ctx, ObjectType thisObject, size_t argCount, const ValueType args[], ReturnType &ret);
static void Splice(ContextType ctx, ObjectType thisObject, size_t argCount, const ValueType args[], ReturnType &ret);
static void StaticResults(ContextType ctx, ObjectType thisObject, size_t argCount, const ValueType args[], ReturnType &ret);
static void Filtered(ContextType ctx, ObjectType thisObject, size_t argCount, const ValueType args[], ReturnType &ret);
static void Sorted(ContextType ctx, ObjectType thisObject, size_t argCount, const ValueType args[], ReturnType &ret);
static void GetLength(ContextType, ObjectType, ReturnValue &);
static void GetIndex(ContextType, ObjectType, uint32_t, ReturnValue &);
static bool SetIndex(ContextType, ObjectType, uint32_t, ValueType);
static void Push(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Pop(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Unshift(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Shift(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Splice(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void StaticResults(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Filtered(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Sorted(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
};
template<typename T>
void List<T>::GetLength(ContextType ctx, ObjectType object, ReturnType &ret) {
realm::List *list = RJSGetInternal<realm::List *>(object);
RJSSetReturnNumber(ctx, ret, list->size());
struct ObjectClass<T, realm::List> : BaseObjectClass<T> {
using List = List<T>;
std::string const name = "List";
MethodMap<T> const methods = {
{"push", wrap<List::Push>},
{"pop", wrap<List::Pop>},
{"unshift", wrap<List::Unshift>},
{"shift", wrap<List::Shift>},
{"splice", wrap<List::Splice>},
{"snapshot", wrap<List::StaticResults>},
{"filtered", wrap<List::Filtered>},
{"sorted", wrap<List::Sorted>},
};
PropertyMap<T> const properties = {
{"length", {wrap<List::GetLength>}},
};
IndexPropertyType<T> const index_accessor = {wrap<List::GetIndex>, wrap<List::SetIndex>};
};
template<typename T>
typename T::Object List<T>::create(ContextType ctx, realm::List &list) {
return create_object<T, realm::List>(ctx, new realm::List(list));
}
template<typename T>
void List<T>::GetIndex(ContextType ctx, ObjectType object, size_t index, ReturnType &ret) {
realm::List *list = RJSGetInternal<realm::List *>(object);
ret = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(index)));
void List<T>::GetLength(ContextType ctx, ObjectType object, ReturnValue &return_value) {
auto list = get_internal<T, realm::List>(object);
return_value.set((uint32_t)list->size());
}
template<typename T>
void List<T>::SetIndex(ContextType ctx, ObjectType object, size_t index, ValueType value) {
realm::List *list = RJSGetInternal<realm::List *>(object);
void List<T>::GetIndex(ContextType ctx, ObjectType object, uint32_t index, ReturnValue &return_value) {
auto list = get_internal<T, realm::List>(object);
auto realm_object = realm::Object(list->get_realm(), list->get_object_schema(), list->get(index));
return_value.set(RealmObject<T>::create(ctx, realm_object));
}
template<typename T>
bool List<T>::SetIndex(ContextType ctx, ObjectType object, uint32_t index, ValueType value) {
auto list = get_internal<T, realm::List>(object);
list->set(ctx, value, index);
return true;
}
template<typename T>
void List<T>::Push(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
realm::List *list = RJSGetInternal<realm::List *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
for (size_t i = 0; i < argumentCount; i++) {
void List<T>::Push(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count_at_least(argc, 1);
auto list = get_internal<T, realm::List>(this_object);
for (size_t i = 0; i < argc; i++) {
list->add(ctx, arguments[i]);
}
RJSSetReturnNumber(ctx, returnObject, list->size());
return_value.set((uint32_t)list->size());
}
template<typename T>
void List<T>::Pop(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
realm::List *list = RJSGetInternal<realm::List *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0);
void List<T>::Pop(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
auto list = get_internal<T, realm::List>(this_object);
size_t size = list->size();
if (size == 0) {
list->verify_in_transaction();
RJSSetReturnUndefined(ctx, returnObject);
return_value.set_undefined();
}
else {
size_t index = size - 1;
returnObject = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(index)));
auto realm_object = realm::Object(list->get_realm(), list->get_object_schema(), list->get(index));
return_value.set(RealmObject<T>::create(ctx, realm_object));
list->remove(index);
}
}
template<typename T>
void List<T>::Unshift(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
realm::List *list = RJSGetInternal<realm::List *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
for (size_t i = 0; i < argumentCount; i++) {
void List<T>::Unshift(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count_at_least(argc, 1);
auto list = get_internal<T, realm::List>(this_object);
for (size_t i = 0; i < argc; i++) {
list->insert(ctx, arguments[i], i);
}
RJSSetReturnNumber(ctx, returnObject, list->size());
return_value.set((uint32_t)list->size());
}
template<typename T>
void List<T>::Shift(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
realm::List *list = RJSGetInternal<realm::List *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0);
void List<T>::Shift(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
auto list = get_internal<T, realm::List>(this_object);
if (list->size() == 0) {
list->verify_in_transaction();
RJSSetReturnUndefined(ctx, returnObject);
return_value.set_undefined();
}
else {
returnObject = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(0)));
auto realm_object = realm::Object(list->get_realm(), list->get_object_schema(), list->get(0));
return_value.set(RealmObject<T>::create(ctx, realm_object));
list->remove(0);
}
}
template<typename T>
void List<T>::Splice(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
realm::List *list = RJSGetInternal<realm::List *>(thisObject);
size_t size = list->size();
void List<T>::Splice(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count_at_least(argc, 1);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
long index = std::min<long>(RJSValidatedValueToNumber(ctx, arguments[0]), size);
auto list = get_internal<T, realm::List>(this_object);
size_t size = list->size();
long index = std::min<long>(Value::validated_to_number(ctx, arguments[0]), size);
if (index < 0) {
index = std::max<long>(size + index, 0);
}
long remove;
if (argumentCount < 2) {
if (argc < 2) {
remove = size - index;
}
else {
remove = std::max<long>(RJSValidatedValueToNumber(ctx, arguments[1]), 0);
remove = std::max<long>(Value::validated_to_number(ctx, arguments[1]), 0);
remove = std::min<long>(remove, size - index);
}
std::vector<ReturnType> removedObjects(remove);
std::vector<ValueType> removed_objects;
removed_objects.reserve(remove);
for (size_t i = 0; i < remove; i++) {
removedObjects[i] = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(index)));
auto realm_object = realm::Object(list->get_realm(), list->get_object_schema(), list->get(index));
removed_objects.push_back(RealmObject<T>::create(ctx, realm_object));
list->remove(index);
}
for (size_t i = 2; i < argumentCount; i++) {
for (size_t i = 2; i < argc; i++) {
list->insert(ctx, arguments[i], index + i - 2);
}
RJSSetReturnArray(ctx, remove, removedObjects.data(), returnObject);
}
template<typename T>
void List<T>::StaticResults(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
realm::List *list = RJSGetInternal<realm::List *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0);
returnObject = RJSResultsCreate(ctx, list->get_realm(), list->get_object_schema(), std::move(list->get_query()), false);
return_value.set(Object::create_array(ctx, removed_objects));
}
template<typename T>
void List<T>::Filtered(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
realm::List *list = RJSGetInternal<realm::List *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
void List<T>::StaticResults(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
returnObject = RJSResultsCreateFiltered(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argumentCount, arguments);
auto list = get_internal<T, realm::List>(this_object);
// TODO: Results
// return_value = RJSResultsCreate(ctx, list->get_realm(), list->get_object_schema(), std::move(list->get_query()), false);
}
template<typename T>
void List<T>::Sorted(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
realm::List *list = RJSGetInternal<realm::List *>(thisObject);
RJSValidateArgumentRange(argumentCount, 1, 2);
void List<T>::Filtered(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count_at_least(argc, 1);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
returnObject = RJSResultsCreateSorted(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argumentCount, arguments);
auto list = get_internal<T, realm::List>(this_object);
auto sharedRealm = *get_internal<T, SharedRealm>(this_object);
// TODO: Results
// return_value = RJSResultsCreateFiltered(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argc, arguments);
}
template<typename T>
void List<T>::Sorted(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1, 2);
auto list = get_internal<T, realm::List>(this_object);
auto sharedRealm = *get_internal<T, SharedRealm>(this_object);
// TODO: Results
// return_value = RJSResultsCreateSorted(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argc, arguments);
}
}
} // js
} // realm

View File

@ -1,295 +0,0 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#include "js_util.hpp"
#include "js_object.hpp"
#include "js_results.hpp"
#include "js_schema.hpp"
#include "jsc_list.hpp"
#include "js_realm.hpp"
#include "object_store.hpp"
#include "object_accessor.hpp"
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
using namespace realm;
JSValueRef ObjectGetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef* exception) {
try {
Object *obj = RJSGetInternal<Object *>(jsObject);
return obj->get_property_value<JSValueRef>(ctx, RJSStringForJSString(jsPropertyName));
} catch (InvalidPropertyException &ex) {
// getters for nonexistent properties in JS should always return undefined
} catch (std::exception &ex) {
if (exception) {
*exception = RJSMakeError(ctx, ex);
}
}
return NULL;
}
bool ObjectSetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef value, JSValueRef* exception) {
try {
Object *obj = RJSGetInternal<Object *>(jsObject);
obj->set_property_value(ctx, RJSStringForJSString(jsPropertyName), value, true);
} catch (std::exception &ex) {
if (exception) {
*exception = RJSMakeError(ctx, ex);
}
return false;
}
return true;
}
void ObjectPropertyNames(JSContextRef ctx, JSObjectRef jsObject, JSPropertyNameAccumulatorRef propertyNames) {
Object *obj = RJSGetInternal<Object *>(jsObject);
for (auto &prop : obj->get_object_schema().properties) {
JSStringRef propertyName = RJSStringForString(prop.name);
JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
JSStringRelease(propertyName);
}
}
JSClassRef RJSObjectClass() {
static JSClassRef s_objectClass = RJSCreateWrapperClass<Object *>("RealmObject", ObjectGetProperty, ObjectSetProperty, NULL, ObjectPropertyNames);
return s_objectClass;
}
namespace realm {
namespace js {
JSClassRef object_class() { return RJSObjectClass(); };
}
}
JSObjectRef RJSObjectCreate(JSContextRef ctx, Object object) {
static JSStringRef prototypeString = JSStringCreateWithUTF8CString("prototype");
auto delegate = realm::js::get_delegate<jsc::Types>(object.realm().get());
JSObjectRef constructor = delegate->m_constructors[object.get_object_schema().name];
JSObjectRef prototype = constructor ? RJSValidatedObjectProperty(ctx, constructor, prototypeString) : NULL;
JSObjectRef jsObject = realm::js::WrapObject(ctx, RJSObjectClass(), new Object(object), prototype);
if (constructor) {
JSValueRef exception = NULL;
JSValueRef result = JSObjectCallAsFunction(ctx, constructor, jsObject, 0, NULL, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
else if (result != jsObject && !JSValueIsNull(ctx, result) && !JSValueIsUndefined(ctx, result)) {
throw std::runtime_error("Realm object constructor must not return another value");
}
}
return jsObject;
}
namespace realm {
template<> bool RJSAccessor::dict_has_value_for_key(JSContextRef ctx, JSValueRef dict, const std::string &prop_name) {
JSObjectRef object = RJSValidatedValueToObject(ctx, dict);
JSStringRef propStr = RJSStringForString(prop_name);
bool ret = JSObjectHasProperty(ctx, object, propStr);
JSStringRelease(propStr);
return ret;
}
template<> JSValueRef RJSAccessor::dict_value_for_key(JSContextRef ctx, JSValueRef dict, const std::string &prop_name) {
JSObjectRef object = RJSValidatedValueToObject(ctx, dict);
JSStringRef propStr = RJSStringForString(prop_name);
JSValueRef ex = NULL;
JSValueRef ret = JSObjectGetProperty(ctx, object, propStr, &ex);
if (ex) {
throw RJSException(ctx, ex);
}
JSStringRelease(propStr);
return ret;
}
template<> bool RJSAccessor::has_default_value_for_property(JSContextRef ctx, Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name) {
auto defaults = realm::js::get_delegate<jsc::Types>(realm)->m_defaults[object_schema.name];
return defaults.find(prop_name) != defaults.end();
}
template<> JSValueRef RJSAccessor::default_value_for_property(JSContextRef ctx, Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name) {
auto defaults = realm::js::get_delegate<jsc::Types>(realm)->m_defaults[object_schema.name];
return defaults[prop_name];
}
template<> bool RJSAccessor::is_null(JSContextRef ctx, JSValueRef &val) {
return JSValueIsNull(ctx, val) || JSValueIsUndefined(ctx, val);
}
template<> JSValueRef RJSAccessor::null_value(JSContextRef ctx) {
return JSValueMakeNull(ctx);
}
template<> bool RJSAccessor::to_bool(JSContextRef ctx, JSValueRef &val) {
if (!JSValueIsBoolean(ctx, val)) {
throw std::runtime_error("Property expected to be of type boolean");
}
return JSValueToBoolean(ctx, val);
}
template<> JSValueRef RJSAccessor::from_bool(JSContextRef ctx, bool b) {
return JSValueMakeBoolean(ctx, b);
}
template<> long long RJSAccessor::to_long(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedValueToNumber(ctx, val);
}
template<> JSValueRef RJSAccessor::from_long(JSContextRef ctx, long long l) {
return JSValueMakeNumber(ctx, l);
}
template<> float RJSAccessor::to_float(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedValueToNumber(ctx, val);
}
template<> JSValueRef RJSAccessor::from_float(JSContextRef ctx, float f) {
return JSValueMakeNumber(ctx, f);
}
template<> double RJSAccessor::to_double(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedValueToNumber(ctx, val);
}
template<> JSValueRef RJSAccessor::from_double(JSContextRef ctx, double d) {
return JSValueMakeNumber(ctx, d);
}
template<> std::string RJSAccessor::to_string(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedStringForValue(ctx, val);
}
template<> JSValueRef RJSAccessor::from_string(JSContextRef ctx, StringData s) {
return RJSValueForString(ctx, s);
}
template<> std::string RJSAccessor::to_binary(JSContextRef ctx, JSValueRef &val) {
static JSStringRef arrayBufferString = JSStringCreateWithUTF8CString("ArrayBuffer");
static JSStringRef bufferString = JSStringCreateWithUTF8CString("buffer");
static JSStringRef byteLengthString = JSStringCreateWithUTF8CString("byteLength");
static JSStringRef byteOffsetString = JSStringCreateWithUTF8CString("byteOffset");
static JSStringRef isViewString = JSStringCreateWithUTF8CString("isView");
static JSStringRef uint8ArrayString = JSStringCreateWithUTF8CString("Uint8Array");
JSObjectRef arrayBufferConstructor = RJSValidatedObjectProperty(ctx, JSContextGetGlobalObject(ctx), arrayBufferString);
JSObjectRef uint8ArrayContructor = RJSValidatedObjectProperty(ctx, JSContextGetGlobalObject(ctx), uint8ArrayString);
JSValueRef uint8ArrayArguments[3];
size_t uint8ArrayArgumentsCount = 0;
// Value should either be an ArrayBuffer or ArrayBufferView (i.e. TypedArray or DataView).
if (JSValueIsInstanceOfConstructor(ctx, val, arrayBufferConstructor, NULL)) {
uint8ArrayArguments[0] = val;
uint8ArrayArgumentsCount = 1;
}
else if (JSObjectRef object = JSValueToObject(ctx, val, NULL)) {
// Check if value is an ArrayBufferView by calling ArrayBuffer.isView(val).
JSObjectRef isViewMethod = RJSValidatedObjectProperty(ctx, arrayBufferConstructor, isViewString);
JSValueRef isView = JSObjectCallAsFunction(ctx, isViewMethod, arrayBufferConstructor, 1, &val, NULL);
if (isView && JSValueToBoolean(ctx, isView)) {
uint8ArrayArguments[0] = RJSValidatedObjectProperty(ctx, object, bufferString);
uint8ArrayArguments[1] = RJSValidatedPropertyValue(ctx, object, byteOffsetString);
uint8ArrayArguments[2] = RJSValidatedPropertyValue(ctx, object, byteLengthString);
uint8ArrayArgumentsCount = 3;
}
}
if (!uint8ArrayArgumentsCount) {
throw std::runtime_error("Can only convert ArrayBuffer and TypedArray objects to binary");
}
JSValueRef exception = NULL;
JSObjectRef uint8Array = JSObjectCallAsConstructor(ctx, uint8ArrayContructor, uint8ArrayArgumentsCount, uint8ArrayArguments, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
size_t byteCount = RJSValidatedListLength(ctx, uint8Array);
std::string bytes(byteCount, 0);
for (size_t i = 0; i < byteCount; i++) {
JSValueRef byteValue = JSObjectGetPropertyAtIndex(ctx, uint8Array, (unsigned)i, NULL);
bytes[i] = JSValueToNumber(ctx, byteValue, NULL);
}
return bytes;
}
template<> JSValueRef RJSAccessor::from_binary(JSContextRef ctx, BinaryData data) {
static JSStringRef bufferString = JSStringCreateWithUTF8CString("buffer");
static JSStringRef uint8ArrayString = JSStringCreateWithUTF8CString("Uint8Array");
size_t byteCount = data.size();
JSValueRef byteCountValue = JSValueMakeNumber(ctx, byteCount);
JSObjectRef uint8ArrayContructor = RJSValidatedObjectProperty(ctx, JSContextGetGlobalObject(ctx), uint8ArrayString);
JSObjectRef uint8Array = JSObjectCallAsConstructor(ctx, uint8ArrayContructor, 1, &byteCountValue, NULL);
for (size_t i = 0; i < byteCount; i++) {
JSValueRef num = JSValueMakeNumber(ctx, data[i]);
JSObjectSetPropertyAtIndex(ctx, uint8Array, (unsigned)i, num, NULL);
}
return RJSValidatedObjectProperty(ctx, uint8Array, bufferString);
}
template<> DateTime RJSAccessor::to_datetime(JSContextRef ctx, JSValueRef &val) {
JSObjectRef object = RJSValidatedValueToDate(ctx, val);
double utc = RJSValidatedValueToNumber(ctx, object);
return DateTime(utc);
}
template<> JSValueRef RJSAccessor::from_datetime(JSContextRef ctx, DateTime dt) {
JSValueRef time = JSValueMakeNumber(ctx, dt.get_datetime());
return JSObjectMakeDate(ctx, 1, &time, NULL);
}
template<> size_t RJSAccessor::to_existing_object_index(JSContextRef ctx, JSValueRef &val) {
JSObjectRef object = RJSValidatedValueToObject(ctx, val);
if (JSValueIsObjectOfClass(ctx, val, RJSObjectClass())) {
return RJSGetInternal<Object *>(object)->row().get_index();
}
throw std::runtime_error("object is not a Realm Object");
}
template<> size_t RJSAccessor::to_object_index(JSContextRef ctx, SharedRealm realm, JSValueRef &val, const std::string &type, bool try_update) {
JSObjectRef object = RJSValidatedValueToObject(ctx, val);
if (JSValueIsObjectOfClass(ctx, val, RJSObjectClass())) {
return RJSGetInternal<Object *>(object)->row().get_index();
}
auto object_schema = realm->config().schema->find(type);
if (RJSIsValueArray(ctx, object)) {
object = RJSDictForPropertyArray(ctx, *object_schema, object);
}
Object child = Object::create<JSValueRef>(ctx, realm, *object_schema, (JSValueRef)object, try_update);
return child.row().get_index();
}
template<> JSValueRef RJSAccessor::from_object(JSContextRef ctx, Object object) {
return RJSObjectCreate(ctx, object);
}
template<> size_t RJSAccessor::list_size(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedListLength(ctx, RJSValidatedValueToObject(ctx, val));
}
template<> JSValueRef RJSAccessor::list_value_at_index(JSContextRef ctx, JSValueRef &val, size_t index) {
return RJSValidatedObjectAtIndex(ctx, RJSValidatedValueToObject(ctx, val), (unsigned int)index);
}
template<> JSValueRef RJSAccessor::from_list(JSContextRef ctx, List list) {
return RJSListCreate(ctx, list);
}
}

View File

@ -18,11 +18,103 @@
#pragma once
#include "js_class.hpp"
#include "js_types.hpp"
#include "js_util.hpp"
#include "object_accessor.hpp"
#include "object_store.hpp"
namespace realm {
class Object;
namespace js {
template<typename T>
struct RealmObject {
using ContextType = typename T::Context;
using FunctionType = typename T::Function;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
using String = String<T>;
using Value = Value<T>;
using Object = Object<T>;
using Function = Function<T>;
using ReturnValue = ReturnValue<T>;
static ObjectType create(ContextType, realm::Object &);
static void GetProperty(ContextType, ObjectType, const String &, ReturnValue &);
static bool SetProperty(ContextType, ObjectType, const String &, ValueType, ReturnValue &);
static std::vector<String> GetPropertyNames(ContextType, ObjectType);
};
template<typename T>
struct ObjectClass<T, realm::Object> : BaseObjectClass<T> {
using RealmObject = RealmObject<T>;
const std::string name = "RealmObject";
const StringPropertyType<T> string_accessor = {
wrap<RealmObject::GetProperty>,
wrap<RealmObject::SetProperty>,
wrap<RealmObject::GetPropertyNames>,
};
};
template<typename T>
typename T::Object RealmObject<T>::create(ContextType ctx, realm::Object &realm_object) {
static String s_prototype = "prototype";
auto delegate = get_delegate<T>(realm_object.realm().get());
auto name = realm_object.get_object_schema().name;
auto object = create_object<T, realm::Object>(ctx, new realm::Object(realm_object));
if (!delegate->m_constructors.count(name)) {
return object;
}
FunctionType constructor = delegate->m_constructors.at(name);
ObjectType prototype = Object::validated_get_object(ctx, constructor, s_prototype);
Object::set_prototype(ctx, object, prototype);
ValueType result = Function::call(ctx, constructor, object, 0, NULL);
if (result != object && !Value::is_null(ctx, result) && !Value::is_undefined(ctx, result)) {
throw std::runtime_error("Realm object constructor must not return another value");
}
return object;
}
JSClassRef RJSObjectClass();
JSObjectRef RJSObjectCreate(JSContextRef ctx, realm::Object object);
template<typename T>
void RealmObject<T>::GetProperty(ContextType ctx, ObjectType object, const String &property, ReturnValue &return_value) {
try {
auto realm_object = get_internal<realm::Object>(object);
auto result = realm_object->template get_property_value<ValueType>(ctx, property);
return_value.set(result);
} catch (InvalidPropertyException &ex) {
// getters for nonexistent properties in JS should always return undefined
}
}
template<typename T>
bool RealmObject<T>::SetProperty(ContextType ctx, ObjectType object, const String &property, ValueType value, ReturnValue &return_value) {
auto realm_object = get_internal<realm::Object>(object);
realm_object->set_property_value(ctx, property, value, true);
return true;
}
template<typename T>
std::vector<String<T>> RealmObject<T>::GetPropertyNames(ContextType ctx, ObjectType object) {
auto realm_object = get_internal<realm::Object>(object);
auto &properties = realm_object->get_object_schema().properties;
std::vector<String> names(properties.size());
size_t index = 0;
for (auto &prop : properties) {
names[index++] = prop.name;
}
return names;
}
} // js
} // realm

145
src/js_object_accessor.hpp Normal file
View File

@ -0,0 +1,145 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "js_list.hpp"
#include "js_object.hpp"
#include "js_schema.hpp"
namespace realm {
namespace js {
template<typename T>
class NativeAccessor {
using ContextType = typename T::Context;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
using Object = Object<T>;
using Value = Value<T>;
public:
static bool dict_has_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name) {
ObjectType object = Value::validated_to_object(ctx, dict);
return Object::has_property(ctx, object, prop_name);
}
static ValueType dict_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name) {
ObjectType object = Value::validated_to_object(ctx, dict);
return Object::get_property(ctx, object, prop_name);
}
static bool has_default_value_for_property(ContextType ctx, realm::Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name) {
auto defaults = get_delegate<T>(realm)->m_defaults[object_schema.name];
return defaults.count(prop_name) != 0;
}
static ValueType default_value_for_property(ContextType ctx, realm::Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name) {
auto defaults = get_delegate<T>(realm)->m_defaults[object_schema.name];
return defaults.at(prop_name);
}
// These must be implemented for each JS engine.
static std::string to_binary(ContextType, ValueType &);
static ValueType from_binary(ContextType, BinaryData);
static bool to_bool(ContextType ctx, ValueType &value) {
return Value::validated_to_boolean(ctx, value, "Property");
}
static ValueType from_bool(ContextType ctx, bool boolean) {
return Value::from_boolean(ctx, boolean);
}
static long long to_long(ContextType ctx, ValueType &value) {
return Value::validated_to_number(ctx, value, "Property");
}
static ValueType from_long(ContextType ctx, long long number) {
return Value::from_number(ctx, number);
}
static float to_float(ContextType ctx, ValueType &value) {
return Value::validated_to_number(ctx, value, "Property");
}
static ValueType from_float(ContextType ctx, float number) {
return Value::from_number(ctx, number);
}
static double to_double(ContextType ctx, ValueType &value) {
return Value::validated_to_number(ctx, value, "Property");
}
static ValueType from_double(ContextType ctx, double number) {
return Value::from_number(ctx, number);
}
static std::string to_string(ContextType ctx, ValueType &value) {
return Value::validated_to_string(ctx, value, "Property");
}
static ValueType from_string(ContextType ctx, StringData string) {
return Value::from_string(ctx, string);
}
static DateTime to_datetime(ContextType ctx, ValueType &value) {
ObjectType date = Value::validated_to_date(ctx, value, "Property");
return DateTime(Value::to_number(ctx, date));
}
static ValueType from_datetime(ContextType ctx, DateTime dt) {
return Object::create_date(ctx, dt.get_datetime());
}
static bool is_null(ContextType ctx, ValueType &value) {
return Value::is_null(ctx, value) || Value::is_undefined(ctx, value);
}
static ValueType null_value(ContextType ctx) {
return Value::from_null(ctx);
}
static size_t to_object_index(ContextType ctx, SharedRealm realm, ValueType &value, const std::string &type, bool try_update) {
ObjectType object = Value::validated_to_object(ctx, value);
if (Object::template is_instance<realm::Object>(ctx, object)) {
return get_internal<T, realm::Object>(object)->row().get_index();
}
auto object_schema = realm->config().schema->find(type);
if (Value::is_array(ctx, object)) {
object = Schema<T>::dict_for_property_array(ctx, *object_schema, object);
}
auto child = realm::Object::create<ValueType>(ctx, realm, *object_schema, static_cast<ValueType>(object), try_update);
return child.row().get_index();
}
static size_t to_existing_object_index(ContextType ctx, ValueType &value) {
ObjectType object = Value::validated_to_object(ctx, value);
if (Object::template is_instance<realm::Object>(ctx, object)) {
return get_internal<T, realm::Object>(object)->row().get_index();
}
throw std::runtime_error("object is not a Realm Object");
}
static ValueType from_object(ContextType ctx, realm::Object realm_object) {
return RealmObject<T>::create(ctx, realm_object);
}
static size_t list_size(ContextType ctx, ValueType &value) {
return Object::validated_get_length(ctx, Value::validated_to_object(ctx, value));
}
static ValueType list_value_at_index(ContextType ctx, ValueType &value, size_t index) {
return Object::validated_get_object(ctx, Value::validated_to_object(ctx, value), (uint32_t)index);
}
static ValueType from_list(ContextType ctx, realm::List list) {
return List<T>::create(ctx, list);
}
static Mixed to_mixed(ContextType ctx, ValueType &val) {
throw std::runtime_error("'Any' type is unsupported");
}
};
} // js
} // realm

View File

@ -16,7 +16,6 @@
//
////////////////////////////////////////////////////////////////////////////
#include "js_realm.hpp"
#include "platform.hpp"
namespace realm {
@ -34,4 +33,5 @@ void set_default_path(std::string path) {
s_defaultPath = path;
}
}}
} // js
} // realm

View File

@ -18,7 +18,13 @@
#pragma once
#include <map>
#include <set>
#include "js_class.hpp"
#include "js_types.hpp"
#include "js_util.hpp"
#include "js_object.hpp"
#include "js_schema.hpp"
#include "shared_realm.hpp"
@ -27,9 +33,6 @@
#include "results.hpp"
#include "platform.hpp"
#include <map>
#include <set>
namespace realm {
namespace js {
@ -37,10 +40,13 @@ template<typename T>
class RealmDelegate : public BindingContext {
public:
using GlobalContextType = typename T::GlobalContext;
using ObjectClassType = typename T::ObjectClass;
using FunctionType = typename T::Function;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
using ObjectDefaults = std::map<std::string, ValueType>;
using Value = Value<T>;
using ObjectDefaultsMap = typename Schema<T>::ObjectDefaultsMap;
using ConstructorMap = typename Schema<T>::ConstructorMap;
virtual void did_change(std::vector<ObserverState> const& observers, std::vector<void*> const& invalidated) {
notify("change");
@ -50,75 +56,47 @@ class RealmDelegate : public BindingContext {
}
virtual void will_change(std::vector<ObserverState> const& observers, std::vector<void*> const& invalidated) {}
RealmDelegate(std::weak_ptr<Realm> realm, GlobalContextType ctx) : m_context(ctx), m_realm(realm) {
GlobalContextProtect(m_context);
}
RealmDelegate(std::weak_ptr<Realm> realm, GlobalContextType ctx) : m_context(ctx), m_realm(realm) {}
~RealmDelegate() {
remove_all_notifications();
for (auto constructor : m_constructors) {
ValueUnprotect(m_context, constructor.second);
}
for (auto objectDefaults : m_defaults) {
for (auto value : objectDefaults.second) {
ValueUnprotect(m_context, value.second);
}
}
GlobalContextUnprotect(m_context);
}
void add_notification(JSObjectRef notification) {
if (!m_notifications.count(notification)) {
ValueProtect(m_context, notification);
m_notifications.insert(notification);
}
}
void remove_notification(JSObjectRef notification) {
if (m_notifications.count(notification)) {
ValueUnprotect(m_context, notification);
m_notifications.erase(notification);
void add_notification(FunctionType notification) {
m_notifications.insert(Protected<FunctionType>(m_context, notification));
}
void remove_notification(FunctionType notification) {
m_notifications.erase(Protected<FunctionType>(m_context, notification));
}
void remove_all_notifications() {
for (auto notification : m_notifications) {
ValueUnprotect(m_context, notification);
}
m_notifications.clear();
}
std::map<std::string, ObjectDefaults> m_defaults;
std::map<std::string, ObjectType> m_constructors;
ObjectDefaultsMap m_defaults;
ConstructorMap m_constructors;
private:
std::set<ObjectType> m_notifications;
GlobalContextType m_context;
private:
Protected<GlobalContextType> m_context;
std::set<Protected<FunctionType>> m_notifications;
std::weak_ptr<Realm> m_realm;
void notify(const char *notification_name) {
JSValueRef arguments[2];
SharedRealm realm = m_realm.lock();
if (!realm) {
throw std::runtime_error("Realm no longer exists");
}
ObjectType realm_object = WrapObject<SharedRealm *>(m_context, realm::js::realm_class(), new SharedRealm(realm));
ObjectType realm_object = create_object<T, SharedRealm>(m_context, new SharedRealm(realm));
ValueType arguments[2];
arguments[0] = realm_object;
arguments[1] = RJSValueForString(m_context, notification_name);
arguments[1] = Value::from_string(m_context, notification_name);
for (auto callback : m_notifications) {
JSValueRef ex = NULL;
ObjectCallAsFunction(m_context, callback, realm_object, 2, arguments, ex);
if (ex) {
throw RJSException(m_context, ex);
}
Function<T>::call(m_context, callback, realm_object, 2, arguments);
}
}
};
template<typename T>
RealmDelegate<T> *get_delegate(Realm *realm) {
return dynamic_cast<realm::js::RealmDelegate<T> *>(realm->m_binding_context.get());
}
std::string default_path();
void set_default_path(std::string path);
@ -126,36 +104,40 @@ template<typename T>
class Realm : public BindingContext {
public:
using ContextType = typename T::Context;
using FunctionType = typename T::Function;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
using ReturnType = typename T::Return;
using ExceptionType = typename T::Exception;
using String = String<T>;
using Object = Object<T>;
using Value = Value<T>;
using ReturnValue = ReturnValue<T>;
using NativeAccessor = realm::NativeAccessor<ValueType, ContextType>;
// member methods
static void Objects(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void Create(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void Delete(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void DeleteAll(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void Write(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void AddListener(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void RemoveListener(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void RemoveAllListeners(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void Close(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void Objects(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Create(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Delete(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void DeleteAll(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Write(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void AddListener(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void RemoveListener(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void RemoveAllListeners(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void Close(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
// properties
static void GetPath(ContextType ctx, ObjectType object, ReturnType &returnObject);
static void GetSchemaVersion(ContextType ctx, ObjectType object, ReturnType &returnObject);
static void GetPath(ContextType, ObjectType, ReturnValue &);
static void GetSchemaVersion(ContextType, ObjectType, ReturnValue &);
// constructor methods
static void Constructor(ContextType ctx, ObjectType constructor, size_t argumentCount, const ValueType arguments[], ObjectType &returnObject);
static void SchemaVersion(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject);
static void Constructor(ContextType, ObjectType, size_t, const ValueType[]);
static void SchemaVersion(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &);
// static properties
static void GetDefaultPath(ContextType ctx, ObjectType object, ReturnType &returnObject);
static void SetDefaultPath(ContextType ctx, ObjectType object, ValueType value);
static void GetDefaultPath(ContextType, ObjectType, ReturnValue &);
static void SetDefaultPath(ContextType, ObjectType, ValueType value);
static std::string validated_notification_name(JSContextRef ctx, JSValueRef value) {
std::string name = RJSValidatedStringForValue(ctx, value);
static std::string validated_notification_name(ContextType ctx, const ValueType &value) {
std::string name = Value::validated_to_string(ctx, value, "notification name");
if (name != "change") {
throw std::runtime_error("Only the 'change' notification name is supported.");
}
@ -163,9 +145,9 @@ public:
}
// converts constructor object or type name to type name
static std::string validated_object_type_for_value(SharedRealm &realm, JSContextRef ctx, JSValueRef value) {
if (ValueIsObject(ctx, value) && ValueIsConstructor(ctx, value)) {
ObjectType constructor = ValueToObject(ctx, value);
static std::string validated_object_type_for_value(SharedRealm &realm, ContextType ctx, const ValueType &value) {
if (Value::is_constructor(ctx, value)) {
FunctionType constructor = Value::to_constructor(ctx, value);
auto delegate = get_delegate<T>(realm.get());
for (auto pair : delegate->m_constructors) {
@ -175,10 +157,10 @@ public:
}
throw std::runtime_error("Constructor was not registered in the schema for this Realm");
}
return RJSValidatedStringForValue(ctx, value, "objectType");
return Value::validated_to_string(ctx, value, "objectType");
}
static std::string RJSNormalizePath(std::string path) {
static std::string normalize_path(std::string path) {
if (path.size() && path[0] != '/') {
return default_realm_file_directory() + "/" + path;
}
@ -186,55 +168,80 @@ public:
}
};
template<typename T>
struct ObjectClass<T, SharedRealm> : BaseObjectClass<T> {
using Realm = Realm<T>;
std::string const name = "Realm";
ConstructorType<T>* const constructor = Realm::Constructor;
MethodMap<T> const methods = {
{"objects", wrap<Realm::Objects>},
{"create", wrap<Realm::Create>},
{"delete", wrap<Realm::Delete>},
{"deleteAll", wrap<Realm::DeleteAll>},
{"write", wrap<Realm::Write>},
{"addListener", wrap<Realm::AddListener>},
{"removeListener", wrap<Realm::RemoveListener>},
{"removeAllListeners", wrap<Realm::RemoveAllListeners>},
{"close", wrap<Realm::Close>},
};
PropertyMap<T> const properties = {
{"path", {wrap<Realm::GetPath>}},
{"schemaVersion", {wrap<Realm::GetSchemaVersion>}},
};
};
template<typename T>
void Realm<T>::Constructor(ContextType ctx, ObjectType constructor, size_t argumentCount, const ValueType arguments[], ObjectType &returnObject) {
using RJSAccessor = realm::NativeAccessor<ValueType, ContextType>;
using StringType = typename T::String;
void Realm<T>::Constructor(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[]) {
static const String path_string = "path";
static const String schema_string = "schema";
static const String schema_version_string = "schemaVersion";
static const String encryption_key_string = "encryptionKey";
realm::Realm::Config config;
typename Schema<T>::ObjectDefaultsMap defaults;
typename Schema<T>::ConstructorMap constructors;
if (argumentCount == 0) {
if (argc == 0) {
config.path = default_path();
}
else if (argumentCount == 1) {
else if (argc == 1) {
ValueType value = arguments[0];
if (ValueIsString(ctx, value)) {
config.path = RJSValidatedStringForValue(ctx, value, "path");
if (Value::is_string(ctx, value)) {
config.path = Value::validated_to_string(ctx, value, "path");
}
else if (ValueIsObject(ctx, value)) {
ObjectType object = RJSValidatedValueToObject(ctx, value);
else if (Value::is_object(ctx, value)) {
ObjectType object = Value::validated_to_object(ctx, value);
StringType pathString("path");
ValueType pathValue = RJSValidatedPropertyValue(ctx, object, pathString);
if (!JSValueIsUndefined(ctx, pathValue)) {
config.path = RJSValidatedStringForValue(ctx, pathValue, "path");
ValueType pathValue = Object::get_property(ctx, object, path_string);
if (!Value::is_undefined(ctx, pathValue)) {
config.path = Value::validated_to_string(ctx, pathValue, "path");
}
else {
config.path = js::default_path();
}
StringType schemaString("schema");
ValueType schemaValue = RJSValidatedPropertyValue(ctx, object, schemaString);
if (!ValueIsUndefined(ctx, schemaValue)) {
config.schema.reset(new realm::Schema(Schema<T>::parse_schema(ctx, RJSValidatedValueToObject(ctx, schemaValue), defaults, constructors)));
ValueType schemaValue = Object::get_property(ctx, object, schema_string);
if (!Value::is_undefined(ctx, schemaValue)) {
ObjectType schemaObject = Value::validated_to_object(ctx, schemaValue, "schema");
config.schema.reset(new realm::Schema(Schema<T>::parse_schema(ctx, schemaObject, defaults, constructors)));
}
StringType schemaVersionString("schemaVersion");
ValueType versionValue = RJSValidatedPropertyValue(ctx, object, schemaVersionString);
if (JSValueIsNumber(ctx, versionValue)) {
config.schema_version = RJSValidatedValueToNumber(ctx, versionValue);
ValueType versionValue = Object::get_property(ctx, object, schema_version_string);
if (!Value::is_undefined(ctx, versionValue)) {
config.schema_version = Value::validated_to_number(ctx, versionValue, "schemaVersion");
}
else {
config.schema_version = 0;
}
StringType encryptionKeyString("encryptionKey");
ValueType encryptionKeyValue = RJSValidatedPropertyValue(ctx, object, encryptionKeyString);
if (!JSValueIsUndefined(ctx, encryptionKeyValue)) {
std::string encryptionKey = RJSAccessor::to_binary(ctx, encryptionKeyValue);
config.encryption_key = std::vector<char>(encryptionKey.begin(), encryptionKey.end());;
ValueType encryptionKeyValue = Object::get_property(ctx, object, encryption_key_string);
if (!Value::is_undefined(ctx, encryptionKeyValue)) {
std::string encryptionKey = NativeAccessor::to_binary(ctx, encryptionKeyValue);
config.encryption_key = std::vector<char>(encryptionKey.begin(), encryptionKey.end());
}
}
}
@ -242,76 +249,81 @@ void Realm<T>::Constructor(ContextType ctx, ObjectType constructor, size_t argum
throw std::runtime_error("Invalid arguments when constructing 'Realm'");
}
config.path = RJSNormalizePath(config.path);
config.path = normalize_path(config.path);
ensure_directory_exists_for_file(config.path);
SharedRealm realm = realm::Realm::get_shared_realm(config);
auto delegate = new RealmDelegate<T>(realm, JSContextGetGlobalContext(ctx));
auto delegate = new RealmDelegate<T>(realm, Context<T>::get_global_context(ctx));
if (!realm->m_binding_context) {
realm->m_binding_context.reset(delegate);
}
delegate->m_defaults = defaults;
delegate->m_constructors = constructors;
returnObject = WrapObject(ctx, realm_class(), new SharedRealm(realm));
set_internal<T, SharedRealm>(this_object, new SharedRealm(realm));
}
template<typename T>
void Realm<T>::SchemaVersion(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
using RJSAccessor = realm::NativeAccessor<ValueType, ContextType>;
RJSValidateArgumentRange(argumentCount, 1, 2);
void Realm<T>::SchemaVersion(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1, 2);
realm::Realm::Config config;
config.path = RJSNormalizePath(RJSValidatedStringForValue(ctx, arguments[0]));
if (argumentCount == 2) {
config.path = normalize_path(Value::validated_to_string(ctx, arguments[0]));
if (argc == 2) {
auto encryptionKeyValue = arguments[1];
std::string encryptionKey = RJSAccessor::to_binary(ctx, encryptionKeyValue);
std::string encryptionKey = NativeAccessor::to_binary(ctx, encryptionKeyValue);
config.encryption_key = std::vector<char>(encryptionKey.begin(), encryptionKey.end());
}
auto version = realm::Realm::get_schema_version(config);
if (version == ObjectStore::NotVersioned) {
RJSSetReturnNumber(ctx, returnObject, -1);
return_value.set(-1);
}
else {
RJSSetReturnNumber(ctx, returnObject, version);
return_value.set(version);
}
}
template<typename T>
void Realm<T>::GetDefaultPath(ContextType ctx, ObjectType object, ReturnType &returnObject) {
returnObject = RJSValueForString(ctx, realm::js::default_path());
void Realm<T>::GetDefaultPath(ContextType ctx, ObjectType object, ReturnValue &return_value) {
return_value.set(realm::js::default_path());
}
template<typename T>
void Realm<T>::SetDefaultPath(ContextType ctx, ObjectType object, ValueType value) {
js::set_default_path(RJSValidatedStringForValue(ctx, value, "defaultPath"));
js::set_default_path(Value::validated_to_string(ctx, value, "defaultPath"));
}
template<typename T>
void Realm<T>::GetPath(ContextType ctx, ObjectType object, ReturnType &returnObject) {
returnObject = RJSValueForString(ctx, RJSGetInternal<SharedRealm *>(object)->get()->config().path);
void Realm<T>::GetPath(ContextType ctx, ObjectType object, ReturnValue &return_value) {
std::string path = get_internal<T, SharedRealm>(object)->get()->config().path;
return_value.set(path);
}
template<typename T>
void Realm<T>::GetSchemaVersion(ContextType ctx, ObjectType object, ReturnType &returnObject) {
returnObject = JSValueMakeNumber(ctx, RJSGetInternal<SharedRealm *>(object)->get()->config().schema_version);
void Realm<T>::GetSchemaVersion(ContextType ctx, ObjectType object, ReturnValue &return_value) {
double version = get_internal<T, SharedRealm>(object)->get()->config().schema_version;
return_value.set(version);
}
template<typename T>
void Realm<T>::Objects(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
RJSValidateArgumentCount(argumentCount, 1);
void Realm<T>::Objects(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
SharedRealm sharedRealm = *get_internal<T, SharedRealm>(this_object);
std::string className = validated_object_type_for_value(sharedRealm, ctx, arguments[0]);
returnObject = RJSResultsCreate(ctx, sharedRealm, className);
// TODO
// return_value = RJSResultsCreate(ctx, sharedRealm, className);
}
template<typename T>
void Realm<T>::Create(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
RJSValidateArgumentRange(argumentCount, 2, 3);
void Realm<T>::Create(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 2, 3);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
SharedRealm sharedRealm = *get_internal<T, SharedRealm>(this_object);
std::string className = validated_object_type_for_value(sharedRealm, ctx, arguments[0]);
auto &schema = sharedRealm->config().schema;
auto object_schema = schema->find(className);
@ -320,53 +332,57 @@ void Realm<T>::Create(ContextType ctx, ObjectType thisObject, size_t argumentCou
throw std::runtime_error("Object type '" + className + "' not found in schema.");
}
auto object = RJSValidatedValueToObject(ctx, arguments[1]);
if (RJSIsValueArray(ctx, arguments[1])) {
object = RJSDictForPropertyArray(ctx, *object_schema, object);
ObjectType object = Value::validated_to_object(ctx, arguments[1], "properties");
if (Value::is_array(ctx, arguments[1])) {
object = Schema<T>::dict_for_property_array(ctx, *object_schema, object);
}
bool update = false;
if (argumentCount == 3) {
update = RJSValidatedValueToBoolean(ctx, arguments[2]);
if (argc == 3) {
update = Value::validated_to_boolean(ctx, arguments[2], "update");
}
returnObject = RJSObjectCreate(ctx, Object::create<ValueType>(ctx, sharedRealm, *object_schema, object, update));
auto realm_object = realm::Object::create<ValueType>(ctx, sharedRealm, *object_schema, object, update);
return_value.set(RealmObject<T>::create(ctx, realm_object));
}
template<typename T>
void Realm<T>::Delete(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
RJSValidateArgumentCount(argumentCount, 1);
void Realm<T>::Delete(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
SharedRealm realm = *get_internal<T, SharedRealm>(this_object);
if (!realm->is_in_transaction()) {
throw std::runtime_error("Can only delete objects within a transaction.");
}
auto arg = RJSValidatedValueToObject(ctx, arguments[0]);
if (RJSValueIsObjectOfClass(ctx, arg, realm::js::object_class())) {
Object *object = RJSGetInternal<Object *>(arg);
ObjectType arg = Value::validated_to_object(ctx, arguments[0]);
// TODO: fix this template call
if (Object::template is_instance<realm::Object>(ctx, arg)) {
auto object = get_internal<T, realm::Object>(arg);
realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object->get_object_schema().name);
table->move_last_over(object->row().get_index());
}
else if (RJSIsValueArray(ctx, arg)) {
size_t length = RJSValidatedListLength(ctx, arg);
for (long i = length-1; i >= 0; i--) {
JSObjectRef jsObject = RJSValidatedValueToObject(ctx, RJSValidatedObjectAtIndex(ctx, arg, (unsigned int)i));
if (!RJSValueIsObjectOfClass(ctx, jsObject, object_class())) {
else if (Value::is_array(ctx, arg)) {
uint32_t length = Object::validated_get_length(ctx, arg);
for (uint32_t i = length; i--;) {
ObjectType object = Object::validated_get_object(ctx, arg, i);
if (!Object::template is_instance<realm::Object>(ctx, object)) {
throw std::runtime_error("Argument to 'delete' must be a Realm object or a collection of Realm objects.");
}
Object *object = RJSGetInternal<Object *>(jsObject);
realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object->get_object_schema().name);
table->move_last_over(object->row().get_index());
auto realm_object = get_internal<T, realm::Object>(object);
realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), realm_object->get_object_schema().name);
table->move_last_over(realm_object->row().get_index());
}
}
else if(RJSValueIsObjectOfClass(ctx, arg, realm::js::results_class())) {
Results *results = RJSGetInternal<Results *>(arg);
results->clear();
}
else if(RJSValueIsObjectOfClass(ctx, arg, realm::js::list_class())) {
List *list = RJSGetInternal<List *>(arg);
// else if(RJSValueIsObjectOfClass(ctx, arg, realm::js::results_class())) {
// auto results = get_internal<T, realm::Results>(arg);
// results->clear();
// }
else if (Object::template is_instance<realm::List>(ctx, arg)) {
auto list = get_internal<T, realm::List>(arg);
list->delete_all();
}
else {
@ -375,10 +391,10 @@ void Realm<T>::Delete(ContextType ctx, ObjectType thisObject, size_t argumentCou
}
template<typename T>
void Realm<T>::DeleteAll(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
RJSValidateArgumentCount(argumentCount, 0);
void Realm<T>::DeleteAll(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
SharedRealm realm = *get_internal<T, SharedRealm>(this_object);
if (!realm->is_in_transaction()) {
throw std::runtime_error("Can only delete objects within a transaction.");
@ -390,14 +406,15 @@ void Realm<T>::DeleteAll(ContextType ctx, ObjectType thisObject, size_t argument
}
template<typename T>
void Realm<T>::Write(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
RJSValidateArgumentCount(argumentCount, 1);
void Realm<T>::Write(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
SharedRealm realm = *get_internal<T, SharedRealm>(this_object);
FunctionType callback = Value::validated_to_function(ctx, arguments[0]);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
auto object = RJSValidatedValueToFunction(ctx, arguments[0]);
try {
realm->begin_transaction();
RJSCallFunction(ctx, object, thisObject, 0, NULL);
Function<T>::call(ctx, callback, this_object, 0, nullptr);
realm->commit_transaction();
}
catch (std::exception &exp) {
@ -409,42 +426,45 @@ void Realm<T>::Write(ContextType ctx, ObjectType thisObject, size_t argumentCoun
}
template<typename T>
void Realm<T>::AddListener(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
RJSValidateArgumentCount(argumentCount, 2);
__unused std::string name = validated_notification_name(ctx, arguments[0]);
auto callback = RJSValidatedValueToFunction(ctx, arguments[1]);
void Realm<T>::AddListener(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 2);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<js::RealmDelegate<jsc::Types> *>(realm->m_binding_context.get())->add_notification(callback);
__unused std::string name = validated_notification_name(ctx, arguments[0]);
auto callback = Value::validated_to_function(ctx, arguments[1]);
SharedRealm realm = *get_internal<T, SharedRealm>(this_object);
get_delegate<T>(realm.get())->add_notification(callback);
}
template<typename T>
void Realm<T>::RemoveListener(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
RJSValidateArgumentCount(argumentCount, 2);
__unused std::string name = validated_notification_name(ctx, arguments[0]);
auto callback = RJSValidatedValueToFunction(ctx, arguments[1]);
void Realm<T>::RemoveListener(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 2);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<js::RealmDelegate<jsc::Types> *>(realm->m_binding_context.get())->remove_notification(callback);
__unused std::string name = validated_notification_name(ctx, arguments[0]);
auto callback = Value::validated_to_function(ctx, arguments[1]);
SharedRealm realm = *get_internal<T, SharedRealm>(this_object);
get_delegate<T>(realm.get())->remove_notification(callback);
}
template<typename T>
void Realm<T>::RemoveAllListeners(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
RJSValidateArgumentRange(argumentCount, 0, 1);
if (argumentCount) {
void Realm<T>::RemoveAllListeners(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0, 1);
if (argc) {
validated_notification_name(ctx, arguments[0]);
}
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<js::RealmDelegate<jsc::Types> *>(realm->m_binding_context.get())->remove_all_notifications();
SharedRealm realm = *get_internal<T, SharedRealm>(this_object);
get_delegate<T>(realm.get())->remove_all_notifications();
}
template<typename T>
void Realm<T>::Close(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) {
RJSValidateArgumentCount(argumentCount, 0);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
void Realm<T>::Close(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
SharedRealm realm = *get_internal<T, SharedRealm>(this_object);
realm->close();
}
}
}
} // js
} // realm

View File

@ -17,8 +17,9 @@
////////////////////////////////////////////////////////////////////////////
#include "js_results.hpp"
#include "js_collection.hpp"
#include "jsc_collection.hpp"
#include "js_object.hpp"
#include "jsc_util.hpp"
#include "object_accessor.hpp"
#include "results.hpp"
#include "parser.hpp"
@ -91,7 +92,7 @@ void ResultsPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAc
JSValueRef ResultsStaticCopy(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
Results *results = RJSGetInternal<Results *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0);
validate_argument_count(argumentCount, 0);
Results *copy = new Results(*results);
copy->set_live(false);
@ -109,7 +110,7 @@ JSValueRef ResultsStaticCopy(JSContextRef ctx, JSObjectRef function, JSObjectRef
JSValueRef ResultsSorted(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
Results *results = RJSGetInternal<Results *>(thisObject);
RJSValidateArgumentRange(argumentCount, 1, 2);
validate_argument_count(argumentCount, 1, 2);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
return RJSResultsCreateSorted(ctx, sharedRealm, results->get_object_schema(), std::move(results->get_query()), argumentCount, arguments);
@ -125,7 +126,7 @@ JSValueRef ResultsSorted(JSContextRef ctx, JSObjectRef function, JSObjectRef thi
JSValueRef ResultsFiltered(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
Results *results = RJSGetInternal<Results *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
validate_argument_count_at_least(argumentCount, 1);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
return RJSResultsCreateFiltered(ctx, sharedRealm, results->get_object_schema(), std::move(results->get_query()), argumentCount, arguments);
@ -189,7 +190,7 @@ JSObjectRef RJSResultsCreateSorted(JSContextRef ctx, SharedRealm realm, const Ob
std::vector<bool> ascending;
if (RJSIsValueArray(ctx, arguments[0])) {
RJSValidateArgumentCount(argumentCount, 1, "Second argument is not allowed if passed an array of sort descriptors");
validate_argument_count(argumentCount, 1, "Second argument is not allowed if passed an array of sort descriptors");
JSObjectRef js_prop_names = RJSValidatedValueToObject(ctx, arguments[0]);
prop_count = RJSValidatedListLength(ctx, js_prop_names);
@ -214,7 +215,7 @@ JSObjectRef RJSResultsCreateSorted(JSContextRef ctx, SharedRealm realm, const Ob
}
}
else {
RJSValidateArgumentRange(argumentCount, 1, 2);
validate_argument_count(argumentCount, 1, 2);
prop_count = 1;
prop_names.push_back(RJSValidatedStringForValue(ctx, arguments[0]));

View File

@ -18,10 +18,13 @@
#pragma once
#include "js_util.hpp"
#include <memory>
#include <vector>
#include "jsc_types.hpp"
namespace realm {
class ObjectSchema;
class Realm;
class Query;
typedef std::shared_ptr<Realm> SharedRealm;

View File

@ -19,6 +19,7 @@
#include "js_schema.hpp"
#include "object_store.hpp"
/*
namespace realm {
struct SchemaWrapper {
Schema *schema;
@ -44,3 +45,4 @@ JSObjectRef RJSSchemaCreate(JSContextRef ctx, Schema &schema) {
wrapper->owned = false;
return js::WrapObject(ctx, RJSSchemaClass(), wrapper);
}
*/

View File

@ -18,62 +18,77 @@
#pragma once
#include "js_util.hpp"
#include "schema.hpp"
#include <map>
namespace realm {
class Schema;
}
JSClassRef RJSSchemaClass();
JSObjectRef RJSSchemaCreate(JSContextRef ctx, realm::Schema *schema);
#include "js_types.hpp"
#include "schema.hpp"
namespace realm {
namespace js {
template<typename T>
struct Schema
{
struct Schema {
using ContextType = typename T::Context;
using FunctionType = typename T::Function;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
using ReturnType = typename T::Return;
using StringType = typename T::String;
using ObjectDefaults = std::map<std::string, ValueType>;
using ObjectDefaultsMap = std::map<std::string, ObjectDefaults>;
using ConstructorMap = std::map<std::string, ObjectType>;
using String = String<T>;
using Object = Object<T>;
using Value = Value<T>;
static Property parse_property(ContextType ctx, ValueType attributes, std::string propertyame, ObjectDefaults &objectDefaults);
static ObjectSchema parse_object_schema(ContextType ctx, ObjectType objectSchemaObject, ObjectDefaultsMap &defaults, ConstructorMap &constructors);
static realm::Schema parse_schema(ContextType ctx, ObjectType jsonObject, ObjectDefaultsMap &defaults, ConstructorMap &constructors);
using ObjectDefaults = std::map<std::string, Protected<ValueType>>;
using ObjectDefaultsMap = std::map<std::string, ObjectDefaults>;
using ConstructorMap = std::map<std::string, Protected<FunctionType>>;
static ObjectType dict_for_property_array(ContextType, const ObjectSchema &, ObjectType);
static Property parse_property(ContextType, ValueType, std::string, ObjectDefaults &);
static ObjectSchema parse_object_schema(ContextType, ObjectType, ObjectDefaultsMap &, ConstructorMap &);
static realm::Schema parse_schema(ContextType, ObjectType, ObjectDefaultsMap &, ConstructorMap &);
};
template<typename T>
typename T::Object Schema<T>::dict_for_property_array(ContextType ctx, const ObjectSchema &object_schema, ObjectType array) {
size_t count = object_schema.properties.size();
if (count != Object::validated_get_length(ctx, array)) {
throw std::runtime_error("Array must contain values for all object properties");
}
ObjectType dict = Object::create_empty(ctx);
for (uint32_t i = 0; i < count; i++) {
ValueType value = Object::get_property(ctx, array, i);
Object::set_property(ctx, dict, object_schema.properties[i].name, value);
}
return dict;
}
template<typename T>
Property Schema<T>::parse_property(ContextType ctx, ValueType attributes, std::string propertyName, ObjectDefaults &objectDefaults) {
StringType defaultString("default");
StringType indexedString("indexed");
StringType typeString("type");
StringType objectTypeString("objectType");
StringType optionalString("optional");
static const String defaultString = "default";
static const String indexedString = "indexed";
static const String typeString = "type";
static const String objectTypeString = "objectType";
static const String optionalString = "optional";
Property prop;
prop.name = propertyName;
JSObjectRef propertyObject = NULL;
ObjectType propertyObject = {};
std::string type;
if (ValueIsObject(ctx, attributes)) {
propertyObject = RJSValidatedValueToObject(ctx, attributes);
type = RJSValidatedStringProperty(ctx, propertyObject, typeString);
if (Value::is_object(ctx, attributes)) {
propertyObject = Value::validated_to_object(ctx, attributes);
type = Object::validated_get_string(ctx, propertyObject, typeString);
ValueType optionalValue = ObjectGetProperty(ctx, propertyObject, optionalString, NULL);
if (!ValueIsUndefined(ctx, optionalValue)) {
prop.is_nullable = RJSValidatedValueToBoolean(ctx, optionalValue, "'optional' designation expected to be of type boolean");
ValueType optionalValue = Object::get_property(ctx, propertyObject, optionalString);
if (!Value::is_undefined(ctx, optionalValue)) {
prop.is_nullable = Value::validated_to_boolean(ctx, optionalValue, "optional");
}
}
else {
type = RJSValidatedStringForValue(ctx, attributes);
type = Value::validated_to_string(ctx, attributes);
}
if (type == "bool") {
@ -98,11 +113,11 @@ Property Schema<T>::parse_property(ContextType ctx, ValueType attributes, std::s
prop.type = PropertyTypeData;
}
else if (type == "list") {
if (!propertyObject) {
if (!Value::is_valid(propertyObject)) {
throw std::runtime_error("List property must specify 'objectType'");
}
prop.type = PropertyTypeArray;
prop.object_type = RJSValidatedStringProperty(ctx, propertyObject, objectTypeString);
prop.object_type = Object::validated_get_string(ctx, propertyObject, objectTypeString);
}
else {
prop.type = PropertyTypeObject;
@ -110,26 +125,25 @@ Property Schema<T>::parse_property(ContextType ctx, ValueType attributes, std::s
// The type could either be 'object' or the name of another object type in the same schema.
if (type == "object") {
if (!propertyObject) {
if (!Value::is_valid(propertyObject)) {
throw std::runtime_error("Object property must specify 'objectType'");
}
prop.object_type = RJSValidatedStringProperty(ctx, propertyObject, objectTypeString);
prop.object_type = Object::validated_get_string(ctx, propertyObject, objectTypeString);
}
else {
prop.object_type = type;
}
}
if (propertyObject) {
ValueType defaultValue = RJSValidatedPropertyValue(ctx, propertyObject, defaultString);
if (!ValueIsUndefined(ctx, defaultValue)) {
ValueProtect(ctx, defaultValue);
objectDefaults.emplace(prop.name, defaultValue);
if (Value::is_valid(propertyObject)) {
ValueType defaultValue = Object::get_property(ctx, propertyObject, defaultString);
if (!Value::is_undefined(ctx, defaultValue)) {
objectDefaults.emplace(prop.name, Protected<ValueType>(ctx, defaultValue));
}
ValueType indexedValue = RJSValidatedPropertyValue(ctx, propertyObject, indexedString);
if (!ValueIsUndefined(ctx, indexedValue)) {
prop.is_indexed = RJSValidatedValueToBoolean(ctx, indexedValue);
ValueType indexedValue = Object::get_property(ctx, propertyObject, indexedString);
if (!Value::is_undefined(ctx, indexedValue)) {
prop.is_indexed = Value::validated_to_boolean(ctx, indexedValue);
}
}
@ -138,41 +152,41 @@ Property Schema<T>::parse_property(ContextType ctx, ValueType attributes, std::s
template<typename T>
ObjectSchema Schema<T>::parse_object_schema(ContextType ctx, ObjectType objectSchemaObject, ObjectDefaultsMap &defaults, ConstructorMap &constructors) {
StringType nameString("name");
StringType primaryString("primaryKey");
StringType propertiesString("properties");
StringType schemaString("schema");
static const String nameString = "name";
static const String primaryString = "primaryKey";
static const String propertiesString = "properties";
static const String schemaString = "schema";
ObjectType objectConstructor = NULL;
if (ValueIsConstructor(ctx, objectSchemaObject)) {
objectConstructor = objectSchemaObject;
objectSchemaObject = RJSValidatedObjectProperty(ctx, objectConstructor, schemaString, "Realm object constructor must have a 'schema' property.");
FunctionType objectConstructor = {};
if (Value::is_constructor(ctx, objectSchemaObject)) {
objectConstructor = Value::to_constructor(ctx, objectSchemaObject);
objectSchemaObject = Object::validated_get_object(ctx, objectConstructor, schemaString, "Realm object constructor must have a 'schema' property.");
}
ObjectDefaults objectDefaults;
ObjectSchema objectSchema;
objectSchema.name = RJSValidatedStringProperty(ctx, objectSchemaObject, nameString);
objectSchema.name = Object::validated_get_string(ctx, objectSchemaObject, nameString);
ObjectType propertiesObject = RJSValidatedObjectProperty(ctx, objectSchemaObject, propertiesString, "ObjectSchema must have a 'properties' object.");
if (RJSIsValueArray(ctx, propertiesObject)) {
size_t propertyCount = RJSValidatedListLength(ctx, propertiesObject);
for (size_t i = 0; i < propertyCount; i++) {
ObjectType propertyObject = RJSValidatedObjectAtIndex(ctx, propertiesObject, (unsigned int)i);
std::string propertyName = RJSValidatedStringProperty(ctx, propertyObject, nameString);
ObjectType propertiesObject = Object::validated_get_object(ctx, objectSchemaObject, propertiesString, "ObjectSchema must have a 'properties' object.");
if (Value::is_array(ctx, propertiesObject)) {
uint32_t length = Object::validated_get_length(ctx, propertiesObject);
for (uint32_t i = 0; i < length; i++) {
ObjectType propertyObject = Object::validated_get_object(ctx, propertiesObject, i);
std::string propertyName = Object::validated_get_string(ctx, propertyObject, nameString);
objectSchema.properties.emplace_back(parse_property(ctx, propertyObject, propertyName, objectDefaults));
}
}
else {
auto propertyNames = ObjectGetPropertyNames(ctx, propertiesObject);
auto propertyNames = Object::get_property_names(ctx, propertiesObject);
for (auto propertyName : propertyNames) {
ValueType propertyValue = RJSValidatedPropertyValue(ctx, propertiesObject, StringType(propertyName.c_str()));
ValueType propertyValue = Object::get_property(ctx, propertiesObject, propertyName);
objectSchema.properties.emplace_back(parse_property(ctx, propertyValue, propertyName, objectDefaults));
}
}
JSValueRef primaryValue = RJSValidatedPropertyValue(ctx, objectSchemaObject, primaryString);
if (!JSValueIsUndefined(ctx, primaryValue)) {
objectSchema.primary_key = RJSValidatedStringForValue(ctx, primaryValue);
ValueType primaryValue = Object::get_property(ctx, objectSchemaObject, primaryString);
if (!Value::is_undefined(ctx, primaryValue)) {
objectSchema.primary_key = Value::validated_to_string(ctx, primaryValue);
Property *property = objectSchema.primary_key_property();
if (!property) {
throw std::runtime_error("Missing primary key property '" + objectSchema.primary_key + "'");
@ -181,9 +195,8 @@ ObjectSchema Schema<T>::parse_object_schema(ContextType ctx, ObjectType objectSc
}
// Store prototype so that objects of this type will have their prototype set to this prototype object.
if (objectConstructor) {
ValueProtect(ctx, objectConstructor);
constructors[objectSchema.name] = std::move(objectConstructor);
if (Value::is_valid(objectConstructor)) {
constructors.emplace(objectSchema.name, Protected<FunctionType>(ctx, objectConstructor));
}
defaults.emplace(objectSchema.name, std::move(objectDefaults));
@ -194,14 +207,16 @@ ObjectSchema Schema<T>::parse_object_schema(ContextType ctx, ObjectType objectSc
template<typename T>
realm::Schema Schema<T>::parse_schema(ContextType ctx, ObjectType jsonObject, ObjectDefaultsMap &defaults, ConstructorMap &constructors) {
std::vector<ObjectSchema> schema;
size_t length = RJSValidatedListLength(ctx, jsonObject);
for (unsigned int i = 0; i < length; i++) {
JSObjectRef jsonObjectSchema = RJSValidatedObjectAtIndex(ctx, jsonObject, i);
uint32_t length = Object::validated_get_length(ctx, jsonObject);
for (uint32_t i = 0; i < length; i++) {
ObjectType jsonObjectSchema = Object::validated_get_object(ctx, jsonObject, i);
ObjectSchema objectSchema = parse_object_schema(ctx, jsonObjectSchema, defaults, constructors);
schema.emplace_back(std::move(objectSchema));
}
return realm::Schema(schema);
}
}
}
} // js
} // realm

294
src/js_types.hpp Normal file
View File

@ -0,0 +1,294 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include <stdexcept>
#include <string>
#include <vector>
#if defined(__GNUC__) && !(defined(DEBUG) && DEBUG)
# define REALM_JS_INLINE inline __attribute__((always_inline))
#elif defined(_MSC_VER) && !(defined(DEBUG) && DEBUG)
# define REALM_JS_INLINE __forceinline
#else
# define REALM_JS_INLINE inline
#endif
namespace realm {
namespace js {
enum PropertyAttributes {
None = 0,
ReadOnly = 1 << 0,
DontEnum = 1 << 1,
DontDelete = 1 << 2
};
template<typename T>
class String {
using StringType = typename T::String;
public:
String(const char *);
String(const StringType &);
String(StringType &&);
String(const std::string &);
operator StringType() const;
operator std::string() const;
};
template<typename T>
class Context {
using ContextType = typename T::Context;
using GlobalContextType = typename T::GlobalContext;
public:
static GlobalContextType get_global_context(ContextType);
};
template<typename T>
class Value {
using ContextType = typename T::Context;
using FunctionType = typename T::Function;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
public:
static bool is_array(ContextType, const ValueType &);
static bool is_array_buffer(ContextType, const ValueType &);
static bool is_boolean(ContextType, const ValueType &);
static bool is_constructor(ContextType, const ValueType &);
static bool is_date(ContextType, const ValueType &);
static bool is_function(ContextType, const ValueType &);
static bool is_null(ContextType, const ValueType &);
static bool is_number(ContextType, const ValueType &);
static bool is_object(ContextType, const ValueType &);
static bool is_string(ContextType, const ValueType &);
static bool is_undefined(ContextType, const ValueType &);
static bool is_valid(const ValueType &);
static ValueType from_boolean(ContextType, bool);
static ValueType from_null(ContextType);
static ValueType from_number(ContextType, double);
static ValueType from_string(ContextType, const String<T> &);
static ValueType from_undefined(ContextType);
static ObjectType to_array(ContextType, const ValueType &);
static bool to_boolean(ContextType, const ValueType &);
static FunctionType to_constructor(ContextType, const ValueType &);
static ObjectType to_date(ContextType, const ValueType &);
static FunctionType to_function(ContextType, const ValueType &);
static double to_number(ContextType, const ValueType &);
static ObjectType to_object(ContextType, const ValueType &);
static String<T> to_string(ContextType, const ValueType &);
#define VALIDATED(return_t, type) \
static return_t validated_to_##type(ContextType ctx, const ValueType &value, const char *name = nullptr) { \
if (!is_##type(ctx, value)) { \
std::string prefix = name ? std::string("'") + name + "'" : "JS value"; \
throw std::invalid_argument(prefix + " must be: " #type); \
} \
return to_##type(ctx, value); \
}
VALIDATED(ObjectType, array)
VALIDATED(bool, boolean)
VALIDATED(FunctionType, constructor)
VALIDATED(ObjectType, date)
VALIDATED(FunctionType, function)
VALIDATED(double, number)
VALIDATED(ObjectType, object)
VALIDATED(String<T>, string)
#undef VALIDATED
};
template<typename T>
class Function {
using ContextType = typename T::Context;
using FunctionType = typename T::Function;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
public:
static ValueType call(ContextType, const FunctionType &, const ObjectType &, uint32_t, const ValueType[]);
static ValueType call(ContextType ctx, const FunctionType &function, const ObjectType &this_object, const std::vector<ValueType> &arguments) {
return call(ctx, function, this_object, arguments.size(), arguments.data());
}
static ObjectType construct(ContextType, const FunctionType &, uint32_t, const ValueType[]);
static ValueType construct(ContextType ctx, const FunctionType &function, const std::vector<ValueType> &arguments) {
return construct(ctx, function, arguments.size(), arguments.data());
}
};
template<typename T>
class Object {
using ContextType = typename T::Context;
using FunctionType = typename T::Function;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
public:
static bool has_property(ContextType, const ObjectType &, const String<T> &);
static bool has_property(ContextType, const ObjectType &, uint32_t);
static ValueType get_property(ContextType, const ObjectType &, const String<T> &);
static ValueType get_property(ContextType, const ObjectType &, uint32_t);
static void set_property(ContextType, const ObjectType &, const String<T> &, const ValueType &, PropertyAttributes attributes = None);
static void set_property(ContextType, const ObjectType &, uint32_t, const ValueType &);
static std::vector<String<T>> get_property_names(ContextType, const ObjectType &);
static ValueType get_prototype(ContextType, const ObjectType &);
static void set_prototype(ContextType, const ObjectType &, const ValueType &);
static uint32_t validated_get_length(ContextType ctx, const ObjectType &object) {
static const String<T> length_string = "length";
return Value<T>::validated_to_number(ctx, get_property(ctx, object, length_string));
}
#define VALIDATED(return_t, type) \
static return_t validated_get_##type(ContextType ctx, const ObjectType &object, const String<T> &key, const char *message = nullptr) { \
try { \
return Value<T>::validated_to_##type(ctx, get_property(ctx, object, key), std::string(key).c_str()); \
} \
catch(std::invalid_argument &e) { \
throw message ? std::invalid_argument(message) : e; \
} \
} \
static return_t validated_get_##type(ContextType ctx, const ObjectType &object, uint32_t index, const char *message = nullptr) { \
try { \
return Value<T>::validated_to_##type(ctx, get_property(ctx, object, index)); \
} \
catch(std::invalid_argument &e) { \
throw message ? std::invalid_argument(message) : e; \
} \
}
VALIDATED(ObjectType, array)
VALIDATED(bool, boolean)
VALIDATED(FunctionType, constructor)
VALIDATED(ObjectType, date)
VALIDATED(FunctionType, function)
VALIDATED(double, number)
VALIDATED(ObjectType, object)
VALIDATED(String<T>, string)
#undef VALIDATED
static ValueType call_method(ContextType ctx, const ObjectType &object, const String<T> &name, uint32_t argc, const ValueType arguments[]) {
FunctionType method = validated_get_function(ctx, object, name);
return Function<T>::call(ctx, method, object, argc, arguments);
}
static ValueType call_method(ContextType ctx, const ObjectType &object, const String<T> &name, const std::vector<ValueType> &arguments) {
return call_method(ctx, object, name, (uint32_t)arguments.size(), arguments.data());
}
static ObjectType create_empty(ContextType);
static ObjectType create_array(ContextType, uint32_t, const ValueType[]);
static ObjectType create_array(ContextType ctx, const std::vector<ValueType> &values) {
return create_array(ctx, (uint32_t)values.size(), values.data());
}
static ObjectType create_array(ContextType ctx) {
return create_array(ctx, 0, nullptr);
}
static ObjectType create_date(ContextType, double);
template<typename U>
static ObjectType create(ContextType, U*);
template<typename U>
static bool is_instance(ContextType, const ObjectType &);
template<typename U>
static U* get_internal(const ObjectType &);
template<typename U>
static void set_internal(const ObjectType &, U*);
};
template<typename T>
class Protected {
operator T() const;
bool operator==(const T &) const;
bool operator!=(const T &) const;
bool operator==(const Protected<T> &) const;
bool operator!=(const Protected<T> &) const;
bool operator<(const Protected<T> &) const;
};
template<typename T>
class Exception : public std::runtime_error {
using ContextType = typename T::Context;
using ValueType = typename T::Value;
const Protected<ValueType> m_value;
public:
Exception(ContextType ctx, const ValueType &val)
: std::runtime_error(std::string(Value<T>::to_string(ctx, val))), m_value(ctx, val) {}
operator ValueType() const {
return m_value;
}
static ValueType value(ContextType ctx, const std::string &message);
static ValueType value(ContextType ctx, const std::exception &exp) {
if (const Exception<T> *js_exp = dynamic_cast<const Exception<T> *>(&exp)) {
return *js_exp;
}
return value(ctx, exp.what());
}
};
template<typename T>
class ReturnValue {
using ValueType = typename T::Value;
public:
void set(const ValueType &);
void set(const std::string &);
void set(bool);
void set(double);
void set(int32_t);
void set(uint32_t);
void set_null();
void set_undefined();
};
template<typename T, typename U>
REALM_JS_INLINE typename T::Object create_object(typename T::Context ctx, U* internal = nullptr) {
return Object<T>::template create<U>(ctx, internal);
}
template<typename T, typename U>
REALM_JS_INLINE U* get_internal(const typename T::Object &object) {
return Object<T>::template get_internal<U>(object);
}
template<typename T, typename U>
REALM_JS_INLINE void set_internal(const typename T::Object &object, U* ptr) {
Object<T>::template set_internal<U>(object, ptr);
}
} // js
} // realm

View File

@ -1,99 +0,0 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#include "js_util.hpp"
#include <JavaScriptCore/JSStringRef.h>
using namespace realm;
JSValueRef RJSMakeError(JSContextRef ctx, RJSException &exp) {
JSValueRef value = exp.exception();
return JSObjectMakeError(ctx, 1, &value, NULL);
}
JSValueRef RJSMakeError(JSContextRef ctx, std::exception &exp) {
if (RJSException *rjsExp = dynamic_cast<RJSException *>(&exp)) {
return RJSMakeError(ctx, *rjsExp);
}
return RJSMakeError(ctx, exp.what());
}
JSValueRef RJSMakeError(JSContextRef ctx, const std::string &message) {
JSValueRef value = RJSValueForString(ctx, message);
return JSObjectMakeError(ctx, 1, &value, NULL);
}
std::string RJSStringForJSString(JSStringRef jsString) {
std::string str;
size_t maxSize = JSStringGetMaximumUTF8CStringSize(jsString);
str.resize(maxSize);
str.resize(JSStringGetUTF8CString(jsString, &str[0], maxSize) - 1);
return str;
}
std::string RJSStringForValue(JSContextRef ctx, JSValueRef value) {
JSValueRef exception = nullptr;
JSStringRef jsString = JSValueToStringCopy(ctx, value, &exception);
if (!jsString) {
throw RJSException(ctx, exception);
}
std::string string = RJSStringForJSString(jsString);
JSStringRelease(jsString);
return string;
}
std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const char * name) {
if (!JSValueIsString(ctx, value)) {
if (name) {
throw std::invalid_argument((std::string)"'" + name + "' must be of type 'String'");
}
else {
throw std::invalid_argument("JSValue must be of type 'String'");
}
}
return RJSStringForValue(ctx, value);
}
JSStringRef RJSStringForString(const std::string &str) {
return JSStringCreateWithUTF8CString(str.c_str());
}
JSValueRef RJSValueForString(JSContextRef ctx, const std::string &str) {
JSStringRef jsStr = RJSStringForString(str);
JSValueRef value = JSValueMakeString(ctx, jsStr);
JSStringRelease(jsStr);
return value;
}
bool RJSIsValueArray(JSContextRef ctx, JSValueRef value) {
static JSStringRef arrayString = JSStringCreateWithUTF8CString("Array");
return RJSIsValueObjectOfType(ctx, value, arrayString);
}
bool RJSIsValueArrayBuffer(JSContextRef ctx, JSValueRef value) {
static JSStringRef arrayString = JSStringCreateWithUTF8CString("ArrayBuffer");
return RJSIsValueObjectOfType(ctx, value, arrayString);
}
bool RJSIsValueDate(JSContextRef ctx, JSValueRef value) {
static JSStringRef dateString = JSStringCreateWithUTF8CString("Date");
return RJSIsValueObjectOfType(ctx, value, dateString);
}

View File

@ -18,257 +18,25 @@
#pragma once
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSStringRef.h>
#include <math.h>
#include <string>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <cmath>
#include "property.hpp"
#include "js_compat.hpp"
#include "schema.hpp"
#define WRAP_EXCEPTION(METHOD, EXCEPTION, ARGS...) \
try { METHOD(ARGS); } \
catch(std::exception &e) { RJSSetException(ctx, EXCEPTION, e); }
#define WRAP_CLASS_METHOD(CLASS_NAME, METHOD_NAME) \
JSValueRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* ex) { \
JSValueRef returnValue = NULL; \
WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, thisObject, argumentCount, arguments, returnValue); \
return returnValue; \
}
#define WRAP_CONSTRUCTOR(CLASS_NAME, METHOD_NAME) \
JSObjectRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* ex) { \
JSObjectRef returnObject = NULL; \
WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, constructor, argumentCount, arguments, returnObject); \
return returnObject; \
}
#define WRAP_PROPERTY_GETTER(CLASS_NAME, METHOD_NAME) \
JSValueRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* ex) { \
JSValueRef returnValue = NULL; \
WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, object, returnValue); \
return returnValue; \
}
#define WRAP_PROPERTY_SETTER(CLASS_NAME, METHOD_NAME) \
bool CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef* ex) { \
WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, object, value); \
return true; \
}
// for stol failure (std::invalid_argument) this could be another property that is handled externally, so ignore
#define WRAP_INDEXED_GETTER(CLASS_NAME, METHOD_NAME) \
JSValueRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* ex) { \
JSValueRef returnValue = NULL; \
try { \
size_t index = RJSValidatedPositiveIndex(RJSStringForJSString(property)); \
CLASS_NAME::METHOD_NAME(ctx, object, index, returnValue); return returnValue; \
} \
catch (std::out_of_range &exp) { return JSValueMakeUndefined(ctx); } \
catch (std::invalid_argument &exp) { return NULL; } \
catch (std::exception &e) { RJSSetException(ctx, *ex, e); return NULL; } \
}
#define WRAP_INDEXED_SETTER(CLASS_NAME, METHOD_NAME) \
bool CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef* ex) { \
try { \
size_t index = RJSValidatedPositiveIndex(RJSStringForJSString(property)); \
{ CLASS_NAME::METHOD_NAME(ctx, object, index, value); return true; } \
} \
catch (std::out_of_range &exp) { RJSSetException(ctx, *ex, exp); } \
catch (std::invalid_argument &exp) { *ex = RJSMakeError(ctx, "Invalid index"); } \
catch (std::exception &e) { RJSSetException(ctx, *ex, e); } \
return false; \
}
#include "shared_realm.hpp"
namespace realm {
namespace js {
template<typename T>
inline void RJSFinalize(JSObjectRef object) {
delete static_cast<T>(JSObjectGetPrivate(object));
JSObjectSetPrivate(object, NULL);
class RealmDelegate;
template<typename T>
static inline RealmDelegate<T> *get_delegate(Realm *realm) {
return static_cast<RealmDelegate<T> *>(realm->m_binding_context.get());
}
template<typename T>
inline T RJSGetInternal(JSObjectRef jsObject) {
return static_cast<T>(JSObjectGetPrivate(jsObject));
}
template<typename T>
JSClassRef RJSCreateWrapperClass(const char * name, JSObjectGetPropertyCallback getter = NULL, JSObjectSetPropertyCallback setter = NULL, const JSStaticFunction *funcs = NULL,
JSObjectGetPropertyNamesCallback propertyNames = NULL, JSClassRef parentClass = NULL, const JSStaticValue *values = NULL) {
JSClassDefinition classDefinition = kJSClassDefinitionEmpty;
classDefinition.className = name;
classDefinition.finalize = RJSFinalize<T>;
classDefinition.getProperty = getter;
classDefinition.setProperty = setter;
classDefinition.staticFunctions = funcs;
classDefinition.getPropertyNames = propertyNames;
classDefinition.parentClass = parentClass;
classDefinition.staticValues = values;
return JSClassCreate(&classDefinition);
}
std::string RJSStringForJSString(JSStringRef jsString);
std::string RJSStringForValue(JSContextRef ctx, JSValueRef value);
std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const char * name = nullptr);
JSStringRef RJSStringForString(const std::string &str);
JSValueRef RJSValueForString(JSContextRef ctx, const std::string &str);
inline void RJSValidateArgumentCount(size_t argumentCount, size_t expected, const char *message = nullptr) {
if (argumentCount != expected) {
throw std::invalid_argument(message ?: "Invalid arguments");
}
}
inline void RJSValidateArgumentCountIsAtLeast(size_t argumentCount, size_t expected, const char *message = nullptr) {
if (argumentCount < expected) {
throw std::invalid_argument(message ?: "Invalid arguments");
}
}
inline void RJSValidateArgumentRange(size_t argumentCount, size_t min, size_t max, const char *message = nullptr) {
if (argumentCount < min || argumentCount > max) {
throw std::invalid_argument(message ?: "Invalid arguments");
}
}
class RJSException : public std::runtime_error {
public:
RJSException(JSContextRef ctx, JSValueRef &ex) : std::runtime_error(RJSStringForValue(ctx, ex)),
m_jsException(ex) {}
JSValueRef exception() { return m_jsException; }
private:
JSValueRef m_jsException;
};
JSValueRef RJSMakeError(JSContextRef ctx, RJSException &exp);
JSValueRef RJSMakeError(JSContextRef ctx, std::exception &exp);
JSValueRef RJSMakeError(JSContextRef ctx, const std::string &message);
bool RJSIsValueArray(JSContextRef ctx, JSValueRef value);
bool RJSIsValueArrayBuffer(JSContextRef ctx, JSValueRef value);
bool RJSIsValueDate(JSContextRef ctx, JSValueRef value);
static inline JSObjectRef RJSValidatedValueToObject(JSContextRef ctx, JSValueRef value, const char *message = nullptr) {
JSObjectRef object = JSValueToObject(ctx, value, NULL);
if (!object) {
throw std::runtime_error(message ?: "Value is not an object.");
}
return object;
}
static inline JSObjectRef RJSValidatedValueToDate(JSContextRef ctx, JSValueRef value, const char *message = nullptr) {
JSObjectRef object = JSValueToObject(ctx, value, NULL);
if (!object || !RJSIsValueDate(ctx, object)) {
throw std::runtime_error(message ?: "Value is not a date.");
}
return object;
}
static inline JSObjectRef RJSValidatedValueToFunction(JSContextRef ctx, JSValueRef value, const char *message = nullptr) {
JSObjectRef object = JSValueToObject(ctx, value, NULL);
if (!object || !JSObjectIsFunction(ctx, object)) {
throw std::runtime_error(message ?: "Value is not a function.");
}
return object;
}
static inline double RJSValidatedValueToNumber(JSContextRef ctx, JSValueRef value) {
if (JSValueIsNull(ctx, value)) {
throw std::invalid_argument("`null` is not a number.");
}
JSValueRef exception = NULL;
double number = JSValueToNumber(ctx, value, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
if (isnan(number)) {
throw std::invalid_argument("Value not convertible to a number.");
}
return number;
}
static inline double RJSValidatedValueToBoolean(JSContextRef ctx, JSValueRef value, const char *err = nullptr) {
if (!JSValueIsBoolean(ctx, value)) {
throw std::invalid_argument(err ?: "Value is not a boolean.");
}
return JSValueToBoolean(ctx, value);
}
static inline JSValueRef RJSValidatedPropertyValue(JSContextRef ctx, JSObjectRef object, JSStringRef property) {
JSValueRef exception = NULL;
JSValueRef propertyValue = JSObjectGetProperty(ctx, object, property, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
return propertyValue;
}
static inline JSValueRef RJSValidatedPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned int index) {
JSValueRef exception = NULL;
JSValueRef propertyValue = JSObjectGetPropertyAtIndex(ctx, object, index, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
return propertyValue;
}
static inline JSObjectRef RJSValidatedObjectProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property, const char *err = nullptr) {
JSValueRef propertyValue = RJSValidatedPropertyValue(ctx, object, property);
if (JSValueIsUndefined(ctx, propertyValue)) {
throw std::runtime_error(err ?: "Object property '" + RJSStringForJSString(property) + "' is undefined");
}
return RJSValidatedValueToObject(ctx, propertyValue, err);
}
static inline JSObjectRef RJSValidatedObjectAtIndex(JSContextRef ctx, JSObjectRef object, unsigned int index) {
return RJSValidatedValueToObject(ctx, RJSValidatedPropertyAtIndex(ctx, object, index));
}
static inline std::string RJSValidatedStringProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property) {
JSValueRef exception = NULL;
JSValueRef propertyValue = JSObjectGetProperty(ctx, object, property, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
return RJSValidatedStringForValue(ctx, propertyValue, RJSStringForJSString(property).c_str());
}
static inline size_t RJSValidatedListLength(JSContextRef ctx, JSObjectRef object) {
JSValueRef exception = NULL;
static JSStringRef lengthString = JSStringCreateWithUTF8CString("length");
JSValueRef lengthValue = JSObjectGetProperty(ctx, object, lengthString, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
if (!JSValueIsNumber(ctx, lengthValue)) {
throw std::runtime_error("Missing property 'length'");
}
return RJSValidatedValueToNumber(ctx, lengthValue);
}
static inline void RJSValidatedSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes = 0) {
JSValueRef exception = NULL;
JSObjectSetProperty(ctx, object, propertyName, value, attributes, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
}
template<typename T>
T stot(const std::string s) {
static inline T stot(const std::string &s) {
std::istringstream iss(s);
T value;
iss >> value;
@ -278,82 +46,34 @@ T stot(const std::string s) {
return value;
}
static inline size_t RJSValidatedPositiveIndex(std::string indexStr) {
long index = stot<long>(indexStr);
static inline uint32_t validated_positive_index(std::string string) {
int64_t index = stot<int64_t>(string);
if (index < 0) {
throw std::out_of_range(std::string("Index ") + indexStr + " cannot be less than zero.");
throw std::out_of_range(std::string("Index ") + string + " cannot be less than zero.");
}
return index;
if (index > std::numeric_limits<uint32_t>::max()) {
throw std::out_of_range(std::string("Index ") + string + " must be a 32-bit unsigned integer");
}
return static_cast<uint32_t>(index);
}
static inline bool RJSIsValueObjectOfType(JSContextRef ctx, JSValueRef value, JSStringRef type) {
JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
JSValueRef exception = NULL;
JSValueRef constructorValue = JSObjectGetProperty(ctx, globalObject, type, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
bool ret = JSValueIsInstanceOfConstructor(ctx, value, RJSValidatedValueToObject(ctx, constructorValue), &exception);
if (exception) {
throw RJSException(ctx, exception);
}
return ret;
}
static inline void RJSSetReturnUndefined(JSContextRef ctx, JSValueRef &returnObject) {
returnObject = JSValueMakeUndefined(ctx);
}
template<typename T>
static inline void RJSSetReturnNumber(JSContextRef ctx, JSValueRef &returnObject, T number) {
returnObject = JSValueMakeNumber(ctx, number);
}
static inline void RJSSetReturnArray(JSContextRef ctx, size_t count, const JSValueRef *objects, JSValueRef &returnObject) {
returnObject = JSObjectMakeArray(ctx, count, objects, NULL);
}
static inline void RJSSetException(JSContextRef ctx, JSValueRef &exceptionObject, std::exception &exception) {
exceptionObject = RJSMakeError(ctx, exception);
}
static JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, const realm::ObjectSchema &object_schema, JSObjectRef array) {
// copy to dictionary
if (object_schema.properties.size() != RJSValidatedListLength(ctx, array)) {
throw std::runtime_error("Array must contain values for all object properties");
}
JSValueRef exception = NULL;
JSObjectRef dict = JSObjectMake(ctx, NULL, NULL);
for (unsigned int i = 0; i < object_schema.properties.size(); i++) {
JSStringRef nameStr = JSStringCreateWithUTF8CString(object_schema.properties[i].name.c_str());
JSValueRef value = JSObjectGetPropertyAtIndex(ctx, array, i, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
JSObjectSetProperty(ctx, dict, nameStr, value, kJSPropertyAttributeNone, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
JSStringRelease(nameStr);
}
return dict;
}
static void RJSCallFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef object, size_t argumentCount, const JSValueRef *arguments) {
JSValueRef exception = NULL;
JSObjectCallAsFunction(ctx, function, object, argumentCount, arguments, &exception);
if (exception) {
throw RJSException(ctx, exception);
static inline void validate_argument_count(size_t count, size_t expected, const char *message = nullptr) {
if (count != expected) {
throw std::invalid_argument(message ?: "Invalid arguments");
}
}
static bool RJSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) {
return JSValueIsObjectOfClass(ctx, value, jsClass);
static inline void validate_argument_count(size_t count, size_t min, size_t max, const char *message = nullptr) {
if (count < min || count > max) {
throw std::invalid_argument(message ?: "Invalid arguments");
}
}
static inline void validate_argument_count_at_least(size_t count, size_t expected, const char *message = nullptr) {
if (count < expected) {
throw std::invalid_argument(message ?: "Invalid arguments");
}
}
} // js
} // realm

View File

@ -1,83 +0,0 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "types.hpp"
#include <string>
#include <vector>
namespace realm {
namespace js {
static inline bool ValueIsUndefined(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsUndefined(ctx, value); }
static inline bool ValueIsNull(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsNull(ctx, value); }
static inline bool ValueIsBoolean(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsBoolean(ctx, value); }
static inline bool ValueIsNumber(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsNumber(ctx, value); }
static inline bool ValueIsString(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsString(ctx, value); }
static inline bool ValueIsObject(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsObject(ctx, value); }
static inline bool ValueIsConstructor(jsc::Types::Context ctx, jsc::Types::Value value) { return ValueIsObject(ctx, value) && JSObjectIsConstructor(ctx, (JSObjectRef)value); }
static inline jsc::Types::Object ValueToObject(jsc::Types::Context ctx, jsc::Types::Value value) { return (JSObjectRef)value; }
static inline void ValueProtect(jsc::Types::Context ctx, jsc::Types::Value value) { JSValueProtect(ctx, value); }
static inline void ValueUnprotect(jsc::Types::Context ctx, jsc::Types::Value value) { JSValueUnprotect(ctx, value); }
static inline std::string StringTypeToString(JSStringRef jsString) {
std::string str;
size_t maxSize = JSStringGetMaximumUTF8CStringSize(jsString);
str.resize(maxSize);
str.resize(JSStringGetUTF8CString(jsString, &str[0], maxSize) - 1);
return str;
}
static inline std::vector<std::string> ObjectGetPropertyNames(jsc::Types::Context ctx, jsc::Types::Object object) {
JSPropertyNameArrayRef propertyNames = JSObjectCopyPropertyNames(ctx, object);
size_t propertyCount = JSPropertyNameArrayGetCount(propertyNames);
std::vector<std::string> outNames;
for (size_t i = 0; i < propertyCount; i++) {
outNames.push_back(StringTypeToString(JSPropertyNameArrayGetNameAtIndex(propertyNames, i)));
}
JSPropertyNameArrayRelease(propertyNames);
return outNames;
}
static inline jsc::Types::Value ObjectGetProperty(jsc::Types::Context ctx, jsc::Types::Object object, jsc::Types::String propertyName, jsc::Types::Exception *exception) {
return JSObjectGetProperty(ctx, object, propertyName, exception);
}
static inline void ObjectCallAsFunction(jsc::Types::Context ctx, jsc::Types::Object function, jsc::Types::Object thisObject, size_t argsCount, const jsc::Types::Value args[], jsc::Types::Exception &exception) {
JSObjectCallAsFunction(ctx, function, thisObject, argsCount, args, &exception);
}
static inline void GlobalContextProtect(jsc::Types::GlobalContext ctx) { JSGlobalContextRetain(ctx); }
static inline void GlobalContextUnprotect(jsc::Types::GlobalContext ctx) { JSGlobalContextRelease(ctx); }
template<class T>
jsc::Types::Object WrapObject(jsc::Types::Context ctx, jsc::Types::ObjectClass objectClass, T internal, jsc::Types::Object prototype = nullptr) {
JSObjectRef ref = JSObjectMake(ctx, objectClass, (void *)internal);
if (prototype) {
JSObjectSetPrototype(ctx, ref, prototype);
}
return ref;
}
jsc::Types::ObjectClass realm_class();
jsc::Types::ObjectClass list_class();
jsc::Types::ObjectClass object_class();
jsc::Types::ObjectClass results_class();
}}

309
src/jsc/jsc_class.hpp Normal file
View File

@ -0,0 +1,309 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "jsc_types.hpp"
#include "js_class.hpp"
#include "js_util.hpp"
namespace realm {
namespace jsc {
template<typename T>
using ObjectClass = js::ObjectClass<Types, T>;
using BaseObjectClass = js::BaseObjectClass<Types>;
using ConstructorType = js::ConstructorType<Types>;
using MethodType = js::MethodType<Types>;
using PropertyGetterType = js::PropertyGetterType<Types>;
using PropertySetterType = js::PropertySetterType<Types>;
using IndexPropertyGetterType = js::IndexPropertyGetterType<Types>;
using IndexPropertySetterType = js::IndexPropertySetterType<Types>;
using StringPropertyGetterType = js::StringPropertyGetterType<Types>;
using StringPropertySetterType = js::StringPropertySetterType<Types>;
using StringPropertyEnumeratorType = js::StringPropertyEnumeratorType<Types>;
template<typename T>
static inline T stot(const std::string &s) {
std::istringstream iss(s);
T value;
iss >> value;
if (iss.fail()) {
throw std::invalid_argument("Cannot convert string '" + s + "'");
}
return value;
}
template<typename T>
class ObjectWrap {
static ObjectClass<T> s_class;
std::unique_ptr<T> m_object;
ObjectWrap(T* object = nullptr) : m_object(object) {}
static JSObjectRef construct(JSContextRef ctx, JSObjectRef constructor, size_t argc, const JSValueRef arguments[], JSValueRef* exception) {
JSObjectRef this_object = ObjectWrap<T>::create(ctx, nullptr);
try {
s_class.constructor(ctx, this_object, argc, arguments);
}
catch(std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
}
return this_object;
}
static JSValueRef get_property(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) {
if (auto index_getter = s_class.index_accessor.getter) {
try {
uint32_t index = validated_positive_index(jsc::String(property));
return index_getter(ctx, object, index, exception);
}
catch (std::out_of_range &) {}
catch (std::invalid_argument &) {}
}
if (auto string_getter = s_class.string_accessor.getter) {
return string_getter(ctx, object, property, exception);
}
return NULL;
}
static bool set_property(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef* exception) {
if (auto index_setter = s_class.index_accessor.setter) {
try {
uint32_t index = validated_positive_index(jsc::String(property));
return index_setter(ctx, object, index, value, exception);
}
catch (std::out_of_range &) {}
catch (std::invalid_argument &) {}
}
if (auto string_setter = s_class.string_accessor.setter) {
return string_setter(ctx, object, property, value, exception);
}
return false;
}
static void get_property_names(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef accumulator) {
if (s_class.index_accessor.getter) {
try {
uint32_t length = Object::validated_get_length(ctx, object);
char string[32];
for (uint32_t i = 0; i < length; i++) {
sprintf(string, "%lu", i);
JSPropertyNameAccumulatorAddName(accumulator, jsc::String(string));
}
}
catch (std::exception &) {
// Enumerating properties should never throw an exception into JS.
}
}
if (auto string_enumerator = s_class.string_accessor.enumerator) {
string_enumerator(ctx, object, accumulator);
}
}
template<typename U>
static JSClassRef get_superclass(BaseObjectClass*) {
return nullptr;
}
template<typename U>
static JSClassRef get_superclass(ObjectClass<U>*) {
return ObjectWrap<U>::get_class();
}
static JSClassRef create_class() {
JSStaticFunction staticFunctions[s_class.methods.size() + 1];
JSStaticValue staticValues[s_class.properties.size() + 1];
JSClassDefinition definition;
// TODO: Set parentClass ensuring finalize is setup to do the right thing.
definition.finalize = finalize;
if (s_class.constructor) {
// TODO: Correctly setup constructor class with static methods/properties.
// definition.callAsConstructor = construct;
}
if (s_class.index_accessor.getter || s_class.string_accessor.getter) {
definition.getProperty = get_property;
}
if (s_class.index_accessor.setter || s_class.string_accessor.setter) {
definition.setProperty = set_property;
}
if (s_class.index_accessor.getter || s_class.string_accessor.enumerator) {
definition.getPropertyNames = get_property_names;
}
if (!s_class.methods.empty()) {
JSPropertyAttributes attributes = kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete;
size_t index = 0;
for (auto &pair : s_class.methods) {
staticFunctions[index++] = {pair.first.c_str(), pair.second, attributes};
}
staticFunctions[index] = {0};
definition.staticFunctions = staticFunctions;
}
if (!s_class.properties.empty()) {
JSPropertyAttributes attributes = kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete;
size_t index = 0;
for (auto &pair : s_class.properties) {
auto &prop = pair.second;
staticValues[index++] = {pair.first.c_str(), prop.getter, prop.setter, attributes | (prop.setter ? 0 : kJSPropertyAttributeReadOnly)};
}
staticValues[index] = {0};
definition.staticValues = staticValues;
}
return JSClassCreate(&definition);
}
static JSClassRef get_class() {
static JSClassRef js_class = create_class();
return js_class;
}
static void finalize(JSObjectRef object) {
delete static_cast<ObjectWrap<T> *>(JSObjectGetPrivate(object));
}
static JSObjectRef uncallable_constructor(JSContextRef ctx, JSObjectRef constructor, size_t argc, const JSValueRef arguments[], JSValueRef* exception) {
*exception = jsc::Exception::value(ctx, "Illegal constructor");
return NULL;
}
public:
operator T*() const {
return m_object.get();
}
static JSObjectRef create(JSContextRef ctx, T* internal = nullptr) {
return JSObjectMake(ctx, get_class(), new ObjectWrap<T>(internal));
}
static JSObjectRef create_constructor(JSContextRef ctx) {
return JSObjectMakeConstructor(ctx, get_class(), uncallable_constructor);
}
static bool has_instance(JSContextRef ctx, JSValueRef value) {
return JSValueIsObjectOfClass(ctx, value, get_class());
}
};
// The declared static variables must be defined as well.
template<typename T> ObjectClass<T> ObjectWrap<T>::s_class;
} // jsc
namespace js {
template<jsc::MethodType F>
JSValueRef wrap(JSContextRef ctx, JSObjectRef function, JSObjectRef this_object, size_t argc, const JSValueRef arguments[], JSValueRef* exception) {
jsc::ReturnValue return_value(ctx);
try {
F(ctx, this_object, argc, arguments, return_value);
}
catch(std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
}
return return_value;
}
template<jsc::PropertyGetterType F>
JSValueRef wrap(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) {
jsc::ReturnValue return_value(ctx);
try {
F(ctx, object, return_value);
}
catch(std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
}
return return_value;
}
template<jsc::PropertySetterType F>
void wrap(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef* exception) {
try {
F(ctx, object, value);
}
catch(std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
}
}
template<jsc::IndexPropertyGetterType F>
JSValueRef wrap(JSContextRef ctx, JSObjectRef object, uint32_t index, JSValueRef* exception) {
jsc::ReturnValue return_value(ctx);
try {
F(ctx, object, index, return_value);
}
catch(std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
}
return return_value;
}
template<jsc::IndexPropertySetterType F>
bool wrap(JSContextRef ctx, JSObjectRef object, uint32_t index, JSValueRef value, JSValueRef* exception) {
try {
return F(ctx, object, index, value);
}
catch(std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
}
return false;
}
template<jsc::StringPropertyGetterType F>
JSValueRef wrap(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) {
jsc::ReturnValue return_value(ctx);
try {
F(ctx, object, property, return_value);
}
catch(std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
}
return return_value;
}
template<jsc::StringPropertySetterType F>
bool wrap(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef* exception) {
try {
return F(ctx, object, property, value);
}
catch(std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
}
return false;
}
template<jsc::StringPropertyEnumeratorType F>
void wrap(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef accumulator) {
auto names = F(ctx, object);
for (auto &name : names) {
JSPropertyNameAccumulatorAddName(accumulator, name);
}
}
} // js
} // realm

View File

@ -16,7 +16,7 @@
//
////////////////////////////////////////////////////////////////////////////
#include "js_collection.hpp"
#include "jsc_collection.hpp"
static JSClassRef RJSCreateCollectionClass() {
JSClassDefinition classDefinition = kJSClassDefinitionEmpty;

View File

@ -18,6 +18,6 @@
#pragma once
#include "js_util.hpp"
#include "jsc_types.hpp"
JSClassRef RJSCollectionClass();

View File

@ -16,27 +16,28 @@
//
////////////////////////////////////////////////////////////////////////////
#include "js_init.h"
#include <algorithm>
#include <cassert>
#include "jsc_init.hpp"
#include "jsc_realm.hpp"
#include "js_object.hpp"
#include "js_collection.hpp"
#include "jsc_collection.hpp"
#include "jsc_list.hpp"
#include "js_results.hpp"
#include "js_util.hpp"
#include "js_schema.hpp"
#include "jsc_util.hpp"
#include "platform.hpp"
#include "shared_realm.hpp"
#include "impl/realm_coordinator.hpp"
#include <algorithm>
#include <cassert>
extern "C" {
using namespace realm;
using namespace realm::jsc;
JSValueRef RJSTypeGet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) {
std::string str = RJSStringForJSString(propertyName);
std::string str = String(propertyName);
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return RJSValueForString(ctx, str);
return Value::from_string(ctx, str);
}
JSClassRef RJSRealmTypeClass() {
@ -58,54 +59,49 @@ JSClassRef RJSRealmTypeClass() {
return JSClassCreate(&realmTypesDefinition);
}
static JSObjectRef UncallableConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) {
*exception = RJSMakeError(ctx, "Illegal constructor");
return NULL;
}
static JSValueRef ClearTestState(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
RJSClearTestState();
return NULL;
}
JSObjectRef RJSConstructorCreate(JSContextRef ctx) {
static JSStringRef clearTestStateString = JSStringCreateWithUTF8CString("clearTestState");
static JSStringRef collectionString = JSStringCreateWithUTF8CString("Collection");
static JSStringRef listString = JSStringCreateWithUTF8CString("List");
static JSStringRef resultsString = JSStringCreateWithUTF8CString("Results");
static JSStringRef typeString = JSStringCreateWithUTF8CString("Types");
static const String clearTestStateString = "clearTestState";
static const String collectionString = "Collection";
static const String listString = "List";
static const String resultsString = "Results";
static const String typeString = "Types";
JSObjectRef realmObject = JSObjectMake(ctx, RJSRealmConstructorClass(), NULL);
JSPropertyAttributes attributes = kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete;
js::PropertyAttributes attributes = js::PropertyAttributes(js::ReadOnly | js::DontEnum | js::DontDelete);
JSObjectRef collectionConstructor = JSObjectMakeConstructor(ctx, RJSCollectionClass(), UncallableConstructor);
RJSValidatedSetProperty(ctx, realmObject, collectionString, collectionConstructor, attributes);
// JSObjectRef collectionConstructor = JSObjectMakeConstructor(ctx, RJSCollectionClass(), UncallableConstructor);
// RJSValidatedSetProperty(ctx, realmObject, collectionString, collectionConstructor, attributes);
JSObjectRef listConstructor = JSObjectMakeConstructor(ctx, RJSListClass(), UncallableConstructor);
RJSValidatedSetProperty(ctx, realmObject, listString, listConstructor, attributes);
// JSObjectRef listConstructor = JSObjectMakeConstructor(ctx, RJSListClass(), UncallableConstructor);
// RJSValidatedSetProperty(ctx, realmObject, listString, listConstructor, attributes);
JSObjectRef resultsContructor = JSObjectMakeConstructor(ctx, RJSResultsClass(), UncallableConstructor);
RJSValidatedSetProperty(ctx, realmObject, resultsString, resultsContructor, attributes);
// JSObjectRef resultsContructor = JSObjectMakeConstructor(ctx, RJSResultsClass(), UncallableConstructor);
// RJSValidatedSetProperty(ctx, realmObject, resultsString, resultsContructor, attributes);
JSObjectRef typesObject = JSObjectMake(ctx, RJSRealmTypeClass(), NULL);
RJSValidatedSetProperty(ctx, realmObject, typeString, typesObject, attributes);
JSObjectRef clearTestStateFunction = JSObjectMakeFunctionWithCallback(ctx, clearTestStateString, ClearTestState);
RJSValidatedSetProperty(ctx, realmObject, clearTestStateString, clearTestStateFunction, attributes);
jsc::Object::set_property(ctx, realmObject, clearTestStateString, clearTestStateFunction, attributes);
return realmObject;
}
void RJSInitializeInContext(JSContextRef ctx) {
static const String nameString = "Realm";
JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
JSObjectRef realmObject = RJSConstructorCreate(ctx);
JSValueRef exception = NULL;
JSStringRef nameString = JSStringCreateWithUTF8CString("Realm");
JSPropertyAttributes attributes = kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete;
JSObjectSetProperty(ctx, globalObject, nameString, realmObject, attributes, &exception);
JSStringRelease(nameString);
assert(!exception);
}

22
src/jsc/jsc_init.hpp Normal file
View File

@ -0,0 +1,22 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "jsc_init.h"
#include "jsc_object_accessor.hpp"

View File

@ -16,7 +16,10 @@
//
////////////////////////////////////////////////////////////////////////////
#include "jsc_class.hpp"
#include "jsc_list.hpp"
#include "jsc_collection.hpp"
#include "jsc_util.hpp"
#include "js_list.hpp"
#include <assert.h>
@ -25,7 +28,7 @@ using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
using namespace realm;
void ListPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) {
List *list = RJSGetInternal<List *>(object);
List *list = js::get_internal<jsc::Types, List>(object);
size_t size = list->size();
char str[32];
@ -37,7 +40,7 @@ void ListPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccum
}
}
using RJSList = realm::js::List<realm::jsc::Types>;
using RJSList = js::List<jsc::Types>;
WRAP_PROPERTY_GETTER(RJSList, GetLength)
WRAP_INDEXED_GETTER(RJSList, GetIndex)
WRAP_INDEXED_SETTER(RJSList, SetIndex)

View File

@ -18,7 +18,7 @@
#pragma once
#include "js_util.hpp"
#include "jsc_types.hpp"
#include "list.hpp"
JSClassRef RJSListClass();

View File

@ -0,0 +1,90 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#include "jsc_object_accessor.hpp"
using namespace realm;
using namespace realm::jsc;
using Accessor = js::NativeAccessor<Types>;
template<>
std::string Accessor::to_binary(JSContextRef ctx, JSValueRef &value) {
static jsc::String s_array_buffer = "ArrayBuffer";
static jsc::String s_buffer = "buffer";
static jsc::String s_byte_length = "byteLength";
static jsc::String s_byte_offset = "byteOffset";
static jsc::String s_is_view = "isView";
static jsc::String s_uint8_array = "Uint8Array";
JSObjectRef global_object = JSContextGetGlobalObject(ctx);
JSObjectRef array_buffer_constructor = jsc::Object::validated_get_constructor(ctx, global_object, s_array_buffer);
JSObjectRef uint8_array_constructor = jsc::Object::validated_get_constructor(ctx, global_object, s_uint8_array);
JSValueRef uint8_array_arguments[3];
uint32_t uint8_array_argc = 0;
// Value should either be an ArrayBuffer or ArrayBufferView (i.e. TypedArray or DataView).
if (JSValueIsInstanceOfConstructor(ctx, value, array_buffer_constructor, nullptr)) {
uint8_array_arguments[0] = value;
uint8_array_argc = 1;
}
else if (JSObjectRef object = JSValueToObject(ctx, value, nullptr)) {
// Check if value is an ArrayBufferView by calling ArrayBuffer.isView(val).
JSValueRef is_view = jsc::Object::call_method(ctx, array_buffer_constructor, s_is_view, 1, &object);
if (jsc::Value::to_boolean(ctx, is_view)) {
uint8_array_arguments[0] = jsc::Object::validated_get_object(ctx, object, s_buffer);
uint8_array_arguments[1] = jsc::Object::get_property(ctx, object, s_byte_offset);
uint8_array_arguments[2] = jsc::Object::get_property(ctx, object, s_byte_length);
uint8_array_argc = 3;
}
}
if (!uint8_array_argc) {
throw std::runtime_error("Can only convert ArrayBuffer and TypedArray objects to binary");
}
JSObjectRef uint8_array = jsc::Function::construct(ctx, uint8_array_constructor, uint8_array_argc, uint8_array_arguments);
uint32_t byte_count = jsc::Object::validated_get_length(ctx, uint8_array);
std::string bytes(byte_count, 0);
for (uint32_t i = 0; i < byte_count; i++) {
JSValueRef byteValue = jsc::Object::get_property(ctx, uint8_array, i);
bytes[i] = jsc::Value::to_number(ctx, byteValue);
}
return bytes;
}
template<>
JSValueRef Accessor::from_binary(JSContextRef ctx, BinaryData data) {
static jsc::String s_buffer = "buffer";
static jsc::String s_uint8_array = "Uint8Array";
size_t byte_count = data.size();
JSValueRef byte_count_value = jsc::Value::from_number(ctx, byte_count);
JSObjectRef uint8_array_constructor = jsc::Object::validated_get_constructor(ctx, JSContextGetGlobalObject(ctx), s_uint8_array);
JSObjectRef uint8_array = jsc::Function::construct(ctx, uint8_array_constructor, 1, &byte_count_value);
for (uint32_t i = 0; i < byte_count; i++) {
JSValueRef num = jsc::Value::from_number(ctx, data[i]);
jsc::Object::set_property(ctx, uint8_array, i, num);
}
return jsc::Object::validated_get_object(ctx, uint8_array, s_buffer);
}

View File

@ -18,34 +18,13 @@
#pragma once
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSStringRef.h>
#include "jsc_class.hpp"
#include "js_object_accessor.hpp"
namespace realm {
namespace jsc {
class String {
public:
String(const char * str) : m_str(JSStringCreateWithUTF8CString(str)) {}
String(const String &other) : m_str(JSStringRetain(other)) {}
~String() { JSStringRelease(m_str); }
operator JSStringRef() const { return m_str; }
// Specialize a native accessor class for JSC.
template<>
class NativeAccessor<jsc::Types::Value, jsc::Types::Context> : public js::NativeAccessor<jsc::Types> {};
private:
JSStringRef m_str;
};
struct Types {
using Context = JSContextRef;
using GlobalContext = JSGlobalContextRef;
using ObjectClass = JSClassRef;
using Value = JSValueRef;
using Object = JSObjectRef;
using String = jsc::String;
using Function = JSObjectRef;
using Return = JSValueRef;
using Exception = JSValueRef;
};
}}
} // realm

View File

@ -16,12 +16,14 @@
//
////////////////////////////////////////////////////////////////////////////
#include "jsc_class.hpp"
#include "jsc_realm.hpp"
#include "js_realm.hpp"
#include "js_object.hpp"
#include "js_results.hpp"
#include "jsc_list.hpp"
#include "js_schema.hpp"
#include "jsc_util.hpp"
#include "platform.hpp"
#include "shared_realm.hpp"
@ -79,8 +81,8 @@ WRAP_PROPERTY_GETTER(RJSRealm, GetPath)
WRAP_PROPERTY_GETTER(RJSRealm, GetSchemaVersion)
static const JSStaticValue RealmStaticProperties[] = {
{"path", RJSRealmGetPath, RJSRealmSetDefaultPath, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"schemaVersion", RJSRealmGetSchemaVersion, RJSRealmSetDefaultPath, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"path", RJSRealmGetPath, NULL, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"schemaVersion", RJSRealmGetSchemaVersion, NULL, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{NULL, NULL}
};

View File

@ -18,7 +18,7 @@
#pragma once
#include "types.hpp"
#include "jsc_types.hpp"
JSClassRef RJSRealmClass();
JSClassRef RJSRealmConstructorClass();

502
src/jsc/jsc_types.hpp Normal file
View File

@ -0,0 +1,502 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSStringRef.h>
#include <realm/util/to_string.hpp>
#include "js_types.hpp"
namespace realm {
namespace jsc {
struct Types {
using Context = JSContextRef;
using GlobalContext = JSGlobalContextRef;
using ObjectClass = JSClassRef;
using Value = JSValueRef;
using Object = JSObjectRef;
using String = JSStringRef;
using Function = JSObjectRef;
using ConstructorCallback = JSObjectCallAsConstructorCallback;
using FunctionCallback = JSObjectCallAsFunctionCallback;
using PropertyGetterCallback = JSObjectGetPropertyCallback;
using PropertySetterCallback = JSObjectSetPropertyCallback;
using IndexPropertyGetterCallback = JSValueRef(JSContextRef, JSObjectRef, uint32_t, JSValueRef*);
using IndexPropertySetterCallback = bool(JSContextRef, JSObjectRef, uint32_t, JSValueRef, JSValueRef*);
using StringPropertyGetterCallback = JSObjectGetPropertyCallback;
using StringPropertySetterCallback = JSObjectSetPropertyCallback;
};
template<typename T>
class Protected {
const T m_value;
public:
Protected(T value) : m_value(value) {}
operator T() const {
return m_value;
}
bool operator==(const T &other) const {
return m_value == other;
}
bool operator!=(const T &other) const {
return m_value != other;
}
bool operator==(const Protected<T> &other) const {
return m_value == other;
}
bool operator!=(const Protected<T> &other) const {
return m_value != other;
}
bool operator<(const Protected<T> &other) const {
return m_value < other.m_value;
}
};
template<typename T>
class ObjectWrap;
using String = js::String<Types>;
using Context = js::Context<Types>;
using Value = js::Value<Types>;
using Function = js::Function<Types>;
using Object = js::Object<Types>;
using Exception = js::Exception<Types>;
using ReturnValue = js::ReturnValue<Types>;
} // jsc
namespace js {
template<>
class String<jsc::Types> {
const JSStringRef m_str;
public:
String(const char *s) : m_str(JSStringCreateWithUTF8CString(s)) {}
String(const JSStringRef &s) : m_str(JSStringRetain(s)) {}
String(JSStringRef &&s) : m_str(s) {}
String(const std::string &str) : String(str.c_str()) {}
~String() { JSStringRelease(m_str); }
operator JSStringRef() const {
return m_str;
}
operator std::string() const {
size_t max_size = JSStringGetMaximumUTF8CStringSize(m_str);
std::string string;
string.resize(max_size);
string.resize(JSStringGetUTF8CString(m_str, &string[0], max_size) - 1);
return string;
}
};
template<>
class ReturnValue<jsc::Types> {
const JSContextRef m_context;
JSValueRef m_value = nullptr;
public:
ReturnValue(JSContextRef ctx) : m_context(ctx) {}
void set(const JSValueRef &value) {
m_value = value;
}
void set(const std::string &string) {
m_value = JSValueMakeString(m_context, jsc::String(string));
}
void set(bool boolean) {
m_value = JSValueMakeBoolean(m_context, boolean);
}
void set(double number) {
m_value = JSValueMakeNumber(m_context, number);
}
void set(int32_t number) {
m_value = JSValueMakeNumber(m_context, number);
}
void set(uint32_t number) {
m_value = JSValueMakeNumber(m_context, number);
}
void set_null() {
m_value = JSValueMakeNull(m_context);
}
void set_undefined() {
m_value = JSValueMakeUndefined(m_context);
}
operator JSValueRef() const {
return m_value;
}
};
template<>
class Protected<JSGlobalContextRef> : public jsc::Protected<JSGlobalContextRef> {
public:
Protected(JSGlobalContextRef ctx) : jsc::Protected<JSGlobalContextRef>(ctx) {
JSGlobalContextRetain(*this);
}
~Protected() {
JSGlobalContextRelease(*this);
}
};
template<>
class Protected<JSValueRef> : public jsc::Protected<JSValueRef> {
const JSGlobalContextRef m_context;
public:
Protected(JSContextRef ctx, JSValueRef value) : jsc::Protected<JSValueRef>(value), m_context(JSContextGetGlobalContext(ctx)) {
JSValueProtect(m_context, *this);
}
~Protected() {
JSValueUnprotect(m_context, *this);
}
};
template<>
class Protected<JSObjectRef> : public Protected<JSValueRef> {
public:
Protected(JSContextRef ctx, JSObjectRef object) : Protected<JSValueRef>(ctx, object) {}
operator JSObjectRef() const {
return static_cast<JSObjectRef>(*this);
}
};
static inline bool is_object_of_type(JSContextRef ctx, JSValueRef value, jsc::String type) {
JSObjectRef global_object = JSContextGetGlobalObject(ctx);
JSValueRef exception = nullptr;
JSValueRef constructor = JSObjectGetProperty(ctx, global_object, type, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
bool result = JSValueIsInstanceOfConstructor(ctx, value, jsc::Value::validated_to_constructor(ctx, constructor), &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
return result;
}
template<>
inline JSGlobalContextRef jsc::Context::get_global_context(JSContextRef ctx) {
return JSContextGetGlobalContext(ctx);
}
template<>
inline bool jsc::Value::is_array(JSContextRef ctx, const JSValueRef &value) {
// JSValueIsArray() is not available until iOS 9.
static const jsc::String type = "Array";
return is_object_of_type(ctx, value, type);
}
template<>
inline bool jsc::Value::is_array_buffer(JSContextRef ctx, const JSValueRef &value) {
static const jsc::String type = "ArrayBuffer";
return is_object_of_type(ctx, value, type);
}
template<>
inline bool jsc::Value::is_date(JSContextRef ctx, const JSValueRef &value) {
static const jsc::String type = "Date";
return is_object_of_type(ctx, value, type);
}
template<>
inline bool jsc::Value::is_boolean(JSContextRef ctx, const JSValueRef &value) {
return JSValueIsBoolean(ctx, value);
}
template<>
inline bool jsc::Value::is_constructor(JSContextRef ctx, const JSValueRef &value) {
return JSValueIsObject(ctx, value) && JSObjectIsConstructor(ctx, (JSObjectRef)value);
}
template<>
inline bool jsc::Value::is_function(JSContextRef ctx, const JSValueRef &value) {
return JSValueIsObject(ctx, value) && JSObjectIsFunction(ctx, (JSObjectRef)value);
}
template<>
inline bool jsc::Value::is_null(JSContextRef ctx, const JSValueRef &value) {
return JSValueIsNull(ctx, value);
}
template<>
inline bool jsc::Value::is_number(JSContextRef ctx, const JSValueRef &value) {
return JSValueIsNumber(ctx, value);
}
template<>
inline bool jsc::Value::is_object(JSContextRef ctx, const JSValueRef &value) {
return JSValueIsObject(ctx, value);
}
template<>
inline bool jsc::Value::is_string(JSContextRef ctx, const JSValueRef &value) {
return JSValueIsString(ctx, value);
}
template<>
inline bool jsc::Value::is_undefined(JSContextRef ctx, const JSValueRef &value) {
return JSValueIsUndefined(ctx, value);
}
template<>
inline bool jsc::Value::is_valid(const JSValueRef &value) {
return value != nullptr;
}
template<>
JSValueRef jsc::Value::from_boolean(JSContextRef ctx, bool boolean) {
return JSValueMakeBoolean(ctx, boolean);
}
template<>
JSValueRef jsc::Value::from_null(JSContextRef ctx) {
return JSValueMakeNull(ctx);
}
template<>
JSValueRef jsc::Value::from_number(JSContextRef ctx, double number) {
return JSValueMakeNumber(ctx, number);
}
template<>
JSValueRef jsc::Value::from_string(JSContextRef ctx, const jsc::String &string) {
return JSValueMakeString(ctx, string);
}
template<>
JSValueRef jsc::Value::from_undefined(JSContextRef ctx) {
return JSValueMakeUndefined(ctx);
}
template<>
inline bool jsc::Value::to_boolean(JSContextRef ctx, const JSValueRef &value) {
return JSValueToBoolean(ctx, value);
}
template<>
inline double jsc::Value::to_number(JSContextRef ctx, const JSValueRef &value) {
JSValueRef exception = nullptr;
double number = JSValueToNumber(ctx, value, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
if (isnan(number)) {
throw std::invalid_argument("Value not convertible to a number.");
}
return number;
}
template<>
inline jsc::String jsc::Value::to_string(JSContextRef ctx, const JSValueRef &value) {
JSValueRef exception = nullptr;
jsc::String string = JSValueToStringCopy(ctx, value, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
return string;
}
template<>
inline JSObjectRef jsc::Value::to_object(JSContextRef ctx, const JSValueRef &value) {
JSValueRef exception = nullptr;
JSObjectRef object = JSValueToObject(ctx, value, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
return object;
}
template<>
inline JSObjectRef jsc::Value::to_array(JSContextRef ctx, const JSValueRef &value) {
return to_object(ctx, value);
}
template<>
inline JSObjectRef jsc::Value::to_constructor(JSContextRef ctx, const JSValueRef &value) {
return to_object(ctx, value);
}
template<>
inline JSObjectRef jsc::Value::to_date(JSContextRef ctx, const JSValueRef &value) {
return to_object(ctx, value);
}
template<>
inline JSObjectRef jsc::Value::to_function(JSContextRef ctx, const JSValueRef &value) {
return to_object(ctx, value);
}
template<>
inline JSValueRef jsc::Function::call(JSContextRef ctx, const JSObjectRef &function, const JSObjectRef &this_object, uint32_t argc, const JSValueRef arguments[]) {
JSValueRef exception = nullptr;
JSValueRef result = JSObjectCallAsFunction(ctx, function, this_object, argc, arguments, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
return result;
}
template<>
inline JSObjectRef jsc::Function::construct(JSContextRef ctx, const JSObjectRef &function, uint32_t argc, const JSValueRef arguments[]) {
JSValueRef exception = nullptr;
JSObjectRef result = JSObjectCallAsConstructor(ctx, function, argc, arguments, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
return result;
}
template<>
inline bool jsc::Object::has_property(JSContextRef ctx, const JSObjectRef &object, const jsc::String &key) {
return JSObjectHasProperty(ctx, object, key);
}
template<>
inline bool jsc::Object::has_property(JSContextRef ctx, const JSObjectRef &object, uint32_t index) {
return JSObjectHasProperty(ctx, object, jsc::String(util::to_string(index)));
}
template<>
inline JSValueRef jsc::Object::get_property(JSContextRef ctx, const JSObjectRef &object, const jsc::String &key) {
JSValueRef exception = nullptr;
JSValueRef value = JSObjectGetProperty(ctx, object, key, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
return value;
}
template<>
inline JSValueRef jsc::Object::get_property(JSContextRef ctx, const JSObjectRef &object, uint32_t index) {
JSValueRef exception = nullptr;
JSValueRef value = JSObjectGetPropertyAtIndex(ctx, object, index, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
return value;
}
template<>
inline void jsc::Object::set_property(JSContextRef ctx, const JSObjectRef &object, const jsc::String &key, const JSValueRef &value, PropertyAttributes attributes) {
JSValueRef exception = nullptr;
JSObjectSetProperty(ctx, object, key, value, attributes << 1, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
}
template<>
inline void jsc::Object::set_property(JSContextRef ctx, const JSObjectRef &object, uint32_t index, const JSValueRef &value) {
JSValueRef exception = nullptr;
JSObjectSetPropertyAtIndex(ctx, object, index, value, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
}
template<>
inline std::vector<jsc::String> jsc::Object::get_property_names(JSContextRef ctx, const JSObjectRef &object) {
JSPropertyNameArrayRef property_names = JSObjectCopyPropertyNames(ctx, object);
size_t property_count = JSPropertyNameArrayGetCount(property_names);
std::vector<jsc::String> names;
names.reserve(property_count);
for (size_t i = 0; i < property_count; i++) {
names.push_back(JSPropertyNameArrayGetNameAtIndex(property_names, i));
}
JSPropertyNameArrayRelease(property_names);
return names;
}
template<>
inline JSValueRef jsc::Object::get_prototype(JSContextRef ctx, const JSObjectRef &object) {
return JSObjectGetPrototype(ctx, object);
}
template<>
inline void jsc::Object::set_prototype(JSContextRef ctx, const JSObjectRef &object, const JSValueRef &prototype) {
JSObjectSetPrototype(ctx, object, prototype);
}
template<>
inline JSObjectRef jsc::Object::create_empty(JSContextRef ctx) {
return JSObjectMake(ctx, nullptr, nullptr);
}
template<>
inline JSObjectRef jsc::Object::create_array(JSContextRef ctx, uint32_t length, const JSValueRef values[]) {
JSValueRef exception = nullptr;
JSObjectRef array = JSObjectMakeArray(ctx, length, values, &exception);
if (exception) {
throw jsc::Exception(ctx, exception);
}
return array;
}
template<>
inline JSObjectRef jsc::Object::create_date(JSContextRef ctx, double time) {
JSValueRef number = jsc::Value::from_number(ctx, time);
return JSObjectMakeDate(ctx, 1, &number, nullptr);
}
template<>
template<typename U>
inline JSObjectRef jsc::Object::create(JSContextRef ctx, U* internal) {
return jsc::ObjectWrap<U>::create(ctx, internal);
}
template<>
template<typename U>
inline bool jsc::Object::is_instance(JSContextRef ctx, const JSObjectRef &object) {
return jsc::ObjectWrap<U>::has_instance(ctx, object);
}
template<>
template<typename U>
inline U* jsc::Object::get_internal(const JSObjectRef &object) {
return *static_cast<jsc::ObjectWrap<U> *>(JSObjectGetPrivate(object));
}
template<>
template<typename U>
inline void jsc::Object::set_internal(const JSObjectRef &object, U* ptr) {
auto wrap = static_cast<jsc::ObjectWrap<U> *>(JSObjectGetPrivate(object));
*wrap = ptr;
}
template<>
inline JSValueRef jsc::Exception::value(JSContextRef ctx, const std::string &message) {
JSValueRef value = jsc::Value::from_string(ctx, message);
return JSObjectMakeError(ctx, 1, &value, NULL);
}
} // js
} // realm

View File

@ -18,21 +18,73 @@
#pragma once
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSStringRef.h>
#include <math.h>
#include <string>
#include <sstream>
#include <stdexcept>
#include <cmath>
#include "jsc_types.hpp"
#include "property.hpp"
#include "schema.hpp"
namespace realm {
namespace js {
#define WRAP_EXCEPTION(METHOD, EXCEPTION, ARGS...) \
try { METHOD(ARGS); } \
catch(std::exception &e) { RJSSetException(ctx, EXCEPTION, e); }
#define WRAP_CLASS_METHOD(CLASS_NAME, METHOD_NAME) \
JSValueRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* ex) { \
JSValueRef returnValue = NULL; \
WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, thisObject, argumentCount, arguments, returnValue); \
return returnValue; \
}
#define WRAP_CONSTRUCTOR(CLASS_NAME, METHOD_NAME) \
JSObjectRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* ex) { \
JSObjectRef returnObject = NULL; \
WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, constructor, argumentCount, arguments, returnObject); \
return returnObject; \
}
#define WRAP_PROPERTY_GETTER(CLASS_NAME, METHOD_NAME) \
JSValueRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* ex) { \
JSValueRef returnValue = NULL; \
WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, object, property, returnValue); \
return returnValue; \
}
#define WRAP_PROPERTY_SETTER(CLASS_NAME, METHOD_NAME) \
bool CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef* ex) { \
WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, object, property, value); \
return true; \
}
// for stol failure (std::invalid_argument) this could be another property that is handled externally, so ignore
#define WRAP_INDEXED_GETTER(CLASS_NAME, METHOD_NAME) \
JSValueRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* ex) { \
JSValueRef returnValue = NULL; \
try { \
size_t index = RJSValidatedPositiveIndex(RJSStringForJSString(property)); \
CLASS_NAME::METHOD_NAME(ctx, object, index, returnValue); return returnValue; \
} \
catch (std::out_of_range &exp) { return JSValueMakeUndefined(ctx); } \
catch (std::invalid_argument &exp) { return NULL; } \
catch (std::exception &e) { RJSSetException(ctx, *ex, e); return NULL; } \
}
#define WRAP_INDEXED_SETTER(CLASS_NAME, METHOD_NAME) \
bool CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef* ex) { \
try { \
size_t index = RJSValidatedPositiveIndex(RJSStringForJSString(property)); \
{ CLASS_NAME::METHOD_NAME(ctx, object, index, value); return true; } \
} \
catch (std::out_of_range &exp) { RJSSetException(ctx, *ex, exp); } \
catch (std::invalid_argument &exp) { *ex = RJSMakeError(ctx, "Invalid index"); } \
catch (std::exception &e) { RJSSetException(ctx, *ex, e); } \
return false; \
}
template<typename T>
inline void RJSFinalize(JSObjectRef object) {
@ -40,15 +92,6 @@ inline void RJSFinalize(JSObjectRef object) {
JSObjectSetPrivate(object, NULL);
}
template<typename T>
inline JSObjectRef RJSWrapObject(JSContextRef ctx, JSClassRef jsClass, T object, JSValueRef prototype = NULL) {
JSObjectRef ref = JSObjectMake(ctx, jsClass, (void *)object);
if (prototype) {
JSObjectSetPrototype(ctx, ref, prototype);
}
return ref;
}
template<typename T>
inline T RJSGetInternal(JSObjectRef jsObject) {
return static_cast<T>(JSObjectGetPrivate(jsObject));
@ -56,7 +99,7 @@ inline T RJSGetInternal(JSObjectRef jsObject) {
template<typename T>
JSClassRef RJSCreateWrapperClass(const char * name, JSObjectGetPropertyCallback getter = NULL, JSObjectSetPropertyCallback setter = NULL, const JSStaticFunction *funcs = NULL,
JSObjectGetPropertyNamesCallback propertyNames = NULL, JSClassRef parentClass = NULL) {
JSObjectGetPropertyNamesCallback propertyNames = NULL, JSClassRef parentClass = NULL, const JSStaticValue *values = NULL) {
JSClassDefinition classDefinition = kJSClassDefinitionEmpty;
classDefinition.className = name;
classDefinition.finalize = RJSFinalize<T>;
@ -65,6 +108,7 @@ JSClassRef RJSCreateWrapperClass(const char * name, JSObjectGetPropertyCallback
classDefinition.staticFunctions = funcs;
classDefinition.getPropertyNames = propertyNames;
classDefinition.parentClass = parentClass;
classDefinition.staticValues = values;
return JSClassCreate(&classDefinition);
}
@ -75,24 +119,6 @@ std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const
JSStringRef RJSStringForString(const std::string &str);
JSValueRef RJSValueForString(JSContextRef ctx, const std::string &str);
inline void RJSValidateArgumentCount(size_t argumentCount, size_t expected, const char *message = NULL) {
if (argumentCount != expected) {
throw std::invalid_argument(message ?: "Invalid arguments");
}
}
inline void RJSValidateArgumentCountIsAtLeast(size_t argumentCount, size_t expected, const char *message = NULL) {
if (argumentCount < expected) {
throw std::invalid_argument(message ?: "Invalid arguments");
}
}
inline void RJSValidateArgumentRange(size_t argumentCount, size_t min, size_t max, const char *message = NULL) {
if (argumentCount < min || argumentCount > max) {
throw std::invalid_argument(message ?: "Invalid arguments");
}
}
class RJSException : public std::runtime_error {
public:
RJSException(JSContextRef ctx, JSValueRef &ex) : std::runtime_error(RJSStringForValue(ctx, ex)),
@ -111,7 +137,7 @@ bool RJSIsValueArray(JSContextRef ctx, JSValueRef value);
bool RJSIsValueArrayBuffer(JSContextRef ctx, JSValueRef value);
bool RJSIsValueDate(JSContextRef ctx, JSValueRef value);
static inline JSObjectRef RJSValidatedValueToObject(JSContextRef ctx, JSValueRef value, const char *message = NULL) {
static inline JSObjectRef RJSValidatedValueToObject(JSContextRef ctx, JSValueRef value, const char *message = nullptr) {
JSObjectRef object = JSValueToObject(ctx, value, NULL);
if (!object) {
throw std::runtime_error(message ?: "Value is not an object.");
@ -119,7 +145,7 @@ static inline JSObjectRef RJSValidatedValueToObject(JSContextRef ctx, JSValueRef
return object;
}
static inline JSObjectRef RJSValidatedValueToDate(JSContextRef ctx, JSValueRef value, const char *message = NULL) {
static inline JSObjectRef RJSValidatedValueToDate(JSContextRef ctx, JSValueRef value, const char *message = nullptr) {
JSObjectRef object = JSValueToObject(ctx, value, NULL);
if (!object || !RJSIsValueDate(ctx, object)) {
throw std::runtime_error(message ?: "Value is not a date.");
@ -127,7 +153,7 @@ static inline JSObjectRef RJSValidatedValueToDate(JSContextRef ctx, JSValueRef v
return object;
}
static inline JSObjectRef RJSValidatedValueToFunction(JSContextRef ctx, JSValueRef value, const char *message = NULL) {
static inline JSObjectRef RJSValidatedValueToFunction(JSContextRef ctx, JSValueRef value, const char *message = nullptr) {
JSObjectRef object = JSValueToObject(ctx, value, NULL);
if (!object || !JSObjectIsFunction(ctx, object)) {
throw std::runtime_error(message ?: "Value is not a function.");
@ -151,6 +177,13 @@ static inline double RJSValidatedValueToNumber(JSContextRef ctx, JSValueRef valu
return number;
}
static inline double RJSValidatedValueToBoolean(JSContextRef ctx, JSValueRef value, const char *err = nullptr) {
if (!JSValueIsBoolean(ctx, value)) {
throw std::invalid_argument(err ?: "Value is not a boolean.");
}
return JSValueToBoolean(ctx, value);
}
static inline JSValueRef RJSValidatedPropertyValue(JSContextRef ctx, JSObjectRef object, JSStringRef property) {
JSValueRef exception = NULL;
JSValueRef propertyValue = JSObjectGetProperty(ctx, object, property, &exception);
@ -169,7 +202,7 @@ static inline JSValueRef RJSValidatedPropertyAtIndex(JSContextRef ctx, JSObjectR
return propertyValue;
}
static inline JSObjectRef RJSValidatedObjectProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property, const char *err = NULL) {
static inline JSObjectRef RJSValidatedObjectProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property, const char *err = nullptr) {
JSValueRef propertyValue = RJSValidatedPropertyValue(ctx, object, property);
if (JSValueIsUndefined(ctx, propertyValue)) {
throw std::runtime_error(err ?: "Object property '" + RJSStringForJSString(property) + "' is undefined");
@ -248,4 +281,23 @@ static inline bool RJSIsValueObjectOfType(JSContextRef ctx, JSValueRef value, JS
return ret;
}
}}
static inline void RJSSetReturnUndefined(JSContextRef ctx, JSValueRef &returnObject) {
returnObject = JSValueMakeUndefined(ctx);
}
template<typename T>
static inline void RJSSetReturnNumber(JSContextRef ctx, JSValueRef &returnObject, T number) {
returnObject = JSValueMakeNumber(ctx, number);
}
static inline void RJSSetReturnArray(JSContextRef ctx, size_t count, const JSValueRef *objects, JSValueRef &returnObject) {
returnObject = JSObjectMakeArray(ctx, count, objects, NULL);
}
static inline void RJSSetException(JSContextRef ctx, JSValueRef &exceptionObject, std::exception &exception) {
exceptionObject = RJSMakeError(ctx, exception);
}
static bool RJSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) {
return JSValueIsObjectOfClass(ctx, value, jsClass);
}

278
src/node/node_class.hpp Normal file
View File

@ -0,0 +1,278 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "node_types.hpp"
#include "js_class.hpp"
namespace realm {
namespace node {
template<typename T>
using ObjectClass = js::ObjectClass<Types, T>;
using ConstructorType = js::ConstructorType<Types>;
using MethodType = js::MethodType<Types>;
using PropertyGetterType = js::PropertyGetterType<Types>;
using PropertySetterType = js::PropertySetterType<Types>;
using IndexPropertyGetterType = js::IndexPropertyGetterType<Types>;
using IndexPropertySetterType = js::IndexPropertySetterType<Types>;
using StringPropertyGetterType = js::StringPropertyGetterType<Types>;
using StringPropertySetterType = js::StringPropertySetterType<Types>;
using StringPropertyEnumeratorType = js::StringPropertyEnumeratorType<Types>;
using PropertyType = js::PropertyType<Types>;
static inline std::vector<v8::Local<v8::Value>> get_arguments(const Nan::FunctionCallbackInfo<v8::Value> &info) {
int count = info.Length();
std::vector<v8::Local<v8::Value>> arguments;
arguments.reserve(count);
for (int i = 0; i < count; i++) {
arguments.push_back(info[i]);
}
return arguments;
}
static inline void setup_method(v8::Local<v8::FunctionTemplate> tpl, const std::string &name, Nan::FunctionCallback callback) {
Nan::HandleScope scope;
v8::Local<v8::Signature> signature = Nan::New<v8::Signature>(tpl);
v8::Local<v8::FunctionTemplate> t = Nan::New<v8::FunctionTemplate>(callback, v8::Local<v8::Value>(), signature);
v8::Local<v8::Function> fn = Nan::GetFunction(t).ToLocalChecked();
v8::Local<v8::String> fn_name = Nan::New(name).ToLocalChecked();
// The reason we use this rather than Nan::SetPrototypeMethod is DontEnum.
tpl->PrototypeTemplate()->Set(fn_name, fn, v8::PropertyAttribute::DontEnum);
fn->SetName(fn_name);
}
static inline void setup_property(v8::Local<v8::ObjectTemplate> tpl, const std::string &name, const PropertyType &property) {
Nan::HandleScope scope;
v8::Local<v8::String> prop_name = Nan::New(name).ToLocalChecked();
v8::PropertyAttribute attributes = static_cast<v8::PropertyAttribute>(v8::DontEnum | v8::DontDelete | (property.setter ? v8::None : v8::ReadOnly));
Nan::SetAccessor(tpl, prop_name, property.getter, property.setter, v8::Local<v8::Value>(), v8::DEFAULT, attributes);
}
template<typename T>
class ObjectWrap : public Nan::ObjectWrap {
static ObjectClass<T> s_class;
static Nan::Persistent<v8::Function> s_constructor;
static Nan::Persistent<v8::FunctionTemplate> s_template;
std::unique_ptr<T> m_object;
ObjectWrap(T* object = nullptr) : m_object(object) {}
public:
operator T*() const {
return m_object.get();
}
ObjectWrap<T>& operator=(T* object) {
if (m_object.get() != object) {
m_object = std::unique_ptr<T>(object);
}
return *this;
}
static v8::Local<v8::Object> create(v8::Isolate* isolate, T* internal = nullptr) {
Nan::EscapableHandleScope scope;
// TODO: Figure out why this template ends up being empty here.
v8::Local<v8::FunctionTemplate> tpl = Nan::New(s_template);
v8::Local<v8::Object> instance = Nan::NewInstance(tpl->InstanceTemplate()).ToLocalChecked();
auto wrap = new ObjectWrap<T>(internal);
wrap->Wrap(instance);
return scope.Escape(instance);
}
static bool has_instance(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return Nan::New(s_template)->HasInstance(value);
}
static NAN_MODULE_INIT(init) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(construct);
v8::Local<v8::ObjectTemplate> instance_tpl = tpl->InstanceTemplate();
v8::Local<v8::String> name = Nan::New(s_class.name).ToLocalChecked();
tpl->SetClassName(name);
instance_tpl->SetInternalFieldCount(1);
// TODO: Setup static properties and methods.
for (auto &pair : s_class.methods) {
setup_method(tpl, pair.first, pair.second);
}
for (auto &pair : s_class.properties) {
setup_property(instance_tpl, pair.first, pair.second);
}
if (s_class.index_accessor.getter) {
// TODO: Add our own index enumerator.
auto &index_accessor = s_class.index_accessor;
Nan::SetIndexedPropertyHandler(instance_tpl, index_accessor.getter, index_accessor.setter);
}
if (s_class.string_accessor.getter) {
auto &string_accessor = s_class.string_accessor;
Nan::SetNamedPropertyHandler(instance_tpl, string_accessor.getter, string_accessor.setter, 0, 0, string_accessor.enumerator);
}
v8::Local<v8::Function> constructor = Nan::GetFunction(tpl).ToLocalChecked();
s_constructor.Reset(constructor);
s_template.Reset(tpl);
Nan::Set(target, name, constructor);
}
static NAN_METHOD(construct) {
if (!info.IsConstructCall()) {
Nan::ThrowError("Constructor must be called with new");
}
if (s_class.constructor) {
auto isolate = info.GetIsolate();
auto arguments = get_arguments(info);
v8::Local<v8::Object> this_object = info.This();
info.GetReturnValue().Set(this_object);
auto wrap = new ObjectWrap<T>();
wrap->Wrap(this_object);
try {
s_class.constructor(isolate, this_object, arguments.size(), arguments.data());
}
catch(std::exception &e) {
Nan::ThrowError(node::Exception::value(isolate, e));
}
}
else {
Nan::ThrowError("Illegal constructor");
}
}
};
// The declared static variables must be defined as well.
template<typename T> ObjectClass<T> ObjectWrap<T>::s_class;
template<typename T> Nan::Persistent<v8::Function> ObjectWrap<T>::s_constructor;
template<typename T> Nan::Persistent<v8::FunctionTemplate> ObjectWrap<T>::s_template;
} // node
namespace js {
template<node::MethodType F>
void wrap(Nan::NAN_METHOD_ARGS_TYPE info) {
v8::Isolate* isolate = info.GetIsolate();
node::ReturnValue return_value(info.GetReturnValue());
auto arguments = node::get_arguments(info);
try {
F(isolate, info.This(), arguments.size(), arguments.data(), return_value);
}
catch(std::exception &e) {
Nan::ThrowError(node::Exception::value(isolate, e));
}
}
template<node::PropertyGetterType F>
void wrap(v8::Local<v8::String> property, Nan::NAN_GETTER_ARGS_TYPE info) {
v8::Isolate* isolate = info.GetIsolate();
node::ReturnValue return_value(info.GetReturnValue());
try {
F(isolate, info.This(), return_value);
}
catch(std::exception &e) {
Nan::ThrowError(node::Exception::value(isolate, e));
}
}
template<node::PropertySetterType F>
void wrap(v8::Local<v8::String> property, v8::Local<v8::Value> value, Nan::NAN_SETTER_ARGS_TYPE info) {
v8::Isolate* isolate = info.GetIsolate();
try {
F(isolate, info.This(), value);
}
catch(std::exception &e) {
Nan::ThrowError(node::Exception::value(isolate, e));
}
}
template<node::IndexPropertyGetterType F>
void wrap(uint32_t index, Nan::NAN_INDEX_GETTER_ARGS_TYPE info) {
v8::Isolate* isolate = info.GetIsolate();
node::ReturnValue return_value(info.GetReturnValue());
try {
F(isolate, info.This(), index, return_value);
}
catch(std::exception &e) {
Nan::ThrowError(node::Exception::value(isolate, e));
}
}
template<node::IndexPropertySetterType F>
void wrap(uint32_t index, v8::Local<v8::Value> value, Nan::NAN_INDEX_SETTER_ARGS_TYPE info) {
v8::Isolate* isolate = info.GetIsolate();
try {
F(isolate, info.This(), index, value);
}
catch(std::exception &e) {
Nan::ThrowError(node::Exception::value(isolate, e));
}
}
template<node::StringPropertyGetterType F>
void wrap(v8::Local<v8::String> property, Nan::NAN_PROPERTY_GETTER_ARGS_TYPE info) {
v8::Isolate* isolate = info.GetIsolate();
node::ReturnValue return_value(info.GetReturnValue());
try {
F(isolate, info.This(), property, return_value);
}
catch(std::exception &e) {
Nan::ThrowError(node::Exception::value(isolate, e));
}
}
template<node::StringPropertySetterType F>
void wrap(v8::Local<v8::String> property, v8::Local<v8::Value> value, Nan::NAN_PROPERTY_SETTER_ARGS_TYPE info) {
v8::Isolate* isolate = info.GetIsolate();
try {
F(isolate, info.This(), property, value);
}
catch(std::exception &e) {
Nan::ThrowError(node::Exception::value(isolate, e));
}
}
template<node::StringPropertyEnumeratorType F>
void wrap(Nan::NAN_PROPERTY_ENUMERATOR_ARGS_TYPE info) {
auto names = F(info.GetIsolate(), info.This());
int count = (int)names.size();
v8::Local<v8::Array> array = Nan::New<v8::Array>(count);
for (int i = 0; i < count; i++) {
Nan::Set(array, i, v8::Local<v8::String>(names[i]));
}
info.GetReturnValue().Set(array);
}
} // js
} // realm

19
src/node/node_dummy.c Normal file
View File

@ -0,0 +1,19 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
void node_module_register(void* mod) {}

39
src/node/node_init.cpp Normal file
View File

@ -0,0 +1,39 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#include "node_init.hpp"
#include "js_realm.hpp"
#include "js_list.hpp"
namespace realm {
namespace node {
static void init(v8::Local<v8::Object> exports) {
ObjectWrap<SharedRealm>::init(exports);
ObjectWrap<realm::List>::init(exports);
// RealmObjectWrap::Init(exports);
// RealmResultsWrap::Init(exports);
// RealmListWrap::Init(exports);
//
// NODE_SET_METHOD(exports, "__clearCaches", ClearCaches);
}
} // node
} // realm
NODE_MODULE(Realm, realm::node::init);

21
src/node/node_init.hpp Normal file
View File

@ -0,0 +1,21 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "node_object_accessor.hpp"

View File

@ -0,0 +1,36 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#include "node_object_accessor.hpp"
using namespace realm;
using namespace realm::node;
using Accessor = js::NativeAccessor<Types>;
template<>
std::string Accessor::to_binary(v8::Isolate* isolate, v8::Local<v8::Value> &value) {
// TODO
return std::string();
}
template<>
v8::Local<v8::Value> Accessor::from_binary(v8::Isolate* isolate, BinaryData data) {
// TODO
return v8::Local<v8::Value>();
}

View File

@ -0,0 +1,30 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "node_class.hpp"
#include "js_object_accessor.hpp"
namespace realm {
// Specialize a native accessor class for Node.
template<>
class NativeAccessor<node::Types::Value, node::Types::Context> : public js::NativeAccessor<node::Types> {};
} // realm

473
src/node/node_types.hpp Normal file
View File

@ -0,0 +1,473 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include <cmath>
#include <functional>
#include <map>
#include <string>
#include <nan.h>
#include "js_types.hpp"
namespace realm {
namespace node {
struct Types {
using Context = v8::Isolate*;
using GlobalContext = v8::Local<v8::Context>;
using Value = v8::Local<v8::Value>;
using Object = v8::Local<v8::Object>;
using String = v8::Local<v8::String>;
using Function = v8::Local<v8::Function>;
using ConstructorCallback = Nan::FunctionCallback;
using FunctionCallback = Nan::FunctionCallback;
using PropertyGetterCallback = Nan::GetterCallback;
using PropertySetterCallback = Nan::SetterCallback;
using IndexPropertyGetterCallback = Nan::IndexGetterCallback;
using IndexPropertySetterCallback = Nan::IndexSetterCallback;
using StringPropertyGetterCallback = Nan::PropertyGetterCallback;
using StringPropertySetterCallback = Nan::PropertySetterCallback;
using StringPropertyEnumeratorCallback = Nan::PropertyEnumeratorCallback;
};
template<typename T>
class Protected {
// TODO: Figure out why Nan::CopyablePersistentTraits causes a build failure.
Nan::Persistent<T, v8::CopyablePersistentTraits<T>> m_value;
public:
Protected(v8::Local<T> value) : m_value(value) {}
operator v8::Local<T>() const {
return Nan::New(m_value);
}
bool operator==(const v8::Local<T> &other) const {
return m_value == other;
}
bool operator!=(const v8::Local<T> &other) const {
return m_value != other;
}
bool operator==(const Protected<T> &other) const {
return m_value == other.m_value;
}
bool operator!=(const Protected<T> &other) const {
return m_value != other.m_value;
}
bool operator<(const Protected<T> &other) const {
return *Nan::New(m_value) < *Nan::New(other.m_value);
}
};
template<typename T>
class ObjectWrap;
using String = js::String<Types>;
using Context = js::Context<Types>;
using Value = js::Value<Types>;
using Function = js::Function<Types>;
using Object = js::Object<Types>;
using Exception = js::Exception<Types>;
using ReturnValue = js::ReturnValue<Types>;
} // node
namespace js {
template<>
class String<node::Types> {
std::string m_str;
public:
String(const char* s) : m_str(s) {}
String(const std::string &s) : m_str(s) {}
String(const v8::Local<v8::String> &s) : m_str(*Nan::Utf8String(s)) {}
String(v8::Local<v8::String> &&s) : String(s) {}
operator std::string() const {
return m_str;
}
operator v8::Local<v8::String>() const {
return Nan::New(m_str).ToLocalChecked();
}
};
template<>
class ReturnValue<node::Types> {
Nan::ReturnValue<v8::Value> m_value;
public:
ReturnValue(Nan::ReturnValue<v8::Value> value) : m_value(value) {}
void set(const v8::Local<v8::Value> &value) {
m_value.Set(value);
}
void set(const std::string &string) {
if (string.empty()) {
m_value.SetEmptyString();
}
else {
m_value.Set(Nan::New(string).ToLocalChecked());
}
}
void set(bool boolean) {
m_value.Set(boolean);
}
void set(double number) {
m_value.Set(number);
}
void set(int32_t number) {
m_value.Set(number);
}
void set(uint32_t number) {
m_value.Set(number);
}
void set_null() {
m_value.SetNull();
}
void set_undefined() {
m_value.SetUndefined();
}
};
template<>
class Protected<node::Types::GlobalContext> : public node::Protected<v8::Context> {
public:
Protected(v8::Local<v8::Context> ctx) : node::Protected<v8::Context>(ctx) {}
operator v8::Isolate*() const {
return v8::Local<v8::Context>(*this)->GetIsolate();
}
};
template<>
class Protected<node::Types::Value> : public node::Protected<v8::Value> {
public:
Protected(v8::Isolate* isolate, v8::Local<v8::Value> value) : node::Protected<v8::Value>(value) {}
};
template<>
class Protected<node::Types::Object> : public node::Protected<v8::Object> {
public:
Protected(v8::Isolate* isolate, v8::Local<v8::Object> object) : node::Protected<v8::Object>(object) {}
};
template<>
class Protected<node::Types::Function> : public node::Protected<v8::Function> {
public:
Protected(v8::Isolate* isolate, v8::Local<v8::Function> object) : node::Protected<v8::Function>(object) {}
};
template<>
inline v8::Local<v8::Context> node::Context::get_global_context(v8::Isolate* isolate) {
return isolate->GetCurrentContext();
}
template<>
inline bool node::Value::is_array(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsArray();
}
template<>
inline bool node::Value::is_array_buffer(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsArrayBuffer();
}
template<>
inline bool node::Value::is_date(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsDate();
}
template<>
inline bool node::Value::is_boolean(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsBoolean();
}
template<>
inline bool node::Value::is_constructor(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsFunction();
}
template<>
inline bool node::Value::is_function(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsFunction();
}
template<>
inline bool node::Value::is_null(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsNull();
}
template<>
inline bool node::Value::is_number(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsNumber();
}
template<>
inline bool node::Value::is_object(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsObject();
}
template<>
inline bool node::Value::is_string(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsString();
}
template<>
inline bool node::Value::is_undefined(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsUndefined();
}
template<>
inline bool node::Value::is_valid(const v8::Local<v8::Value> &value) {
return !value.IsEmpty();
}
template<>
inline v8::Local<v8::Value> node::Value::from_boolean(v8::Isolate* isolate, bool boolean) {
return Nan::New(boolean);
}
template<>
inline v8::Local<v8::Value> node::Value::from_null(v8::Isolate* isolate) {
return Nan::Null();
}
template<>
inline v8::Local<v8::Value> node::Value::from_number(v8::Isolate* isolate, double number) {
return Nan::New(number);
}
template<>
inline v8::Local<v8::Value> node::Value::from_string(v8::Isolate* isolate, const node::String &string) {
return v8::Local<v8::String>(string);
}
template<>
inline v8::Local<v8::Value> node::Value::from_undefined(v8::Isolate* isolate) {
return Nan::Undefined();
}
template<>
inline bool node::Value::to_boolean(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return Nan::To<bool>(value).FromMaybe(false);
}
template<>
inline double node::Value::to_number(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
double number = Nan::To<double>(value).FromMaybe(NAN);
if (isnan(number)) {
throw std::invalid_argument("Value not convertible to a number.");
}
return number;
}
template<>
inline node::String node::Value::to_string(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->ToString();
}
template<>
inline v8::Local<v8::Object> node::Value::to_object(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return Nan::To<v8::Object>(value).FromMaybe(v8::Local<v8::Object>());
}
template<>
inline v8::Local<v8::Object> node::Value::to_array(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return to_object(isolate, value);
}
template<>
inline v8::Local<v8::Object> node::Value::to_date(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return to_object(isolate, value);
}
template<>
inline v8::Local<v8::Function> node::Value::to_function(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsFunction() ? v8::Local<v8::Function>::Cast(value) : v8::Local<v8::Function>();
}
template<>
inline v8::Local<v8::Function> node::Value::to_constructor(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return to_function(isolate, value);
}
template<>
inline v8::Local<v8::Value> node::Function::call(v8::Isolate* isolate, const v8::Local<v8::Function> &function, const v8::Local<v8::Object> &this_object, uint32_t argc, const v8::Local<v8::Value> arguments[]) {
Nan::TryCatch trycatch;
auto result = Nan::Call(function, this_object, argc, const_cast<v8::Local<v8::Value>*>(arguments));
if (trycatch.HasCaught()) {
throw node::Exception(isolate, trycatch.Exception());
}
return result.ToLocalChecked();
}
template<>
inline v8::Local<v8::Object> node::Function::construct(v8::Isolate* isolate, const v8::Local<v8::Function> &function, uint32_t argc, const v8::Local<v8::Value> arguments[]) {
Nan::TryCatch trycatch;
auto result = Nan::NewInstance(function, argc, const_cast<v8::Local<v8::Value>*>(arguments));
if (trycatch.HasCaught()) {
throw node::Exception(isolate, trycatch.Exception());
}
return result.ToLocalChecked();
}
template<>
inline bool node::Object::has_property(v8::Isolate* isolate, const v8::Local<v8::Object> &object, const node::String &key) {
return Nan::Has(object, key).FromMaybe(false);
}
template<>
inline bool node::Object::has_property(v8::Isolate* isolate, const v8::Local<v8::Object> &object, uint32_t index) {
return Nan::Has(object, index).FromMaybe(false);
}
template<>
inline v8::Local<v8::Value> node::Object::get_property(v8::Isolate* isolate, const v8::Local<v8::Object> &object, const node::String &key) {
Nan::TryCatch trycatch;
auto value = Nan::Get(object, v8::Local<v8::String>(key));
if (trycatch.HasCaught()) {
throw node::Exception(isolate, trycatch.Exception());
}
return value.ToLocalChecked();
}
template<>
inline v8::Local<v8::Value> node::Object::get_property(v8::Isolate* isolate, const v8::Local<v8::Object> &object, uint32_t index) {
Nan::TryCatch trycatch;
auto value = Nan::Get(object, index);
if (trycatch.HasCaught()) {
throw node::Exception(isolate, trycatch.Exception());
}
return value.ToLocalChecked();
}
template<>
inline void node::Object::set_property(v8::Isolate* isolate, const v8::Local<v8::Object> &object, const node::String &key, const v8::Local<v8::Value> &value, PropertyAttributes attributes) {
Nan::TryCatch trycatch;
if (attributes) {
Nan::ForceSet(object, v8::Local<v8::String>(key), value, v8::PropertyAttribute(attributes));
}
else {
Nan::Set(object, v8::Local<v8::String>(key), value);
}
if (trycatch.HasCaught()) {
throw node::Exception(isolate, trycatch.Exception());
}
}
template<>
inline void node::Object::set_property(v8::Isolate* isolate, const v8::Local<v8::Object> &object, uint32_t index, const v8::Local<v8::Value> &value) {
Nan::TryCatch trycatch;
Nan::Set(object, index, value);
if (trycatch.HasCaught()) {
throw node::Exception(isolate, trycatch.Exception());
}
}
template<>
inline std::vector<node::String> node::Object::get_property_names(v8::Isolate* isolate, const v8::Local<v8::Object> &object) {
auto maybe_array = Nan::GetPropertyNames(object);
if (maybe_array.IsEmpty()) {
return std::vector<node::String>();
}
auto array = maybe_array.ToLocalChecked();
uint32_t count = array->Length();
std::vector<node::String> names;
names.reserve(count);
for (uint32_t i = 0; i < count; i++) {
names.push_back(array->Get(i)->ToString());
}
return names;
}
template<>
inline v8::Local<v8::Value> node::Object::get_prototype(v8::Isolate* isolate, const v8::Local<v8::Object> &object) {
return object->GetPrototype();
}
template<>
inline void node::Object::set_prototype(v8::Isolate* isolate, const v8::Local<v8::Object> &object, const v8::Local<v8::Value> &prototype) {
Nan::SetPrototype(object, prototype);
}
template<>
inline v8::Local<v8::Object> node::Object::create_empty(v8::Isolate* isolate) {
return Nan::New<v8::Object>();
}
template<>
inline v8::Local<v8::Object> node::Object::create_array(v8::Isolate* isolate, uint32_t length, const v8::Local<v8::Value> values[]) {
v8::Local<v8::Array> array = Nan::New<v8::Array>(length);
for (uint32_t i = 0; i < length; i++) {
set_property(isolate, array, i, values[i]);
}
return array;
}
template<>
inline v8::Local<v8::Object> node::Object::create_date(v8::Isolate* isolate, double time) {
return Nan::New<v8::Date>(time).ToLocalChecked();
}
template<>
template<typename U>
inline v8::Local<v8::Object> node::Object::create(v8::Isolate* isolate, U* internal) {
return node::ObjectWrap<U>::create(isolate, internal);
}
template<>
template<typename U>
inline bool node::Object::is_instance(v8::Isolate* isolate, const v8::Local<v8::Object> &object) {
return node::ObjectWrap<U>::has_instance(isolate, object);
}
template<>
template<typename U>
inline U* node::Object::get_internal(const v8::Local<v8::Object> &object) {
return *Nan::ObjectWrap::Unwrap<node::ObjectWrap<U>>(object);
}
template<>
template<typename U>
inline void node::Object::set_internal(const v8::Local<v8::Object> &object, U* ptr) {
auto wrap = Nan::ObjectWrap::Unwrap<node::ObjectWrap<U>>(object);
*wrap = ptr;
}
template<>
inline v8::Local<v8::Value> node::Exception::value(v8::Isolate* isolate, const std::string &message) {
return Nan::Error(message.c_str());
}
} // js
} // realm

View File

@ -21,7 +21,7 @@
#include <dlfcn.h>
#include <map>
#include <string>
#include "js_init.h"
#include "jsc_init.h"
#include "js_object.hpp"
#include "js_results.hpp"
#include "jsc_list.hpp"