diff --git a/v8pp/class.hpp b/v8pp/class.hpp index 6345f725..faa133f5 100644 --- a/v8pp/class.hpp +++ b/v8pp/class.hpp @@ -311,9 +311,65 @@ class class_ return *this; } + template + typename std::enable_if::value + && std::is_member_function_pointer::value + && std::is_member_function_pointer::value, class_&>::type + set(char const *name, member_property_ &&property) { + using attribute_type = typename + detail::function_traits::template pointer_type; + + using property_type = member_property_< + Attribute, + GetMethod, + SetMethod + //typename detail::function_traits::template pointer_type<>, + //typename detail::function_traits::template pointer_type<> + >; + property_type prop(property); + v8::AccessorGetterCallback getter = property_type::template get; + v8::AccessorSetterCallback setter = property_type::template set; + + if (prop.is_readonly) + { + setter = nullptr; + } + + class_info_.class_function_template()->PrototypeTemplate() + ->SetAccessor(v8pp::to_v8(isolate(), name), getter, setter, + detail::set_external_data(isolate(), + std::forward(prop)), v8::DEFAULT, + v8::PropertyAttribute(v8::DontDelete | (setter ? 0 : v8::ReadOnly))); + return *this; + + } + + /// Set class member data + template + typename std::enable_if< + std::is_member_object_pointer::value, class_&>::type + set_const(char const *name, Attribute attribute) + { + v8::HandleScope scope(isolate()); + + using attribute_type = typename + detail::function_traits::template pointer_type; + attribute_type attr(attribute); + v8::AccessorGetterCallback getter = &member_get; + + class_info_.class_function_template()->PrototypeTemplate() + ->SetAccessor(v8pp::to_v8(isolate(), name), getter, nullptr, + detail::set_external_data(isolate(), + std::forward(attr)), v8::DEFAULT, + v8::PropertyAttribute(v8::DontDelete | v8::ReadOnly)); + return *this; + } + /// Set value as a read-only property template - class_& set_const(char const* name, Value const& value) + typename std::enable_if< + !std::is_member_object_pointer::value, class_&>::type + set_const(char const* name, Value const& value) { v8::HandleScope scope(isolate()); diff --git a/v8pp/context.cpp b/v8pp/context.cpp index 6fd92f17..a1fd045c 100644 --- a/v8pp/context.cpp +++ b/v8pp/context.cpp @@ -273,4 +273,10 @@ v8::Local context::run_script(std::string const& source, return scope.Escape(result); } + v8::Local context::impl() { + v8::EscapableHandleScope handleScope(isolate_); + v8::Local ret = v8::Local::New(isolate_, impl_); + return handleScope.Escape(ret); + } + } // namespace v8pp diff --git a/v8pp/context.hpp b/v8pp/context.hpp index f4084f8f..2b297d11 100644 --- a/v8pp/context.hpp +++ b/v8pp/context.hpp @@ -68,6 +68,8 @@ class context return set(name, cl.js_function_template()->GetFunction(isolate_->GetCurrentContext()).ToLocalChecked()); } + v8::Local impl(); + private: bool own_isolate_; v8::Isolate* isolate_; diff --git a/v8pp/property.hpp b/v8pp/property.hpp index 9cdcdb82..4f5d0965 100644 --- a/v8pp/property.hpp +++ b/v8pp/property.hpp @@ -19,6 +19,9 @@ namespace v8pp { template struct property_; +template +struct member_property_; + namespace detail { struct getter_tag {}; @@ -53,6 +56,14 @@ template using is_setter = std::integral_constant::arg_count == 1 && is_void_return::value>; +template +using is_loose_setter = std::integral_constant::arg_count == 1 && + std::is_member_function_pointer::value && + std::is_same< + typename std::decay::return_type>::type, + typename std::decay::arguments>::type>::type>::value>; + template using is_direct_setter = std::integral_constant::arg_count == 3 && @@ -318,6 +329,114 @@ struct rw_property_impl } }; +template +struct rw_member_property { + using property_type = member_property_; + + using class_type = typename std::decay::arguments> ::type>::type; + + static_assert(std::is_member_pointer::value, "member property must be `&T::member`"); + + static_assert(is_getter::value + || is_direct_getter::value + || is_isolate_getter::value, + "property get function must be either `T ()` or \ + `void (v8::Local name, v8::PropertyCallbackInfo const& info)` or \ + `T (v8::Isolate*)`"); + + static void get_impl(class_type& obj, Attribute attr, Get get, v8::Local, + v8::PropertyCallbackInfo const& info, getter_tag) + { + info.GetReturnValue().Set(to_v8(info.GetIsolate(), ((obj.*attr).*get)())); + } + + static void get_impl(class_type& obj, Attribute attr, Get get, + v8::Local name, v8::PropertyCallbackInfo const& info, + direct_getter_tag) + { + ((obj.*attr).*get)(name, info); + } + + static void get_impl(class_type& obj, Attribute attr, Get get, v8::Local, + v8::PropertyCallbackInfo const& info, isolate_getter_tag) + { + v8::Isolate* isolate = info.GetIsolate(); + + info.GetReturnValue().Set(to_v8(isolate, ((obj.*attr).*get)(isolate))); + } + + template + static void get(v8::Local name, + v8::PropertyCallbackInfo const& info) + try + { + auto obj = v8pp::class_::unwrap_object(info.GetIsolate(), info.This()); + assert(obj); + + property_type const& prop = detail::get_external_data(info.Data()); + assert(prop.getter); + assert(prop.attr); + + if (obj && prop.getter && prop.attr) + { + get_impl(*obj, prop.attr, prop.getter, name, info, select_getter_tag()); + } + } + catch (std::exception const& ex) + { + info.GetReturnValue().Set(throw_ex(info.GetIsolate(), ex.what())); + } + + static void set_impl(class_type& obj, Attribute attr, Set set, v8::Local, + v8::Local value, v8::PropertyCallbackInfo const& info, + setter_tag) + { + using value_type = typename call_from_v8_traits::template arg_type<0>; + + ((obj.*attr).*set)(v8pp::from_v8(info.GetIsolate(), value)); + } + + static void set_impl(class_type& obj, Attribute attr, Set set, v8::Local name, + v8::Local value, v8::PropertyCallbackInfo const& info, + direct_setter_tag) + { + ((obj.*attr).*set)(name, value, info); + } + + static void set_impl(class_type& obj, Attribute attr, Set set, v8::Local, + v8::Local value, v8::PropertyCallbackInfo const& info, + isolate_setter_tag) + { + using value_type = typename call_from_v8_traits::template arg_type<1>; + + v8::Isolate* isolate = info.GetIsolate(); + + ((obj.*attr).*set)(isolate, v8pp::from_v8(isolate, value)); + } + + template + static void set(v8::Local name, v8::Local value, + v8::PropertyCallbackInfo const& info) + try + { + auto obj = v8pp::class_::unwrap_object(info.GetIsolate(), info.This()); + assert(obj); + + property_type const& prop = detail::get_external_data(info.Data()); + assert(prop.setter); + + if (obj && prop.setter) + { + set_impl(*obj, prop.attr, prop.setter, name, value, info, select_setter_tag()); + } + } + catch (std::exception const& ex) + { + info.GetReturnValue().Set(throw_ex(info.GetIsolate(), ex.what())); + } + +}; } // namespace detail /// Property with get and set functions @@ -386,6 +505,53 @@ struct property_ } }; +/// Property with get and set functions +template +struct member_property_ + : detail::rw_member_property + { + static_assert(std::is_member_pointer::value, "member property must be `&T::member`"); + + static_assert(detail::is_getter::value + || detail::is_direct_getter::value + || detail::is_isolate_getter::value, + "property get function must be either `T ()` or " + "`void (v8::Local name, v8::PropertyCallbackInfo const& info)` or " + "`T (v8::Isolate*)`"); + + static_assert(detail::is_loose_setter::value, "wtf?"); + + static_assert(detail::is_setter::value + || detail::is_direct_setter::value + || detail::is_isolate_setter::value + || detail::is_loose_setter::value, + "property set function must be either `void (T)` or \ + `void (v8::Local name, v8::Local value, v8::PropertyCallbackInfo const& info)` or \ + `void (v8::Isolate*, T)` or \ + `T& (T::()(const T2&)`" + ); + + Attribute attr; + Get getter; + Set setter; + + enum { is_readonly = false }; + + member_property_(Attribute attr, Get getter, Set setter) + : attr(attr) + , getter(getter) + , setter(setter) + { + } + + template + member_property_(member_property_ const& other) + : attr(other.attr) + , getter(other.getter) + , setter(other.setter) + { + } + }; /// Create read/write property from get and set member functions template property_ property(Get get, Set set) @@ -400,6 +566,11 @@ property_ property(Get get) return property_(get); } +template +member_property_ property(Attribute attr, Get get, Set set) { + return member_property_(attr, get, set); +} + } // namespace v8pp #endif // V8PP_PROPERTY_HPP_INCLUDED