diff --git a/src/ios/RealmJS.xcodeproj/project.pbxproj b/src/ios/RealmJS.xcodeproj/project.pbxproj index c149313f..2e65c234 100644 --- a/src/ios/RealmJS.xcodeproj/project.pbxproj +++ b/src/ios/RealmJS.xcodeproj/project.pbxproj @@ -173,6 +173,22 @@ F60102E31CBBB19700EC01BA /* node_object_accessor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = node_object_accessor.hpp; sourceTree = ""; }; F60102E71CBBB36500EC01BA /* jsc_object_accessor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_object_accessor.hpp; sourceTree = ""; }; F60102F71CBDA6D400EC01BA /* js_collection.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_collection.hpp; sourceTree = ""; }; + F60103071CC4B3DF00EC01BA /* node_protected.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_protected.hpp; sourceTree = ""; }; + F60103081CC4B4F900EC01BA /* jsc_protected.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_protected.hpp; sourceTree = ""; }; + F60103091CC4B5E800EC01BA /* jsc_context.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_context.hpp; sourceTree = ""; }; + F601030A1CC4B64E00EC01BA /* node_context.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_context.hpp; sourceTree = ""; }; + F601030B1CC4B6C900EC01BA /* jsc_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_value.hpp; sourceTree = ""; }; + F601030C1CC4B72B00EC01BA /* node_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_value.hpp; sourceTree = ""; }; + F601030D1CC4B76F00EC01BA /* jsc_object.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_object.hpp; sourceTree = ""; }; + F601030E1CC4B7C900EC01BA /* node_object.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_object.hpp; sourceTree = ""; }; + F601030F1CC4B80800EC01BA /* jsc_function.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_function.hpp; sourceTree = ""; }; + F60103101CC4B86000EC01BA /* node_function.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_function.hpp; sourceTree = ""; }; + F60103111CC4BA6500EC01BA /* jsc_exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_exception.hpp; sourceTree = ""; }; + F60103121CC4CBF000EC01BA /* node_exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_exception.hpp; sourceTree = ""; }; + F60103131CC4CC4500EC01BA /* jsc_string.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_string.hpp; sourceTree = ""; }; + F60103141CC4CC8C00EC01BA /* jsc_return_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_return_value.hpp; sourceTree = ""; }; + F60103151CC4CCFD00EC01BA /* node_return_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_return_value.hpp; sourceTree = ""; }; + F60103161CC4CD2F00EC01BA /* node_string.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = node_string.hpp; sourceTree = ""; }; F61378781C18EAAC008BFC51 /* js */ = {isa = PBXFileReference; lastKnownFileType = folder; path = js; sourceTree = ""; }; F620F0521CAF0B600082977B /* js_class.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_class.hpp; sourceTree = ""; }; F620F0531CAF2EF70082977B /* jsc_class.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsc_class.hpp; sourceTree = ""; }; @@ -271,20 +287,17 @@ children = ( F6BCCFDF1C83809A00FE31AE /* lib */, F62A35131C18E6E2004A917D /* iOS */, + F60103051CC4ADE500EC01BA /* JS */, F6874A441CAD2ACD00EEEE36 /* JSC */, F62BF9001CAC72C40022BCDC /* Node */, F62A35141C18E783004A917D /* Object Store */, F60102F71CBDA6D400EC01BA /* js_collection.hpp */, 029048041C0428DF00ABDED4 /* js_list.hpp */, - F620F0591CB7B4C80082977B /* js_object_accessor.hpp */, 029048061C0428DF00ABDED4 /* js_realm_object.hpp */, 029048071C0428DF00ABDED4 /* js_realm.cpp */, 029048081C0428DF00ABDED4 /* js_realm.hpp */, 0290480A1C0428DF00ABDED4 /* js_results.hpp */, 0290480C1C0428DF00ABDED4 /* js_schema.hpp */, - F620F0521CAF0B600082977B /* js_class.hpp */, - F6874A3E1CACA5A900EEEE36 /* js_types.hpp */, - F6267BC91CADC30000AC36B1 /* js_util.hpp */, 029048351C042A3C00ABDED4 /* platform.hpp */, 0290480F1C0428DF00ABDED4 /* rpc.cpp */, 029048101C0428DF00ABDED4 /* rpc.hpp */, @@ -346,6 +359,17 @@ name = Frameworks; sourceTree = ""; }; + F60103051CC4ADE500EC01BA /* JS */ = { + isa = PBXGroup; + children = ( + F620F0521CAF0B600082977B /* js_class.hpp */, + F6874A3E1CACA5A900EEEE36 /* js_types.hpp */, + F6267BC91CADC30000AC36B1 /* js_util.hpp */, + F620F0591CB7B4C80082977B /* js_object_accessor.hpp */, + ); + name = JS; + sourceTree = ""; + }; F62A35131C18E6E2004A917D /* iOS */ = { isa = PBXGroup; children = ( @@ -408,6 +432,14 @@ F620F0571CB766DA0082977B /* node_init.cpp */, F620F0551CB655A50082977B /* node_class.hpp */, F6874A351CAC792D00EEEE36 /* node_types.hpp */, + F60103161CC4CD2F00EC01BA /* node_string.hpp */, + F601030A1CC4B64E00EC01BA /* node_context.hpp */, + F601030C1CC4B72B00EC01BA /* node_value.hpp */, + F601030E1CC4B7C900EC01BA /* node_object.hpp */, + F60103101CC4B86000EC01BA /* node_function.hpp */, + F60103121CC4CBF000EC01BA /* node_exception.hpp */, + F60103071CC4B3DF00EC01BA /* node_protected.hpp */, + F60103151CC4CCFD00EC01BA /* node_return_value.hpp */, F60102E31CBBB19700EC01BA /* node_object_accessor.hpp */, ); name = Node; @@ -482,6 +514,14 @@ 029048011C0428DF00ABDED4 /* jsc_init.cpp */, F620F0531CAF2EF70082977B /* jsc_class.hpp */, 025678951CAB392000FB8501 /* jsc_types.hpp */, + F60103131CC4CC4500EC01BA /* jsc_string.hpp */, + F60103091CC4B5E800EC01BA /* jsc_context.hpp */, + F601030B1CC4B6C900EC01BA /* jsc_value.hpp */, + F601030D1CC4B76F00EC01BA /* jsc_object.hpp */, + F601030F1CC4B80800EC01BA /* jsc_function.hpp */, + F60103111CC4BA6500EC01BA /* jsc_exception.hpp */, + F60103081CC4B4F900EC01BA /* jsc_protected.hpp */, + F60103141CC4CC8C00EC01BA /* jsc_return_value.hpp */, F60102E71CBBB36500EC01BA /* jsc_object_accessor.hpp */, ); name = JSC; diff --git a/src/jsc/jsc_class.hpp b/src/jsc/jsc_class.hpp index 8281972b..e5612cda 100644 --- a/src/jsc/jsc_class.hpp +++ b/src/jsc/jsc_class.hpp @@ -19,6 +19,7 @@ #pragma once #include "jsc_types.hpp" + #include "js_class.hpp" #include "js_util.hpp" diff --git a/src/jsc/jsc_context.hpp b/src/jsc/jsc_context.hpp new file mode 100644 index 00000000..563bbdfe --- /dev/null +++ b/src/jsc/jsc_context.hpp @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +inline JSGlobalContextRef jsc::Context::get_global_context(JSContextRef ctx) { + return JSContextGetGlobalContext(ctx); +} + +} // js +} // realm diff --git a/src/jsc/jsc_exception.hpp b/src/jsc/jsc_exception.hpp new file mode 100644 index 00000000..c6b315ac --- /dev/null +++ b/src/jsc/jsc_exception.hpp @@ -0,0 +1,33 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +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 diff --git a/src/jsc/jsc_function.hpp b/src/jsc/jsc_function.hpp new file mode 100644 index 00000000..866c973f --- /dev/null +++ b/src/jsc/jsc_function.hpp @@ -0,0 +1,47 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +inline JSValueRef jsc::Function::call(JSContextRef ctx, const JSObjectRef &function, const JSObjectRef &this_object, size_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, size_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; +} + +} // js +} // realm diff --git a/src/jsc/jsc_init.hpp b/src/jsc/jsc_init.hpp index c1621286..de19d7b9 100644 --- a/src/jsc/jsc_init.hpp +++ b/src/jsc/jsc_init.hpp @@ -19,5 +19,14 @@ #pragma once #include "jsc_init.h" +#include "jsc_string.hpp" +#include "jsc_protected.hpp" +#include "jsc_context.hpp" +#include "jsc_value.hpp" +#include "jsc_object.hpp" +#include "jsc_function.hpp" +#include "jsc_exception.hpp" +#include "jsc_return_value.hpp" #include "jsc_object_accessor.hpp" + #include "js_realm.hpp" diff --git a/src/jsc/jsc_object.hpp b/src/jsc/jsc_object.hpp new file mode 100644 index 00000000..0013add0 --- /dev/null +++ b/src/jsc/jsc_object.hpp @@ -0,0 +1,147 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +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::Object::get_property_names(JSContextRef ctx, const JSObjectRef &object) { + JSPropertyNameArrayRef property_names = JSObjectCopyPropertyNames(ctx, object); + size_t property_count = JSPropertyNameArrayGetCount(property_names); + + std::vector 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 +inline JSObjectRef jsc::Object::create_instance(JSContextRef ctx, typename ClassType::Internal* internal) { + return jsc::ObjectWrap::create_instance(ctx, internal); +} + +template<> +template +inline bool jsc::Object::is_instance(JSContextRef ctx, const JSObjectRef &object) { + return jsc::ObjectWrap::has_instance(ctx, object); +} + +template<> +template +inline typename ClassType::Internal* jsc::Object::get_internal(const JSObjectRef &object) { + return *static_cast *>(JSObjectGetPrivate(object)); +} + +template<> +template +inline void jsc::Object::set_internal(const JSObjectRef &object, typename ClassType::Internal* ptr) { + auto wrap = static_cast *>(JSObjectGetPrivate(object)); + *wrap = ptr; +} + +} // js +} // realm diff --git a/src/jsc/jsc_protected.hpp b/src/jsc/jsc_protected.hpp new file mode 100644 index 00000000..79f2b020 --- /dev/null +++ b/src/jsc/jsc_protected.hpp @@ -0,0 +1,78 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace jsc { + +template +class Protected { + const MemberType m_value; + + public: + Protected(MemberType value) : m_value(value) {} + + operator MemberType() const { + return m_value; + } +}; + +} // jsc + +namespace js { + +template<> +class Protected : public jsc::Protected { + public: + Protected(JSGlobalContextRef ctx) : jsc::Protected(ctx) { + JSGlobalContextRetain(*this); + } + ~Protected() { + JSGlobalContextRelease(*this); + } +}; + +template<> +class Protected : public jsc::Protected { + const JSGlobalContextRef m_context; + + public: + Protected(JSContextRef ctx, JSValueRef value) : jsc::Protected(value), m_context(JSContextGetGlobalContext(ctx)) { + JSValueProtect(m_context, *this); + } + ~Protected() { + JSValueUnprotect(m_context, *this); + } +}; + +template<> +class Protected : public Protected { + public: + Protected(JSContextRef ctx, JSObjectRef object) : Protected(ctx, object) {} + + operator JSObjectRef() const { + JSValueRef value = static_cast(*this); + return (JSObjectRef)value; + } +}; + +} // js +} // realm diff --git a/src/jsc/jsc_return_value.hpp b/src/jsc/jsc_return_value.hpp new file mode 100644 index 00000000..1974e384 --- /dev/null +++ b/src/jsc/jsc_return_value.hpp @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +class ReturnValue { + 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; + } +}; + +} // js +} // realm diff --git a/src/jsc/jsc_string.hpp b/src/jsc/jsc_string.hpp new file mode 100644 index 00000000..521b5c70 --- /dev/null +++ b/src/jsc/jsc_string.hpp @@ -0,0 +1,59 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +class String { + using StringType = String; + + JSStringRef m_str; + + public: + String(const char *s) : m_str(JSStringCreateWithUTF8CString(s)) {} + String(const JSStringRef &s) : m_str(JSStringRetain(s)) {} + String(const std::string &str) : String(str.c_str()) {} + String(const StringType &o) : String(o.m_str) {} + String(StringType &&o) : m_str(o.m_str) { + o.m_str = nullptr; + } + ~String() { + if (m_str) { + 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; + } +}; + +} // js +} // realm diff --git a/src/jsc/jsc_types.hpp b/src/jsc/jsc_types.hpp index 835f0f96..07c36e48 100644 --- a/src/jsc/jsc_types.hpp +++ b/src/jsc/jsc_types.hpp @@ -47,19 +47,7 @@ struct Types { using StringPropertyEnumeratorCallback = JSObjectGetPropertyNamesCallback; }; -template -class Protected { - const T m_value; - - public: - Protected(T value) : m_value(value) {} - - operator T() const { - return m_value; - } -}; - -template +template class ObjectWrap; using String = js::String; @@ -71,430 +59,4 @@ using Exception = js::Exception; using ReturnValue = js::ReturnValue; } // jsc - -namespace js { - -template<> -class String { - using StringType = String; - - JSStringRef m_str; - - public: - String(const char *s) : m_str(JSStringCreateWithUTF8CString(s)) {} - String(const JSStringRef &s) : m_str(JSStringRetain(s)) {} - String(const std::string &str) : String(str.c_str()) {} - String(const StringType &o) : String(o.m_str) {} - String(StringType &&o) : m_str(o.m_str) { - o.m_str = nullptr; - } - ~String() { - if (m_str) { - 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 { - 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 : public jsc::Protected { - public: - Protected(JSGlobalContextRef ctx) : jsc::Protected(ctx) { - JSGlobalContextRetain(*this); - } - ~Protected() { - JSGlobalContextRelease(*this); - } -}; - -template<> -class Protected : public jsc::Protected { - const JSGlobalContextRef m_context; - - public: - Protected(JSContextRef ctx, JSValueRef value) : jsc::Protected(value), m_context(JSContextGetGlobalContext(ctx)) { - JSValueProtect(m_context, *this); - } - ~Protected() { - JSValueUnprotect(m_context, *this); - } -}; - -template<> -class Protected : public Protected { - public: - Protected(JSContextRef ctx, JSObjectRef object) : Protected(ctx, object) {} - - operator JSObjectRef() const { - JSValueRef value = static_cast(*this); - return (JSObjectRef)value; - } -}; - -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<> -inline JSValueRef jsc::Value::from_boolean(JSContextRef ctx, bool boolean) { - return JSValueMakeBoolean(ctx, boolean); -} - -template<> -inline JSValueRef jsc::Value::from_null(JSContextRef ctx) { - return JSValueMakeNull(ctx); -} - -template<> -inline JSValueRef jsc::Value::from_number(JSContextRef ctx, double number) { - return JSValueMakeNumber(ctx, number); -} - -template<> -inline JSValueRef jsc::Value::from_string(JSContextRef ctx, const jsc::String &string) { - return JSValueMakeString(ctx, string); -} - -template<> -inline 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); - - // Since the string's retain value is +2 here, we need to manually release it before returning. - JSStringRelease(string); - - 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, size_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, size_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::Object::get_property_names(JSContextRef ctx, const JSObjectRef &object) { - JSPropertyNameArrayRef property_names = JSObjectCopyPropertyNames(ctx, object); - size_t property_count = JSPropertyNameArrayGetCount(property_names); - - std::vector 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 -inline JSObjectRef jsc::Object::create_instance(JSContextRef ctx, typename ClassType::Internal* internal) { - return jsc::ObjectWrap::create_instance(ctx, internal); -} - -template<> -template -inline bool jsc::Object::is_instance(JSContextRef ctx, const JSObjectRef &object) { - return jsc::ObjectWrap::has_instance(ctx, object); -} - -template<> -template -inline typename ClassType::Internal* jsc::Object::get_internal(const JSObjectRef &object) { - return *static_cast *>(JSObjectGetPrivate(object)); -} - -template<> -template -inline void jsc::Object::set_internal(const JSObjectRef &object, typename ClassType::Internal* ptr) { - auto wrap = static_cast *>(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 diff --git a/src/jsc/jsc_value.hpp b/src/jsc/jsc_value.hpp new file mode 100644 index 00000000..d2df79c8 --- /dev/null +++ b/src/jsc/jsc_value.hpp @@ -0,0 +1,194 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +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 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<> +inline JSValueRef jsc::Value::from_boolean(JSContextRef ctx, bool boolean) { + return JSValueMakeBoolean(ctx, boolean); +} + +template<> +inline JSValueRef jsc::Value::from_null(JSContextRef ctx) { + return JSValueMakeNull(ctx); +} + +template<> +inline JSValueRef jsc::Value::from_number(JSContextRef ctx, double number) { + return JSValueMakeNumber(ctx, number); +} + +template<> +inline JSValueRef jsc::Value::from_string(JSContextRef ctx, const jsc::String &string) { + return JSValueMakeString(ctx, string); +} + +template<> +inline 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); + + // Since the string's retain value is +2 here, we need to manually release it before returning. + JSStringRelease(string); + + 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); +} + +} // js +} // realm diff --git a/src/node/node_class.hpp b/src/node/node_class.hpp index 5c54e95e..bc5e0214 100644 --- a/src/node/node_class.hpp +++ b/src/node/node_class.hpp @@ -19,6 +19,7 @@ #pragma once #include "node_types.hpp" + #include "js_class.hpp" #include "js_util.hpp" diff --git a/src/node/node_context.hpp b/src/node/node_context.hpp new file mode 100644 index 00000000..b77b1b64 --- /dev/null +++ b/src/node/node_context.hpp @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +inline v8::Local node::Context::get_global_context(v8::Isolate* isolate) { + return isolate->GetCurrentContext(); +} + +} // js +} // realm diff --git a/src/node/node_exception.hpp b/src/node/node_exception.hpp new file mode 100644 index 00000000..17eca27f --- /dev/null +++ b/src/node/node_exception.hpp @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +inline v8::Local node::Exception::value(v8::Isolate* isolate, const std::string &message) { + return Nan::Error(message.c_str()); +} + +} // js +} // realm diff --git a/src/node/node_function.hpp b/src/node/node_function.hpp new file mode 100644 index 00000000..f983ef23 --- /dev/null +++ b/src/node/node_function.hpp @@ -0,0 +1,49 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +inline v8::Local node::Function::call(v8::Isolate* isolate, const v8::Local &function, const v8::Local &this_object, size_t argc, const v8::Local arguments[]) { + Nan::TryCatch trycatch; + auto result = Nan::Call(function, this_object, (int)argc, const_cast*>(arguments)); + + if (trycatch.HasCaught()) { + throw node::Exception(isolate, trycatch.Exception()); + } + return result.ToLocalChecked(); +} + +template<> +inline v8::Local node::Function::construct(v8::Isolate* isolate, const v8::Local &function, size_t argc, const v8::Local arguments[]) { + Nan::TryCatch trycatch; + auto result = Nan::NewInstance(function, (int)argc, const_cast*>(arguments)); + + if (trycatch.HasCaught()) { + throw node::Exception(isolate, trycatch.Exception()); + } + return result.ToLocalChecked(); +} + +} // js +} // realm diff --git a/src/node/node_init.hpp b/src/node/node_init.hpp index 8a921da4..06980428 100644 --- a/src/node/node_init.hpp +++ b/src/node/node_init.hpp @@ -18,5 +18,14 @@ #pragma once +#include "node_string.hpp" +#include "node_protected.hpp" +#include "node_context.hpp" +#include "node_value.hpp" +#include "node_object.hpp" +#include "node_function.hpp" +#include "node_exception.hpp" +#include "node_return_value.hpp" #include "node_object_accessor.hpp" + #include "js_realm.hpp" diff --git a/src/node/node_object.hpp b/src/node/node_object.hpp new file mode 100644 index 00000000..c1fa9dd0 --- /dev/null +++ b/src/node/node_object.hpp @@ -0,0 +1,159 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +inline bool node::Object::has_property(v8::Isolate* isolate, const v8::Local &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 &object, uint32_t index) { + return Nan::Has(object, index).FromMaybe(false); +} + +template<> +inline v8::Local node::Object::get_property(v8::Isolate* isolate, const v8::Local &object, const node::String &key) { + Nan::TryCatch trycatch; + auto value = Nan::Get(object, v8::Local(key)); + + if (trycatch.HasCaught()) { + throw node::Exception(isolate, trycatch.Exception()); + } + return value.ToLocalChecked(); +} + +template<> +inline v8::Local node::Object::get_property(v8::Isolate* isolate, const v8::Local &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 &object, const node::String &key, const v8::Local &value, PropertyAttributes attributes) { + Nan::TryCatch trycatch; + + if (attributes) { + Nan::ForceSet(object, v8::Local(key), value, v8::PropertyAttribute(attributes)); + } + else { + Nan::Set(object, v8::Local(key), value); + } + + if (trycatch.HasCaught()) { + throw node::Exception(isolate, trycatch.Exception()); + } +} + +template<> +inline void node::Object::set_property(v8::Isolate* isolate, const v8::Local &object, uint32_t index, const v8::Local &value) { + Nan::TryCatch trycatch; + Nan::Set(object, index, value); + + if (trycatch.HasCaught()) { + throw node::Exception(isolate, trycatch.Exception()); + } +} + +template<> +inline std::vector node::Object::get_property_names(v8::Isolate* isolate, const v8::Local &object) { + auto maybe_array = Nan::GetPropertyNames(object); + if (maybe_array.IsEmpty()) { + return std::vector(); + } + + auto array = maybe_array.ToLocalChecked(); + uint32_t count = array->Length(); + + std::vector 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 node::Object::get_prototype(v8::Isolate* isolate, const v8::Local &object) { + return object->GetPrototype(); +} + +template<> +inline void node::Object::set_prototype(v8::Isolate* isolate, const v8::Local &object, const v8::Local &prototype) { + Nan::SetPrototype(object, prototype); +} + +template<> +inline v8::Local node::Object::create_empty(v8::Isolate* isolate) { + return Nan::New(); +} + +template<> +inline v8::Local node::Object::create_array(v8::Isolate* isolate, uint32_t length, const v8::Local values[]) { + v8::Local array = Nan::New(length); + for (uint32_t i = 0; i < length; i++) { + set_property(isolate, array, i, values[i]); + } + return array; +} + +template<> +inline v8::Local node::Object::create_date(v8::Isolate* isolate, double time) { + return Nan::New(time).ToLocalChecked(); +} + +template<> +template +inline v8::Local node::Object::create_instance(v8::Isolate* isolate, typename ClassType::Internal* internal) { + return node::ObjectWrap::create_instance(isolate, internal); +} + +template<> +template +inline bool node::Object::is_instance(v8::Isolate* isolate, const v8::Local &object) { + return node::ObjectWrap::has_instance(isolate, object); +} + +template<> +template +inline typename ClassType::Internal* node::Object::get_internal(const v8::Local &object) { + return *Nan::ObjectWrap::Unwrap>(object); +} + +template<> +template +inline void node::Object::set_internal(const v8::Local &object, typename ClassType::Internal* ptr) { + auto wrap = Nan::ObjectWrap::Unwrap>(object); + *wrap = ptr; +} + +} // js +} // realm diff --git a/src/node/node_protected.hpp b/src/node/node_protected.hpp new file mode 100644 index 00000000..7ae354f1 --- /dev/null +++ b/src/node/node_protected.hpp @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace node { + +template +class Protected { + // TODO: Figure out why Nan::CopyablePersistentTraits causes a build failure. + Nan::Persistent> m_value; + + public: + Protected(v8::Local value) : m_value(value) {} + + operator v8::Local() const { + return Nan::New(m_value); + } + bool operator==(const v8::Local &other) const { + return m_value == other; + } + bool operator!=(const v8::Local &other) const { + return m_value != other; + } + bool operator==(const Protected &other) const { + return m_value == other.m_value; + } + bool operator!=(const Protected &other) const { + return m_value != other.m_value; + } +}; + +} // node + +namespace js { + +template<> +class Protected : public node::Protected { + public: + Protected(v8::Local ctx) : node::Protected(ctx) {} + + operator v8::Isolate*() const { + return v8::Local(*this)->GetIsolate(); + } +}; + +template<> +class Protected : public node::Protected { + public: + Protected(v8::Isolate* isolate, v8::Local value) : node::Protected(value) {} +}; + +template<> +class Protected : public node::Protected { + public: + Protected(v8::Isolate* isolate, v8::Local object) : node::Protected(object) {} +}; + +template<> +class Protected : public node::Protected { + public: + Protected(v8::Isolate* isolate, v8::Local object) : node::Protected(object) {} +}; + +} // js +} // realm diff --git a/src/node/node_return_value.hpp b/src/node/node_return_value.hpp new file mode 100644 index 00000000..310cc854 --- /dev/null +++ b/src/node/node_return_value.hpp @@ -0,0 +1,65 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +class ReturnValue { + Nan::ReturnValue m_value; + + public: + ReturnValue(Nan::ReturnValue value) : m_value(value) {} + + void set(const v8::Local &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(); + } +}; + +} // js +} // realm diff --git a/src/node/node_string.hpp b/src/node/node_string.hpp new file mode 100644 index 00000000..dabe9d07 --- /dev/null +++ b/src/node/node_string.hpp @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +class String { + std::string m_str; + + public: + String(const char* s) : m_str(s) {} + String(const std::string &s) : m_str(s) {} + String(const v8::Local &s) : m_str(*Nan::Utf8String(s)) {} + String(v8::Local &&s) : String(s) {} + + operator std::string() const { + return m_str; + } + operator v8::Local() const { + return Nan::New(m_str).ToLocalChecked(); + } +}; + +} // js +} // realm diff --git a/src/node/node_types.hpp b/src/node/node_types.hpp index d99343ac..4220c173 100644 --- a/src/node/node_types.hpp +++ b/src/node/node_types.hpp @@ -53,32 +53,7 @@ struct Types { using StringPropertyEnumeratorCallback = Nan::PropertyEnumeratorCallback; }; -template -class Protected { - // TODO: Figure out why Nan::CopyablePersistentTraits causes a build failure. - Nan::Persistent> m_value; - - public: - Protected(v8::Local value) : m_value(value) {} - - operator v8::Local() const { - return Nan::New(m_value); - } - bool operator==(const v8::Local &other) const { - return m_value == other; - } - bool operator!=(const v8::Local &other) const { - return m_value != other; - } - bool operator==(const Protected &other) const { - return m_value == other.m_value; - } - bool operator!=(const Protected &other) const { - return m_value != other.m_value; - } -}; - -template +template class ObjectWrap; using String = js::String; @@ -90,398 +65,4 @@ using Exception = js::Exception; using ReturnValue = js::ReturnValue; } // node - -namespace js { - -template<> -class String { - std::string m_str; - - public: - String(const char* s) : m_str(s) {} - String(const std::string &s) : m_str(s) {} - String(const v8::Local &s) : m_str(*Nan::Utf8String(s)) {} - String(v8::Local &&s) : String(s) {} - - operator std::string() const { - return m_str; - } - operator v8::Local() const { - return Nan::New(m_str).ToLocalChecked(); - } -}; - -template<> -class ReturnValue { - Nan::ReturnValue m_value; - - public: - ReturnValue(Nan::ReturnValue value) : m_value(value) {} - - void set(const v8::Local &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 : public node::Protected { - public: - Protected(v8::Local ctx) : node::Protected(ctx) {} - - operator v8::Isolate*() const { - return v8::Local(*this)->GetIsolate(); - } -}; - -template<> -class Protected : public node::Protected { - public: - Protected(v8::Isolate* isolate, v8::Local value) : node::Protected(value) {} -}; - -template<> -class Protected : public node::Protected { - public: - Protected(v8::Isolate* isolate, v8::Local object) : node::Protected(object) {} -}; - -template<> -class Protected : public node::Protected { - public: - Protected(v8::Isolate* isolate, v8::Local object) : node::Protected(object) {} -}; - -template<> -inline v8::Local node::Context::get_global_context(v8::Isolate* isolate) { - return isolate->GetCurrentContext(); -} - -template<> -inline bool node::Value::is_array(v8::Isolate* isolate, const v8::Local &value) { - return value->IsArray(); -} - -template<> -inline bool node::Value::is_array_buffer(v8::Isolate* isolate, const v8::Local &value) { -#if REALM_V8_ARRAY_BUFFER_API - return value->IsArrayBuffer(); -#else - // TODO: Implement this! -#endif -} - -template<> -inline bool node::Value::is_array_buffer_view(v8::Isolate* isolate, const v8::Local &value) { -#if REALM_V8_ARRAY_BUFFER_API - return value->IsArrayBufferView(); -#else - // TODO: Implement this! -#endif -} - -template<> -inline bool node::Value::is_date(v8::Isolate* isolate, const v8::Local &value) { - return value->IsDate(); -} - -template<> -inline bool node::Value::is_boolean(v8::Isolate* isolate, const v8::Local &value) { - return value->IsBoolean(); -} - -template<> -inline bool node::Value::is_constructor(v8::Isolate* isolate, const v8::Local &value) { - return value->IsFunction(); -} - -template<> -inline bool node::Value::is_function(v8::Isolate* isolate, const v8::Local &value) { - return value->IsFunction(); -} - -template<> -inline bool node::Value::is_null(v8::Isolate* isolate, const v8::Local &value) { - return value->IsNull(); -} - -template<> -inline bool node::Value::is_number(v8::Isolate* isolate, const v8::Local &value) { - return value->IsNumber(); -} - -template<> -inline bool node::Value::is_object(v8::Isolate* isolate, const v8::Local &value) { - return value->IsObject(); -} - -template<> -inline bool node::Value::is_string(v8::Isolate* isolate, const v8::Local &value) { - return value->IsString(); -} - -template<> -inline bool node::Value::is_undefined(v8::Isolate* isolate, const v8::Local &value) { - return value->IsUndefined(); -} - -template<> -inline bool node::Value::is_valid(const v8::Local &value) { - return !value.IsEmpty(); -} - -template<> -inline v8::Local node::Value::from_boolean(v8::Isolate* isolate, bool boolean) { - return Nan::New(boolean); -} - -template<> -inline v8::Local node::Value::from_null(v8::Isolate* isolate) { - return Nan::Null(); -} - -template<> -inline v8::Local node::Value::from_number(v8::Isolate* isolate, double number) { - return Nan::New(number); -} - -template<> -inline v8::Local node::Value::from_string(v8::Isolate* isolate, const node::String &string) { - return v8::Local(string); -} - -template<> -inline v8::Local node::Value::from_undefined(v8::Isolate* isolate) { - return Nan::Undefined(); -} - -template<> -inline bool node::Value::to_boolean(v8::Isolate* isolate, const v8::Local &value) { - return Nan::To(value).FromMaybe(false); -} - -template<> -inline double node::Value::to_number(v8::Isolate* isolate, const v8::Local &value) { - double number = Nan::To(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 &value) { - return value->ToString(); -} - -template<> -inline v8::Local node::Value::to_object(v8::Isolate* isolate, const v8::Local &value) { - return Nan::To(value).FromMaybe(v8::Local()); -} - -template<> -inline v8::Local node::Value::to_array(v8::Isolate* isolate, const v8::Local &value) { - return to_object(isolate, value); -} - -template<> -inline v8::Local node::Value::to_date(v8::Isolate* isolate, const v8::Local &value) { - return to_object(isolate, value); -} - -template<> -inline v8::Local node::Value::to_function(v8::Isolate* isolate, const v8::Local &value) { - return value->IsFunction() ? v8::Local::Cast(value) : v8::Local(); -} - -template<> -inline v8::Local node::Value::to_constructor(v8::Isolate* isolate, const v8::Local &value) { - return to_function(isolate, value); -} - -template<> -inline v8::Local node::Function::call(v8::Isolate* isolate, const v8::Local &function, const v8::Local &this_object, size_t argc, const v8::Local arguments[]) { - Nan::TryCatch trycatch; - auto result = Nan::Call(function, this_object, (int)argc, const_cast*>(arguments)); - - if (trycatch.HasCaught()) { - throw node::Exception(isolate, trycatch.Exception()); - } - return result.ToLocalChecked(); -} - -template<> -inline v8::Local node::Function::construct(v8::Isolate* isolate, const v8::Local &function, size_t argc, const v8::Local arguments[]) { - Nan::TryCatch trycatch; - auto result = Nan::NewInstance(function, (int)argc, const_cast*>(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 &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 &object, uint32_t index) { - return Nan::Has(object, index).FromMaybe(false); -} - -template<> -inline v8::Local node::Object::get_property(v8::Isolate* isolate, const v8::Local &object, const node::String &key) { - Nan::TryCatch trycatch; - auto value = Nan::Get(object, v8::Local(key)); - - if (trycatch.HasCaught()) { - throw node::Exception(isolate, trycatch.Exception()); - } - return value.ToLocalChecked(); -} - -template<> -inline v8::Local node::Object::get_property(v8::Isolate* isolate, const v8::Local &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 &object, const node::String &key, const v8::Local &value, PropertyAttributes attributes) { - Nan::TryCatch trycatch; - - if (attributes) { - Nan::ForceSet(object, v8::Local(key), value, v8::PropertyAttribute(attributes)); - } - else { - Nan::Set(object, v8::Local(key), value); - } - - if (trycatch.HasCaught()) { - throw node::Exception(isolate, trycatch.Exception()); - } -} - -template<> -inline void node::Object::set_property(v8::Isolate* isolate, const v8::Local &object, uint32_t index, const v8::Local &value) { - Nan::TryCatch trycatch; - Nan::Set(object, index, value); - - if (trycatch.HasCaught()) { - throw node::Exception(isolate, trycatch.Exception()); - } -} - -template<> -inline std::vector node::Object::get_property_names(v8::Isolate* isolate, const v8::Local &object) { - auto maybe_array = Nan::GetPropertyNames(object); - if (maybe_array.IsEmpty()) { - return std::vector(); - } - - auto array = maybe_array.ToLocalChecked(); - uint32_t count = array->Length(); - - std::vector 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 node::Object::get_prototype(v8::Isolate* isolate, const v8::Local &object) { - return object->GetPrototype(); -} - -template<> -inline void node::Object::set_prototype(v8::Isolate* isolate, const v8::Local &object, const v8::Local &prototype) { - Nan::SetPrototype(object, prototype); -} - -template<> -inline v8::Local node::Object::create_empty(v8::Isolate* isolate) { - return Nan::New(); -} - -template<> -inline v8::Local node::Object::create_array(v8::Isolate* isolate, uint32_t length, const v8::Local values[]) { - v8::Local array = Nan::New(length); - for (uint32_t i = 0; i < length; i++) { - set_property(isolate, array, i, values[i]); - } - return array; -} - -template<> -inline v8::Local node::Object::create_date(v8::Isolate* isolate, double time) { - return Nan::New(time).ToLocalChecked(); -} - -template<> -template -inline v8::Local node::Object::create_instance(v8::Isolate* isolate, typename ClassType::Internal* internal) { - return node::ObjectWrap::create_instance(isolate, internal); -} - -template<> -template -inline bool node::Object::is_instance(v8::Isolate* isolate, const v8::Local &object) { - return node::ObjectWrap::has_instance(isolate, object); -} - -template<> -template -inline typename ClassType::Internal* node::Object::get_internal(const v8::Local &object) { - return *Nan::ObjectWrap::Unwrap>(object); -} - -template<> -template -inline void node::Object::set_internal(const v8::Local &object, typename ClassType::Internal* ptr) { - auto wrap = Nan::ObjectWrap::Unwrap>(object); - *wrap = ptr; -} - -template<> -inline v8::Local node::Exception::value(v8::Isolate* isolate, const std::string &message) { - return Nan::Error(message.c_str()); -} - -} // js } // realm diff --git a/src/node/node_value.hpp b/src/node/node_value.hpp new file mode 100644 index 00000000..0a25ad7f --- /dev/null +++ b/src/node/node_value.hpp @@ -0,0 +1,169 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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" + +namespace realm { +namespace js { + +template<> +inline bool node::Value::is_array(v8::Isolate* isolate, const v8::Local &value) { + return value->IsArray(); +} + +template<> +inline bool node::Value::is_array_buffer(v8::Isolate* isolate, const v8::Local &value) { +#if REALM_V8_ARRAY_BUFFER_API + return value->IsArrayBuffer(); +#else + // TODO: Implement this! +#endif +} + +template<> +inline bool node::Value::is_array_buffer_view(v8::Isolate* isolate, const v8::Local &value) { +#if REALM_V8_ARRAY_BUFFER_API + return value->IsArrayBufferView(); +#else + // TODO: Implement this! +#endif +} + +template<> +inline bool node::Value::is_date(v8::Isolate* isolate, const v8::Local &value) { + return value->IsDate(); +} + +template<> +inline bool node::Value::is_boolean(v8::Isolate* isolate, const v8::Local &value) { + return value->IsBoolean(); +} + +template<> +inline bool node::Value::is_constructor(v8::Isolate* isolate, const v8::Local &value) { + return value->IsFunction(); +} + +template<> +inline bool node::Value::is_function(v8::Isolate* isolate, const v8::Local &value) { + return value->IsFunction(); +} + +template<> +inline bool node::Value::is_null(v8::Isolate* isolate, const v8::Local &value) { + return value->IsNull(); +} + +template<> +inline bool node::Value::is_number(v8::Isolate* isolate, const v8::Local &value) { + return value->IsNumber(); +} + +template<> +inline bool node::Value::is_object(v8::Isolate* isolate, const v8::Local &value) { + return value->IsObject(); +} + +template<> +inline bool node::Value::is_string(v8::Isolate* isolate, const v8::Local &value) { + return value->IsString(); +} + +template<> +inline bool node::Value::is_undefined(v8::Isolate* isolate, const v8::Local &value) { + return value->IsUndefined(); +} + +template<> +inline bool node::Value::is_valid(const v8::Local &value) { + return !value.IsEmpty(); +} + +template<> +inline v8::Local node::Value::from_boolean(v8::Isolate* isolate, bool boolean) { + return Nan::New(boolean); +} + +template<> +inline v8::Local node::Value::from_null(v8::Isolate* isolate) { + return Nan::Null(); +} + +template<> +inline v8::Local node::Value::from_number(v8::Isolate* isolate, double number) { + return Nan::New(number); +} + +template<> +inline v8::Local node::Value::from_string(v8::Isolate* isolate, const node::String &string) { + return v8::Local(string); +} + +template<> +inline v8::Local node::Value::from_undefined(v8::Isolate* isolate) { + return Nan::Undefined(); +} + +template<> +inline bool node::Value::to_boolean(v8::Isolate* isolate, const v8::Local &value) { + return Nan::To(value).FromMaybe(false); +} + +template<> +inline double node::Value::to_number(v8::Isolate* isolate, const v8::Local &value) { + double number = Nan::To(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 &value) { + return value->ToString(); +} + +template<> +inline v8::Local node::Value::to_object(v8::Isolate* isolate, const v8::Local &value) { + return Nan::To(value).FromMaybe(v8::Local()); +} + +template<> +inline v8::Local node::Value::to_array(v8::Isolate* isolate, const v8::Local &value) { + return to_object(isolate, value); +} + +template<> +inline v8::Local node::Value::to_date(v8::Isolate* isolate, const v8::Local &value) { + return to_object(isolate, value); +} + +template<> +inline v8::Local node::Value::to_function(v8::Isolate* isolate, const v8::Local &value) { + return value->IsFunction() ? v8::Local::Cast(value) : v8::Local(); +} + +template<> +inline v8::Local node::Value::to_constructor(v8::Isolate* isolate, const v8::Local &value) { + return to_function(isolate, value); +} + +} // js +} // realm