converted BindingContext

This commit is contained in:
Ari Lazier 2016-03-29 16:17:57 -07:00
parent e7d954a727
commit 5b2a59d5c6
10 changed files with 163 additions and 122 deletions

View File

@ -100,6 +100,7 @@
/* 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>"; };
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>"; };
@ -261,6 +262,7 @@
0290480D1C0428DF00ABDED4 /* js_util.cpp */,
0290480E1C0428DF00ABDED4 /* js_util.hpp */,
02AFE5B11CAB133500953DA3 /* js_compat.hpp */,
025678951CAB392000FB8501 /* types.hpp */,
02AFE5871CA9B23400953DA3 /* jsc_list.cpp */,
02AFE5881CA9B23400953DA3 /* jsc_list.hpp */,
029048351C042A3C00ABDED4 /* platform.hpp */,

View File

@ -74,9 +74,10 @@ JSClassRef RJSObjectClass() {
JSObjectRef RJSObjectCreate(JSContextRef ctx, Object object) {
static JSStringRef prototypeString = JSStringCreateWithUTF8CString("prototype");
JSObjectRef constructor = RJSConstructors(object.realm().get())[object.get_object_schema().name];
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 = RJSWrapObject(ctx, RJSObjectClass(), new Object(object), prototype);
JSObjectRef jsObject = realm::js::WrapObject(ctx, RJSObjectClass(), new Object(object), prototype);
if (constructor) {
JSValueRef exception = NULL;
@ -117,12 +118,12 @@ template<> JSValueRef RJSAccessor::dict_value_for_key(JSContextRef ctx, JSValueR
}
template<> bool RJSAccessor::has_default_value_for_property(JSContextRef ctx, Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name) {
ObjectDefaults &defaults = RJSDefaults(realm)[object_schema.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) {
ObjectDefaults &defaults = RJSDefaults(realm)[object_schema.name];
auto defaults = realm::js::get_delegate<jsc::Types>(realm)->m_defaults[object_schema.name];
return defaults[prop_name];
}

View File

@ -29,99 +29,12 @@
#include "binding_context.hpp"
#include "results.hpp"
#include <set>
#include <cassert>
using namespace realm;
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
class RJSRealmDelegate : public BindingContext {
public:
virtual void changes_available() {
assert(0);
}
virtual void did_change(std::vector<ObserverState> const& observers, std::vector<void*> const& invalidated) {
notify("change");
}
virtual std::vector<ObserverState> get_observed_rows() {
return std::vector<ObserverState>();
}
virtual void will_change(std::vector<ObserverState> const& observers,
std::vector<void*> const& invalidated) {}
RJSRealmDelegate(WeakRealm realm, JSGlobalContextRef ctx) : m_context(ctx), m_realm(realm) {
JSGlobalContextRetain(m_context);
}
~RJSRealmDelegate() {
remove_all_notifications();
for (auto constructor : m_constructors) {
JSValueUnprotect(m_context, constructor.second);
}
for (auto objectDefaults : m_defaults) {
for (auto value : objectDefaults.second) {
JSValueUnprotect(m_context, value.second);
}
}
JSGlobalContextRelease(m_context);
}
void add_notification(JSObjectRef notification) {
if (!m_notifications.count(notification)) {
JSValueProtect(m_context, notification);
m_notifications.insert(notification);
}
}
void remove_notification(JSObjectRef notification) {
if (m_notifications.count(notification)) {
JSValueUnprotect(m_context, notification);
m_notifications.erase(notification);
}
}
void remove_all_notifications() {
for (auto notification : m_notifications) {
JSValueUnprotect(m_context, notification);
}
m_notifications.clear();
}
std::map<std::string, ObjectDefaults> m_defaults;
std::map<std::string, JSObjectRef> m_constructors;
private:
std::set<JSObjectRef> m_notifications;
JSGlobalContextRef m_context;
WeakRealm 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");
}
JSObjectRef realm_object = RJSWrapObject<SharedRealm *>(m_context, RJSRealmClass(), new SharedRealm(realm));
arguments[0] = realm_object;
arguments[1] = RJSValueForString(m_context, notification_name);
for (auto callback : m_notifications) {
JSValueRef ex = NULL;
JSObjectCallAsFunction(m_context, callback, realm_object, 2, arguments, &ex);
if (ex) {
throw RJSException(m_context, ex);
}
}
}
};
std::map<std::string, ObjectDefaults> &RJSDefaults(Realm *realm) {
return static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->m_defaults;
}
std::map<std::string, JSObjectRef> &RJSConstructors(Realm *realm) {
return static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->m_constructors;
}
// static std::string s_defaultPath = realm::default_realm_file_directory() + "/default.realm";
static std::string s_defaultPath = "";
std::string RJSDefaultPath() {
@ -214,12 +127,13 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a
ensure_directory_exists_for_file(config.path);
SharedRealm realm = Realm::get_shared_realm(config);
auto delegate = new js::RealmDelegate<jsc::Types>(realm, JSContextGetGlobalContext(ctx));
if (!realm->m_binding_context) {
realm->m_binding_context.reset(new RJSRealmDelegate(realm, JSContextGetGlobalContext(ctx)));
realm->m_binding_context.reset(delegate);
}
RJSDefaults(realm.get()) = defaults;
RJSConstructors(realm.get()) = constructors;
return RJSWrapObject<SharedRealm *>(ctx, RJSRealmClass(), new SharedRealm(realm));
delegate->m_defaults = defaults;
delegate->m_constructors = constructors;
return js::WrapObject(ctx, RJSRealmClass(), new SharedRealm(realm));
}
catch (std::exception &ex) {
if (jsException) {
@ -299,7 +213,8 @@ std::string RJSValidatedObjectTypeForValue(SharedRealm &realm, JSContextRef ctx,
if (JSValueIsObject(ctx, value) && JSObjectIsConstructor(ctx, (JSObjectRef)value)) {
JSObjectRef constructor = (JSObjectRef)value;
for (auto pair : RJSConstructors(realm.get())) {
auto delegate = js::get_delegate<jsc::Types>(realm.get());
for (auto pair : delegate->m_constructors) {
if (pair.second == constructor) {
return pair.first;
}
@ -453,7 +368,7 @@ void RealmAddListener(ContextType ctx, ObjectType thisObject, size_t argumentCou
auto callback = RJSValidatedValueToFunction(ctx, arguments[1]);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->add_notification(callback);
static_cast<js::RealmDelegate<jsc::Types> *>(realm->m_binding_context.get())->add_notification(callback);
}
catch (std::exception &exp) {
RJSSetException(ctx, exceptionObject, exp);
@ -467,7 +382,7 @@ void RealmRemoveListener(ContextType ctx, ObjectType thisObject, size_t argument
auto callback = RJSValidatedValueToFunction(ctx, arguments[1]);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->remove_notification(callback);
static_cast<js::RealmDelegate<jsc::Types> *>(realm->m_binding_context.get())->remove_notification(callback);
}
catch (std::exception &exp) {
RJSSetException(ctx, exceptionObject, exp);
@ -482,7 +397,7 @@ void RealmRemoveAllListeners(ContextType ctx, ObjectType thisObject, size_t argu
}
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->remove_all_notifications();
static_cast<js::RealmDelegate<jsc::Types> *>(realm->m_binding_context.get())->remove_all_notifications();
}
catch (std::exception &exp) {
RJSSetException(ctx, exceptionObject, exp);
@ -527,3 +442,10 @@ JSClassRef RJSRealmClass() {
static JSClassRef s_realmClass = RJSCreateWrapperClass<SharedRealm *>("Realm", RealmGetProperty, NULL, RJSRealmFuncs);
return s_realmClass;
}
namespace realm {
namespace js {
JSClassRef RealmClass() { return RJSRealmClass(); };
}
}

View File

@ -19,11 +19,101 @@
#pragma once
#include "js_util.hpp"
#include "shared_realm.hpp"
#include "binding_context.hpp"
#include <map>
#include <set>
namespace realm {
class Realm;
using ObjectDefaults = std::map<std::string, JSValueRef>;
namespace js {
template<typename T>
class RealmDelegate : public BindingContext {
public:
using GlobalContextType = typename T::GlobalContext;
using ObjectClassType = typename T::ObjectClass;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
using ObjectDefaults = std::map<std::string, ValueType>;
virtual void did_change(std::vector<ObserverState> const& observers, std::vector<void*> const& invalidated) {
notify("change");
}
virtual std::vector<ObserverState> get_observed_rows() {
return std::vector<ObserverState>();
}
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() {
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 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;
private:
std::set<ObjectType> m_notifications;
GlobalContextType m_context;
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::RealmClass(), new SharedRealm(realm));
arguments[0] = realm_object;
arguments[1] = RJSValueForString(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);
}
}
}
};
template<typename T>
static RealmDelegate<T> *get_delegate(Realm *realm) {
return dynamic_cast<realm::js::RealmDelegate<T> *>(realm->m_binding_context.get());
}
}
}
JSClassRef RJSRealmClass();
@ -32,5 +122,3 @@ JSClassRef RJSRealmConstructorClass();
std::string RJSDefaultPath();
void RJSSetDefaultPath(std::string path);
std::map<std::string, realm::ObjectDefaults> &RJSDefaults(realm::Realm *realm);
std::map<std::string, JSObjectRef> &RJSConstructors(realm::Realm *realm);

View File

@ -96,7 +96,7 @@ JSValueRef ResultsStaticCopy(JSContextRef ctx, JSObjectRef function, JSObjectRef
Results *copy = new Results(*results);
copy->set_live(false);
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), copy);
return js::WrapObject<Results *>(ctx, RJSResultsClass(), copy);
}
catch (std::exception &exp) {
if (jsException) {
@ -144,7 +144,7 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string cl
if (object_schema == realm->config().schema->end()) {
throw std::runtime_error("Object type '" + className + "' not present in Realm.");
}
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, *table));
return js::WrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, *table));
}
JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string className, std::string queryString, std::vector<JSValueRef> args) {
@ -159,14 +159,14 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string cl
query_builder::ArgumentConverter<JSValueRef, JSContextRef> arguments(ctx, args);
query_builder::apply_predicate(query, predicate, arguments, schema, object_schema->name);
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query)));
return js::WrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query)));
}
JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, const ObjectSchema &objectSchema, Query query, bool live) {
Results *results = new Results(realm, objectSchema, std::move(query));
results->set_live(live);
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), results);
return js::WrapObject<Results *>(ctx, js::ResultsClass(), results);
}
JSObjectRef RJSResultsCreateFiltered(JSContextRef ctx, SharedRealm realm, const ObjectSchema &objectSchema, Query query, size_t argumentCount, const JSValueRef arguments[]) {
@ -233,7 +233,7 @@ JSObjectRef RJSResultsCreateSorted(JSContextRef ctx, SharedRealm realm, const Ob
}
Results *results = new Results(realm, objectSchema, std::move(query), {std::move(columns), std::move(ascending)});
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), results);
return js::WrapObject<Results *>(ctx, js::ResultsClass(), results);
}
static const JSStaticFunction RJSResultsFuncs[] = {
@ -247,3 +247,9 @@ JSClassRef RJSResultsClass() {
static JSClassRef s_objectClass = RJSCreateWrapperClass<Results *>("Results", ResultsGetProperty, ResultsSetProperty, RJSResultsFuncs, ResultsPropertyNames, RJSCollectionClass());
return s_objectClass;
}
namespace realm {
namespace js {
JSClassRef ResultsClass() { return RJSResultsClass(); };
}
}

View File

@ -42,7 +42,7 @@ JSObjectRef RJSSchemaCreate(JSContextRef ctx, Schema &schema) {
SchemaWrapper *wrapper = new SchemaWrapper();
wrapper->schema = &schema;
wrapper->owned = false;
return RJSWrapObject(ctx, RJSSchemaClass(), wrapper);
return js::WrapObject(ctx, RJSSchemaClass(), wrapper);
}
static inline Property RJSParseProperty(JSContextRef ctx, JSValueRef propertyAttributes, std::string propertyName, ObjectDefaults &objectDefaults) {

View File

@ -53,15 +53,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));

