diff --git a/test/test_call_from_v8.cpp b/test/test_call_from_v8.cpp index 8a8e0d66..c25d067c 100644 --- a/test/test_call_from_v8.cpp +++ b/test/test_call_from_v8.cpp @@ -32,6 +32,11 @@ void w(v8::FunctionCallbackInfo const& args) return args.GetReturnValue().Set(args.Length()); } +struct X {}; +void class_ref(X&) {} +void class_ptr(X*) {} +void class_sptr(std::shared_ptr) {} + using v8pp::detail::select_call_traits; using v8pp::detail::call_from_v8_traits; using v8pp::detail::isolate_arg_call_traits; @@ -60,6 +65,14 @@ static_assert(std::is_same, static_assert(std::is_same, v8_args_call_traits> ::value, ""); +static_assert(std::is_same::arg_convert<0>::from_type, X*>::value, "class ptr"); +static_assert(std::is_same::arg_convert<0>::from_type, X&>::value, "class ref"); +static_assert(std::is_same::arg_convert<0>::from_type, std::shared_ptr>::value, "class shared_ptr"); + +static_assert(std::is_same::arg_convert<0>::from_type, std::shared_ptr>::value, "class ptr"); +static_assert(std::is_same::arg_convert<0>::from_type, X&>::value, "class ref"); +static_assert(std::is_same::arg_convert<0>::from_type, std::shared_ptr>::value, "class shared_ptr"); + } // unnamed namespace void test_call_from_v8() diff --git a/test/test_class.cpp b/test/test_class.cpp index c28c497c..2492b586 100644 --- a/test/test_class.cpp +++ b/test/test_class.cpp @@ -44,6 +44,11 @@ struct Y : X explicit Y(int x) { var = x; ++instance_count; } ~Y() { --instance_count; } + + int useX(X& x) { return var + x.var; } + + template::object_pointer_type> + int useX_ptr(X_ptr x) { return var + x->var; } }; int Y::instance_count = 0; @@ -112,6 +117,8 @@ void test_class_() Y_class .template inherit() .template ctor() + .set("useX", &Y::useX) + .set("useX_ptr", &Y::useX_ptr) ; check_ex("already wrapped class X", [isolate]() @@ -167,7 +174,7 @@ void test_class_() check("y3_obj", v8pp::to_v8(isolate, y3) == y3_obj); check_eq("y3.var", y3->var, -3); - run_script(context, "for (i = 0; i < 10; ++i) new Y(i); i"); + run_script(context, "x = new X; for (i = 0; i < 10; ++i) { y = new Y(i); y.useX(x); y.useX_ptr(x); }"); check_eq("Y count", Y::instance_count, 10 + 4); // 10 + y + y1 + y2 + y3 run_script(context, "y = null; 0"); diff --git a/v8pp/call_from_v8.hpp b/v8pp/call_from_v8.hpp index 092279a3..62c5ba3a 100644 --- a/v8pp/call_from_v8.hpp +++ b/v8pp/call_from_v8.hpp @@ -18,7 +18,7 @@ namespace v8pp { namespace detail { -template +template struct call_from_v8_traits { static bool const is_mem_fun = std::is_member_function_pointer::value; @@ -43,15 +43,24 @@ struct call_from_v8_traits using arg_type = typename tuple_element::type; - template - using convert_type = decltype(convert>::from_v8( - std::declval(), std::declval>())); + template, + typename T = typename std::remove_reference::type, + typename U = typename std::remove_pointer::type + > + using arg_convert = typename std::conditional< + is_wrapped_class::value && use_shared_ptr, + typename std::conditional::value, + convert>, + convert + >::type, + convert + >::type; template - static convert_type + static decltype(arg_convert::from_v8(std::declval(), std::declval>())) arg_from_v8(v8::FunctionCallbackInfo const& args) { - return convert>::from_v8(args.GetIsolate(), args[Index - Offset]); + return arg_convert::from_v8(args.GetIsolate(), args[Index - Offset]); } static void check(v8::FunctionCallbackInfo const& args) @@ -63,11 +72,11 @@ struct call_from_v8_traits } }; -template -using isolate_arg_call_traits = call_from_v8_traits; +template +using isolate_arg_call_traits = call_from_v8_traits; template -struct v8_args_call_traits : call_from_v8_traits +struct v8_args_call_traits : call_from_v8_traits { template using arg_type = v8::FunctionCallbackInfo const&; @@ -102,12 +111,14 @@ using is_first_arg_isolate = std::integral_constant::template arg_type<0>, v8::Isolate*>::value>; -template +template using select_call_traits = typename std::conditional::value, typename std::conditional::value, - isolate_v8_args_call_traits, isolate_arg_call_traits>::type, + isolate_v8_args_call_traits, + isolate_arg_call_traits>::type, typename std::conditional::value, - v8_args_call_traits, call_from_v8_traits>::type + v8_args_call_traits, + call_from_v8_traits>::type >::type; template @@ -126,22 +137,22 @@ call_from_v8_impl(T& obj, F&& func, v8::FunctionCallbackInfo const& a return (obj.*func)(CallTraits::template arg_from_v8(args)...); } -template +template typename function_traits::return_type call_from_v8_impl(F&& func, v8::FunctionCallbackInfo const& args, - isolate_arg_call_traits, index_sequence) + isolate_arg_call_traits, index_sequence) { return func(args.GetIsolate(), - isolate_arg_call_traits::template arg_from_v8(args)...); + isolate_arg_call_traits::template arg_from_v8(args)...); } -template +template typename function_traits::return_type call_from_v8_impl(T& obj, F&& func, v8::FunctionCallbackInfo const& args, - isolate_arg_call_traits, index_sequence) + isolate_arg_call_traits, index_sequence) { return (obj.*func)(args.GetIsolate(), - isolate_arg_call_traits::template arg_from_v8(args)...); + isolate_arg_call_traits::template arg_from_v8(args)...); } template @@ -160,21 +171,21 @@ call_from_v8_impl(T& obj, F&& func, v8::FunctionCallbackInfo const& a return (obj.*func)(args.GetIsolate(), args); } -template +template typename function_traits::return_type call_from_v8(F&& func, v8::FunctionCallbackInfo const& args) { - using call_traits = select_call_traits; + using call_traits = select_call_traits; call_traits::check(args); return call_from_v8_impl(std::forward(func), args, call_traits(), make_index_sequence()); } -template +template typename function_traits::return_type call_from_v8(T& obj, F&& func, v8::FunctionCallbackInfo const& args) { - using call_traits = select_call_traits; + using call_traits = select_call_traits; call_traits::check(args); return call_from_v8_impl(obj, std::forward(func), args, call_traits(), make_index_sequence()); diff --git a/v8pp/class.hpp b/v8pp/class.hpp index 62ef3205..6d03efe0 100644 --- a/v8pp/class.hpp +++ b/v8pp/class.hpp @@ -553,8 +553,8 @@ class class_ static object_pointer_type call(v8::FunctionCallbackInfo const& args) { using ctor_function = object_pointer_type(*)(v8::Isolate* isolate, Args...); - return detail::call_from_v8(static_cast( - &factory::create), args); + return detail::call_from_v8( + &factory::create, args); } }; diff --git a/v8pp/convert.hpp b/v8pp/convert.hpp index b3b221fc..883af814 100644 --- a/v8pp/convert.hpp +++ b/v8pp/convert.hpp @@ -594,8 +594,7 @@ struct convert::value>::type> }; template -struct convert, - typename std::enable_if::value>::type> +struct convert, typename std::enable_if::value>::type> { using from_type = std::shared_ptr; using to_type = v8::Handle; @@ -621,6 +620,41 @@ struct convert, } }; +struct ref_from_shared_ptr {}; + +template +struct convert +{ + using from_type = T&; + using to_type = v8::Handle; + + static bool is_valid(v8::Isolate* isolate, v8::Handle value) + { + return convert>::is_valid(isolate, value); + } + + static from_type from_v8(v8::Isolate* isolate, v8::Handle value) + { + if (!is_valid(isolate, value)) + { + throw std::invalid_argument("expected Object"); + } + if (std::shared_ptr object = convert>::from_v8(isolate, value)) + { +// assert(object.use_count() > 1); + return *object; + } + throw std::runtime_error("failed to unwrap C++ object"); + } + + static to_type to_v8(v8::Isolate* isolate, T const& value) + { + v8::Handle result = convert>::to_v8(isolate, &value); + if (!result.IsEmpty()) return result; + throw std::runtime_error("failed to wrap C++ object"); + } +}; + template struct convert : convert {}; diff --git a/v8pp/function.hpp b/v8pp/function.hpp index e0d24a48..88fb8a9f 100644 --- a/v8pp/function.hpp +++ b/v8pp/function.hpp @@ -122,7 +122,7 @@ typename std::enable_if::value, typename function_traits::return_type>::type invoke(v8::FunctionCallbackInfo const& args) { - return call_from_v8(std::forward(get_external_data(args.Data())), args); + return call_from_v8(std::forward(get_external_data(args.Data())), args); } template @@ -137,8 +137,9 @@ invoke(v8::FunctionCallbackInfo const& args) v8::Isolate* isolate = args.GetIsolate(); v8::Local obj = args.This(); - return call_from_v8(*class_::unwrap_object(isolate, obj), - std::forward(get_external_data(args.Data())), args); + return call_from_v8( + *class_::unwrap_object(isolate, obj), + std::forward(get_external_data(args.Data())), args); } template