forked from enlightenment/efl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
11 KiB
284 lines
11 KiB
#ifndef EFL_EO_JS_CALL_FUNCTION_HH |
|
#define EFL_EO_JS_CALL_FUNCTION_HH |
|
|
|
#include <eina_tuple.hh> |
|
#include <eina_tuple_c.hh> |
|
#include <eina_function.hh> |
|
|
|
#include <cstdlib> |
|
#include <functional> |
|
#include <iostream> |
|
#include <cassert> |
|
#include <vector> |
|
|
|
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<eina::js::compatibility_return_type(eina::js::compatibility_callback_info_type)>* |
|
f = static_cast<std::function<eina::js::compatibility_return_type(eina::js::compatibility_callback_info_type)>*>(data); |
|
return (*f)(args); |
|
} |
|
|
|
template <typename In, std::size_t I> |
|
struct is_in : eina::_mpl::tuple_contains<std::integral_constant<std::size_t, I>, In> |
|
{}; |
|
|
|
template <typename In, std::size_t I> |
|
struct arg_index : std::integral_constant<std::size_t, |
|
std::conditional<is_in<In, I>::value, std::integral_constant<std::size_t, 1>, std::integral_constant<std::size_t, 0>>::type::value + |
|
arg_index<In, I - 1>::value> |
|
{}; |
|
|
|
template <typename In> |
|
struct arg_index<In, 0> : std::integral_constant<std::size_t, 0> |
|
{}; |
|
|
|
template <typename In, typename Out, typename Ownership, typename F, typename Return, typename Parameters> |
|
struct method_caller |
|
{ |
|
typedef typename eo::js::eo_function_params<F>::type parameters_t; |
|
|
|
template <std::size_t I> |
|
struct is_out : eina::_mpl::tuple_contains<std::integral_constant<std::size_t, I>, Out> |
|
{}; |
|
|
|
template <std::size_t I> |
|
struct is_inout : std::integral_constant<bool, |
|
eina::_mpl::tuple_contains<std::integral_constant<std::size_t, I>, Out>::value && |
|
eina::_mpl::tuple_contains<std::integral_constant<std::size_t, I>, In>::value> |
|
{}; |
|
|
|
template <std::size_t I, typename Outs> |
|
static |
|
typename std::tuple_element<I, parameters_t>::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<I, Parameters>::type; |
|
const auto js_index = arg_index<In, I>::value; |
|
|
|
return eina::js::get_value_from_javascript |
|
(args[js_index], isolate, class_name, eina::js::value_tag<Param>()); |
|
} |
|
|
|
template <std::size_t I, typename Outs> |
|
static |
|
typename std::add_pointer< |
|
typename std::tuple_element |
|
<eina::_mpl::tuple_find<std::integral_constant<std::size_t, I>, 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<eina::_mpl::tuple_find<std::integral_constant<std::size_t, I>, Out>::value> |
|
(outs); |
|
} |
|
|
|
template <typename OutParameter, std::size_t I, typename R> |
|
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<OutParameter>(r, eina::js::value_tag<OutParameter>{}), |
|
args.GetIsolate(), |
|
class_names[I]), |
|
args); |
|
} |
|
|
|
template <typename OutParameters, typename Outs> |
|
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<Outs>::value == 1>::type* = 0) const |
|
{ |
|
using OutParameter = typename std::tuple_element<0, OutParameters>::type; |
|
return create_return_unique_value<OutParameter, std::tuple_element<0, Out>::type::value>(args, std::get<0u>(outs)); |
|
} |
|
|
|
template <typename OutParameters, typename Outs> |
|
eina::js::compatibility_return_type |
|
create_return_value(eina::js::compatibility_callback_info_type |
|
, Outs const& |
|
, typename std::enable_if<std::tuple_size<Outs>::value == 0>::type* = 0) const |
|
{ |
|
// nothing |
|
return eina::js::compatibility_return(); |
|
} |
|
|
|
template <typename OutParameters, typename Outs> |
|
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<Outs>::value > 1)>::type* = 0) const |
|
{ |
|
v8::Isolate* isolate = args.GetIsolate(); |
|
int const length = std::tuple_size<Outs>::value; |
|
v8::Local<v8::Array> ret = eina::js::compatibility_new<v8::Array>(isolate, length); |
|
set_return<OutParameters, 0u>(isolate, ret, outs, eina::make_index_sequence<std::tuple_size<Outs>::value>()); |
|
return eina::js::compatibility_return(ret, args); |
|
} |
|
|
|
template <typename OutParameters, typename R, typename Outs> |
|
eina::js::compatibility_return_type |
|
create_return_value(eina::js::compatibility_callback_info_type args |
|
, R const& r |
|
, Outs const& |
|
, typename std::enable_if<std::tuple_size<Outs>::value == 0>::type* = 0) const |
|
{ |
|
return create_return_unique_value<Return, std::tuple_size<Ownership>::value>(args, r); |
|
} |
|
|
|
template <typename OutParameters, std::size_t Offset, typename Outs, std::size_t...S> |
|
void set_return(v8::Isolate* isolate, v8::Local<v8::Array> r |
|
, Outs const& outs, eina::index_sequence<S...>) const |
|
{ |
|
std::initializer_list<int> l |
|
= {(r->Set(S+Offset, eina::js::get_value_from_c( |
|
eina::js::wrap_value<typename std::tuple_element<S, OutParameters>::type>(std::get<S>(outs), eina::js::value_tag<typename std::tuple_element<S, OutParameters>::type>{}), |
|
isolate, |
|
class_names[std::tuple_element<S, Out>::type::value])),0)...}; |
|
static_cast<void>(l); |
|
} |
|
|
|
template <typename OutParameters, typename R, typename Outs> |
|
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<std::tuple_size<Outs>::value != 0>::type* = 0) const |
|
{ |
|
v8::Isolate* isolate = args.GetIsolate(); |
|
int const length = std::tuple_size<Outs>::value + 1; |
|
v8::Local<v8::Array> ret = eina::js::compatibility_new<v8::Array>(isolate, length); |
|
ret->Set(0, eina::js::get_value_from_c( |
|
eina::js::wrap_value<Return>(r, eina::js::value_tag<Return>{}), |
|
isolate, |
|
class_names[std::tuple_size<Ownership>::value])); |
|
set_return<OutParameters, 1u>(isolate, ret, outs, eina::make_index_sequence<std::tuple_size<Outs>::value>()); |
|
return eina::js::compatibility_return(ret, args); |
|
} |
|
|
|
template <std::size_t I, typename Outs> |
|
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<typename std::tuple_element<I, Parameters>::type>::type; |
|
|
|
const auto js_index = arg_index<In, I>::value; |
|
|
|
*get_value<I>(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<Param>());; |
|
} |
|
|
|
template <std::size_t I, typename Outs> |
|
static void |
|
init_inout(eina::js::compatibility_callback_info_type |
|
, Outs& |
|
, v8::Isolate* |
|
, char const* |
|
, std::false_type) |
|
{ |
|
} |
|
|
|
template <typename OutParameters, std::size_t... I> |
|
eina::js::compatibility_return_type |
|
aux(Eo* eo, eina::js::compatibility_callback_info_type args, eina::index_sequence<I...> |
|
, std::true_type) const |
|
{ |
|
typename eina::_mpl::tuple_transform<Out, out_transform<parameters_t> >::type outs {}; |
|
static_cast<void>(outs); |
|
|
|
std::initializer_list<int> l = |
|
{(init_inout<I>(args, outs, args.GetIsolate(), class_names[I], typename is_inout<I>::type()), 0)...}; |
|
static_cast<void>(l); |
|
|
|
function(eo, get_value<I>(args, outs, args.GetIsolate(), class_names[I], typename is_out<I>::type())...); |
|
return create_return_value<OutParameters>(args, outs); |
|
} |
|
|
|
template <typename OutParameters, std::size_t... I> |
|
eina::js::compatibility_return_type |
|
aux(Eo* eo, eina::js::compatibility_callback_info_type args, eina::index_sequence<I...> |
|
, std::false_type) const |
|
{ |
|
typename eina::_mpl::tuple_transform<Out, out_transform<parameters_t> >::type outs {}; |
|
static_cast<void>(outs); |
|
|
|
std::initializer_list<int> l = |
|
{(init_inout<I>(args, outs, args.GetIsolate(), class_names[I], typename is_inout<I>::type()), 0)...}; |
|
static_cast<void>(l); |
|
|
|
typename eina::_mpl::function_return<F>::type r = |
|
function(eo, get_value<I>(args, outs, args.GetIsolate(), class_names[I], typename is_out<I>::type())...); |
|
return create_return_value<OutParameters>(args, r, outs); |
|
} |
|
|
|
template <typename P> |
|
struct out_transform |
|
{ |
|
template <typename T> |
|
struct apply |
|
{ |
|
typedef typename std::remove_pointer<typename std::tuple_element<T::value, P>::type>::type type; |
|
}; |
|
}; |
|
|
|
eina::js::compatibility_return_type operator()(eina::js::compatibility_callback_info_type args) |
|
{ |
|
using OutParameters = typename eina::_mpl::tuple_transform<Out, out_transform<Parameters> >::type; |
|
|
|
int input_parameters = std::tuple_size<In>::value; |
|
if(input_parameters <= args.Length()) |
|
{ |
|
v8::Local<v8::Object> self = args.This(); |
|
v8::Local<v8::Value> external = self->GetInternalField(0); |
|
Eo* eo = static_cast<Eo*>(v8::External::Cast(*external)->Value()); |
|
try |
|
{ |
|
aux<OutParameters>(eo, args, |
|
eina::make_index_sequence<std::tuple_size<parameters_t>::value>(), |
|
std::is_same<void, Return>()); |
|
} |
|
catch(std::logic_error const&) |
|
{ |
|
return eina::js::compatibility_return(); |
|
} |
|
} |
|
else |
|
{ |
|
return eina::js::compatibility_throw |
|
(v8::Exception::TypeError |
|
(eina::js::compatibility_new<v8::String>(nullptr, "Expected more arguments for this call"))); |
|
} |
|
} |
|
|
|
template <typename A> |
|
method_caller(F f, A&& c) |
|
: function(f) |
|
, class_names(std::forward<A>(c)) |
|
{} |
|
|
|
F function; |
|
/// Hold the names of the type of each argument, with the return's type name at the end |
|
std::array<const char*, std::tuple_size<Ownership>::value + 1> class_names; |
|
}; |
|
|
|
template <typename In, typename Out, typename Ownership, typename Return, typename Parameters, std::size_t N, typename F> |
|
v8::Handle<v8::Value> call_function_data(v8::Isolate* isolate, std::array<const char*, N> class_names, F f) |
|
{ |
|
return eina::js::compatibility_new<v8::External> |
|
(isolate, new std::function<eina::js::compatibility_return_type(eina::js::compatibility_callback_info_type const&)> |
|
(method_caller<In, Out, Ownership, F, Return, Parameters>{f, class_names})); |
|
} |
|
|
|
} } } |
|
|
|
#endif
|
|
|