View File

@ -23,7 +23,7 @@
namespace realm {
namespace js {
static bool ValueIsUndefined(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsUndefined(ctx, value); }
static bool ValueIsNull(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsNull(ctx, value); }
static bool ValueIsBoolean(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsBoolean(ctx, value); }
@ -31,4 +31,27 @@ static bool ValueIsNumber(jsc::Types::Context ctx, jsc::Types::Value value) { re
static bool ValueIsString(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsString(ctx, value); }
static bool ValueIsObject(jsc::Types::Context ctx, jsc::Types::Value value) { return JSValueIsObject(ctx, value); }
}}
static void ValueProtect(jsc::Types::Context ctx, jsc::Types::Value value) { JSValueProtect(ctx, value); }
static void ValueUnprotect(jsc::Types::Context ctx, jsc::Types::Value value) { JSValueUnprotect(ctx, value); }
static 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 void GlobalContextProtect(jsc::Types::GlobalContext ctx) { JSGlobalContextRetain(ctx); }
static void GlobalContextUnprotect(jsc::Types::GlobalContext ctx) { JSGlobalContextRelease(ctx); }
template<class T>
static 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;
}
static jsc::Types::ObjectClass RealmClass();
static jsc::Types::ObjectClass ListClass();
static jsc::Types::ObjectClass ResultsClass();
}}

View File

@ -97,7 +97,7 @@ WRAP_CLASS_METHOD(RJSList, Filtered)
WRAP_CLASS_METHOD(RJSList, Sorted)
JSObjectRef RJSListCreate(JSContextRef ctx, List &list) {
return RJSWrapObject<List *>(ctx, RJSListClass(), new List(list));
return realm::js::WrapObject<List *>(ctx, realm::js::ListClass(), new List(list));
}
static const JSStaticFunction RJSListFuncs[] = {
@ -116,3 +116,9 @@ JSClassRef RJSListClass() {
static JSClassRef s_listClass = RJSCreateWrapperClass<List *>("List", ListGetProperty, ListSetProperty, RJSListFuncs, ListPropertyNames, RJSCollectionClass());
return s_listClass;
}
namespace realm {
namespace js {
JSClassRef ListClass() { return RJSListClass(); };
}
}

View File

@ -27,6 +27,8 @@ namespace jsc {
struct Types {
using Context = JSContextRef;
using GlobalContext = JSGlobalContextRef;
using ObjectClass = JSClassRef;
using Value = JSValueRef;
using Object = JSObjectRef;
using String = JSStringRef;