#ifndef EFL_EO_JS_CALL_FUNCTION_HH #define EFL_EO_JS_CALL_FUNCTION_HH #include #include #include #include #include #include #include #include namespace efl { namespace eo { namespace js { inline eina::js::compatibility_return_type call_function(eina::js::compatibility_callback_info_type args) { void* data = v8::External::Cast(*args.Data())->Value(); std::function* f = static_cast*>(data); return (*f)(args); } template struct is_in : eina::_mpl::tuple_contains, In> {}; template struct arg_index : std::integral_constant::value, std::integral_constant, std::integral_constant>::type::value + arg_index::value> {}; template struct arg_index : std::integral_constant {}; template struct method_caller { typedef typename eo::js::eo_function_params::type parameters_t; template struct is_out : eina::_mpl::tuple_contains, Out> {}; template struct is_inout : std::integral_constant, Out>::value && eina::_mpl::tuple_contains, In>::value> {}; template static typename std::tuple_element::type get_value(eina::js::compatibility_callback_info_type args, Outs& /*outs*/, v8::Isolate* isolate, char const* class_name , std::false_type) { using Param = typename std::tuple_element::type; const auto js_index = arg_index::value; return eina::js::get_value_from_javascript (args[js_index], isolate, class_name, eina::js::value_tag()); } template static typename std::add_pointer< typename std::tuple_element , Out>::value , Outs>::type>::type get_value(eina::js::compatibility_callback_info_type, Outs& outs, v8::Isolate*, char const* , std::true_type) { return &std::get, Out>::value> (outs); } template eina::js::compatibility_return_type create_return_unique_value(eina::js::compatibility_callback_info_type args , R const& r) const { return eina::js::compatibility_return( eina::js::get_value_from_c( eina::js::wrap_value(r, eina::js::value_tag{}), args.GetIsolate(), class_names[I]), args); } template eina::js::compatibility_return_type create_return_value(eina::js::compatibility_callback_info_type args , Outs const& outs , typename std::enable_if::value == 1>::type* = 0) const { using OutParameter = typename std::tuple_element<0, OutParameters>::type; return create_return_unique_value::type::value>(args, std::get<0u>(outs)); } template eina::js::compatibility_return_type create_return_value(eina::js::compatibility_callback_info_type , Outs const& , typename std::enable_if::value == 0>::type* = 0) const { // nothing return eina::js::compatibility_return(); } template eina::js::compatibility_return_type create_return_value(eina::js::compatibility_callback_info_type args , Outs const& outs , typename std::enable_if<(std::tuple_size::value > 1)>::type* = 0) const { v8::Isolate* isolate = args.GetIsolate(); int const length = std::tuple_size::value; v8::Local ret = eina::js::compatibility_new(isolate, length); set_return(isolate, ret, outs, eina::make_index_sequence::value>()); return eina::js::compatibility_return(ret, args); } template eina::js::compatibility_return_type create_return_value(eina::js::compatibility_callback_info_type args , R const& r , Outs const& , typename std::enable_if::value == 0>::type* = 0) const { return create_return_unique_value::value>(args, r); } template void set_return(v8::Isolate* isolate, v8::Local r , Outs const& outs, eina::index_sequence) const { std::initializer_list l = {(r->Set(S+Offset, eina::js::get_value_from_c( eina::js::wrap_value::type>(std::get(outs), eina::js::value_tag::type>{}), isolate, class_names[std::tuple_element::type::value])),0)...}; static_cast(l); } template eina::js::compatibility_return_type create_return_value(eina::js::compatibility_callback_info_type args , R const& r , Outs const& outs , typename std::enable_if::value != 0>::type* = 0) const { v8::Isolate* isolate = args.GetIsolate(); int const length = std::tuple_size::value + 1; v8::Local ret = eina::js::compatibility_new(isolate, length); ret->Set(0, eina::js::get_value_from_c( eina::js::wrap_value(r, eina::js::value_tag{}), isolate, class_names[std::tuple_size::value])); set_return(isolate, ret, outs, eina::make_index_sequence::value>()); return eina::js::compatibility_return(ret, args); } template static void init_inout(eina::js::compatibility_callback_info_type args , Outs& outs , v8::Isolate* isolate , char const* class_name , std::true_type) { using Param = typename std::remove_pointer::type>::type; const auto js_index = arg_index::value; *get_value(args, outs, args.GetIsolate(), class_name, std::true_type()) = eina::js::get_value_from_javascript(args[js_index], isolate, class_name, eina::js::value_tag());; } template static void init_inout(eina::js::compatibility_callback_info_type , Outs& , v8::Isolate* , char const* , std::false_type) { } template eina::js::compatibility_return_type aux(Eo* eo, eina::js::compatibility_callback_info_type args, eina::index_sequence , std::true_type) const { typename eina::_mpl::tuple_transform >::type outs {}; static_cast(outs); std::initializer_list l = {(init_inout(args, outs, args.GetIsolate(), class_names[I], typename is_inout::type()), 0)...}; static_cast(l); function(eo, get_value(args, outs, args.GetIsolate(), class_names[I], typename is_out::type())...); return create_return_value(args, outs); } template eina::js::compatibility_return_type aux(Eo* eo, eina::js::compatibility_callback_info_type args, eina::index_sequence , std::false_type) const { typename eina::_mpl::tuple_transform >::type outs {}; static_cast(outs); std::initializer_list l = {(init_inout(args, outs, args.GetIsolate(), class_names[I], typename is_inout::type()), 0)...}; static_cast(l); typename eina::_mpl::function_return::type r = function(eo, get_value(args, outs, args.GetIsolate(), class_names[I], typename is_out::type())...); return create_return_value(args, r, outs); } template struct out_transform { template struct apply { typedef typename std::remove_pointer::type>::type type; }; }; eina::js::compatibility_return_type operator()(eina::js::compatibility_callback_info_type args) { using OutParameters = typename eina::_mpl::tuple_transform >::type; int input_parameters = std::tuple_size::value; if(input_parameters <= args.Length()) { v8::Local self = args.This(); v8::Local external = self->GetInternalField(0); Eo* eo = static_cast(v8::External::Cast(*external)->Value()); try { aux(eo, args, eina::make_index_sequence::value>(), std::is_same()); } catch(std::logic_error const&) { return eina::js::compatibility_return(); } } else { return eina::js::compatibility_throw (v8::Exception::TypeError (eina::js::compatibility_new(nullptr, "Expected more arguments for this call"))); } } template method_caller(F f, A&& c) : function(f) , class_names(std::forward(c)) {} F function; /// Hold the names of the type of each argument, with the return's type name at the end std::array::value + 1> class_names; }; template v8::Handle call_function_data(v8::Isolate* isolate, std::array class_names, F f) { return eina::js::compatibility_new (isolate, new std::function (method_caller{f, class_names})); } } } } #endif