10 #include <unordered_map> 31 template<
class T,
class =
void>
41 template<
typename T,
class =
void>
44 template<
class T,
class =
void>
57 std::remove_pointer_t<
58 std::remove_reference_t<T>
65 #define V8TOOLKIT_COMMA , 69 #define HANDLE_FUNCTION_VALUES \ 71 if (value->IsFunction()) { \ 72 value = v8toolkit::call_simple_javascript_function(isolate, v8::Local<v8::Function>::Cast(value)); \ 77 #define CAST_TO_NATIVE_CLASS_ONLY(TYPE) \ 79 struct v8toolkit::CastToNative<TYPE> { \ 80 TYPE operator()(v8::Isolate * isolate, v8::Local<v8::Value> value) const; \ 81 static constexpr bool callable(){return true;} \ 85 #define CAST_TO_NATIVE_CODE(TYPE, CODE) \ 86 TYPE CastToNative<TYPE>::operator()(v8::Isolate * isolate, v8::Local<v8::Value> value) const CODE 89 #define CAST_TO_NATIVE(TYPE, CODE) \ 90 CAST_TO_NATIVE_CLASS_ONLY(TYPE) \ 91 inline CAST_TO_NATIVE_CODE(TYPE, CODE) 96 #define CAST_TO_JS(TYPE, FUNCTION_BODY) \ 98 struct v8toolkit::CastToJS<TYPE> { \ 99 v8::Local<v8::Value> operator()(v8::Isolate * isolate, TYPE const & value) const FUNCTION_BODY \ 105 template<
typename T,
class>
106 struct CastToNative {
107 template<
class U = T>
109 static_assert(!std::is_pointer<T>::value,
"Cannot CastToNative to a pointer type of an unwrapped type");
110 static_assert(!(std::is_lvalue_reference<T>::value && !std::is_const<std::remove_reference_t<T>>::value),
111 "Cannot CastToNative to a non-const " 112 "lvalue reference of an unwrapped type because there is no lvalue variable to send");
113 static_assert(!is_wrapped_type_v<T>,
114 "CastToNative<SomeWrappedType> shouldn't fall through to this specialization");
115 static_assert(always_false_v<T>,
"Invalid CastToNative configuration");
169 template<
class... Ts, std::size_t... Is>
174 template<
class... Ts>
178 if (!value->IsArray()) {
179 throw v8toolkit::CastException(fmt::format(
"CastToNative tried to create a {} object but was not given a JavaScript array",
demangle<std::tuple<Ts...>>()));
193 std::enable_if_t<!is_wrapped_type_v<T>>> {
202 struct CastToNative<T const &, std::enable_if_t<!is_wrapped_type_v<T>>> {
222 template<
template<
class,
class>
class ContainerTemplate,
class FirstT,
class SecondT>
225 if (value->IsArray()) {
228 auto error = fmt::format(
"Array to std::pair must be length 2, but was {}", length);
229 isolate->ThrowException(v8::String::NewFromUtf8(isolate, error.c_str()));
232 auto context = isolate->GetCurrentContext();
233 auto array = get_value_as<v8::Array>(value);
234 auto first = array->Get(context, 0).ToLocalChecked();
235 auto second = array->Get(context, 1).ToLocalChecked();
240 auto error = fmt::format(
"CastToNative<std::pair<T>> requires an array but instead got %s\n",
stringify_value(isolate, value));
241 std::cout << error << std::endl;
247 template<
class FirstT,
class SecondT>
250 return pair_type_helper<std::pair, FirstT, SecondT>(isolate, value);
264 if(value->IsFunction()) {
268 "CastToNative<v8::Local<v8::Function>> requires a javascript function but instead got '{}'",
284 return std::unique_ptr<char[]>(strdup(*v8::String::Utf8Value(value)));
305 template<
template<
class,
class...>
class VectorTemplate,
class T,
class... Rest>
307 VectorTemplate<std::remove_reference_t<std::result_of_t<CastToNative<T>(v8::Isolate *,
v8::Local<v8::Value>)>>, Rest...>
310 static_assert(!std::is_reference<ValueType>::value,
"vector-like value type cannot be reference");
311 using ResultType = VectorTemplate<ValueType, Rest...>;
313 auto context = isolate->GetCurrentContext();
315 if (value->IsArray()) {
318 for (
int i = 0; i < array_length; i++) {
319 auto value = array->Get(context, i).ToLocalChecked();
323 throw CastException(fmt::format(
"CastToNative<std::vector-like<{}>> requires an array but instead got JS: '{}'",
331 template<
template<
class,
class...>
class SetTemplate,
class T,
class... Rest>
333 SetTemplate<std::remove_reference_t<std::result_of_t<CastToNative<T>(v8::Isolate *,
v8::Local<v8::Value>)>>, Rest...>
336 static_assert(!std::is_reference<ValueType>::value,
"Set-like value type cannot be reference");
337 using ResultType = SetTemplate<ValueType, Rest...>;
339 auto context = isolate->GetCurrentContext();
341 if (value->IsArray()) {
344 for (
int i = 0; i < array_length; i++) {
345 auto value = array->Get(context, i).ToLocalChecked();
349 throw CastException(fmt::format(
"CastToNative<std::vector-like<{}>> requires an array but instead got JS: '{}'",
360 template<
class T,
class... Rest>
361 struct CastToNative<std::vector<T, Rest...>, std::enable_if_t<std::is_copy_constructible<T>::value>> {
373 template<
class T,
class... Rest>
374 struct CastToNative<std::vector<T, Rest...> &&, std::enable_if_t<!is_wrapped_type_v<std::vector<T, Rest...>>>> {
378 return vector_type_helper<std::vector, std::add_rvalue_reference_t<T>, Rest...>(isolate, value);
385 template<
class T,
class... Rest>
386 struct CastToNative<std::set<T, Rest...>, std::enable_if_t<!is_wrapped_type_v<std::set<T, Rest...>>>> {
390 return set_type_helper<std::set, std::add_rvalue_reference_t<T>, Rest...>(isolate, value);
403 template<
class T,
class... Rest>
406 std::is_copy_constructible<T>::value &&
407 !is_wrapped_type_v<T>
412 return std::unique_ptr<T, Rest...>(
new T(
CastToNative<T>()(isolate, value)));
429 template<
class T,
class... Rest>
430 struct CastToNative<std::unique_ptr<T, Rest...>, std::enable_if_t<!std::is_copy_constructible<T>::value && !is_wrapped_type_v<T>>>;
432 template<template<class,class,class...> class ContainerTemplate, class Key, class Value, class... Rest>
433 ContainerTemplate<Key, Value, Rest...>
map_type_helper(v8::Isolate * isolate, v8::Local<v8::Value> value) {
436 if (!value->IsObject()) {
438 fmt::format(
"Javascript Object type must be passed in to convert to std::map - instead got {}",
442 auto context = isolate->GetCurrentContext();
444 ContainerTemplate<
Key,
Value, Rest...> results;
462 template<
template<
class,
class,
class...>
class ContainerTemplate,
class Key,
class Value,
class... Rest>
465 if (!value->IsObject()) {
467 fmt::format(
"Javascript Object type must be passed in to convert to std::map - instead got {}",
471 auto context = isolate->GetCurrentContext();
473 ContainerTemplate<
Key,
Value, Rest...> results;
506 template<
typename T,
class =
void>
508 static_assert(always_false_v<T>,
"Fallback CastToJS template isn't allowed");
513 struct CastToJS<T &, std::enable_if_t<!is_wrapped_type_v<T>>> {
521 struct CastToJS<T *, std::enable_if_t<!is_wrapped_type_v<T>>> {
523 if (value ==
nullptr) {
524 return v8::Undefined(isolate);
539 std::enable_if_t<!is_wrapped_type_v<T>>
549 CAST_TO_JS(
bool, {
return v8::Boolean::New(isolate, value);});
553 CAST_TO_JS(
char, {
return v8::Integer::New(isolate, value);});
554 CAST_TO_JS(
unsigned char, {
return v8::Integer::New(isolate, value);});
556 CAST_TO_JS(
wchar_t, {
return v8::Number::New(isolate, value);});
557 CAST_TO_JS(char16_t, {
return v8::Integer::New(isolate, value);});
558 CAST_TO_JS(char32_t, {
return v8::Integer::New(isolate, value);});
559 CAST_TO_JS(
short, {
return v8::Integer::New(isolate, value);});
560 CAST_TO_JS(
unsigned short, {
return v8::Integer::New(isolate, value);});
564 CAST_TO_JS(
int, {
return v8::Number::New(isolate, value);});
566 CAST_TO_JS(
unsigned int, {
return v8::Number::New(isolate, value);});
567 CAST_TO_JS(
long, {
return v8::Number::New(isolate, value);});
569 CAST_TO_JS(
unsigned long, {
return v8::Number::New(isolate, value);});
570 CAST_TO_JS(
long long, {
return v8::Number::New(isolate, static_cast<double>(value));});
571 CAST_TO_JS(
unsigned long long, {
return v8::Number::New(isolate, static_cast<double>(value));});
576 CAST_TO_JS(
float, {
return v8::Number::New(isolate, value);});
577 CAST_TO_JS(
double, {
return v8::Number::New(isolate, value);});
578 CAST_TO_JS(
long double, {
return v8::Number::New(isolate, value);});
581 CAST_TO_JS(
std::string, {
return v8::String::NewFromUtf8(isolate, value.c_str(), v8::String::kNormalString, value.length());});
583 CAST_TO_JS(
char *, {
return v8::String::NewFromUtf8(isolate, value);});
584 CAST_TO_JS(
char const *, {
return v8::String::NewFromUtf8(isolate, value);});
594 template<
class R,
class... Params>
597 return v8::String::NewFromUtf8(isolate,
"CastToJS of std::function not supported yet");
614 return value.Get(isolate);
627 return value.Get(isolate);
635 template<
class T1,
class T2>
639 return this->operator()(isolate, pair);
644 template<
template<
class,
class,
class...>
class MapTemplate,
class KeyType,
class ValueType,
class ReferenceTypeIndicator,
class... Rest>
646 assert(isolate->InContext());
647 auto context = isolate->GetCurrentContext();
648 auto object = v8::Object::New(isolate);
650 using KeyForwardT = std::conditional_t<std::is_rvalue_reference_v<ReferenceTypeIndicator>, std::add_rvalue_reference_t<KeyType>, std::add_lvalue_reference_t<KeyType>>;
651 using ValueForwardT = std::conditional_t<std::is_rvalue_reference_v<ReferenceTypeIndicator>, std::add_rvalue_reference_t<ValueType>, std::add_lvalue_reference_t<ValueType>>;
654 for(
auto & pair : map) {
655 (void) object->Set(context,
656 CastToJS<std::remove_reference_t<KeyType>> ()(isolate, std::forward<KeyForwardT> (const_cast<KeyForwardT> (pair.first ))),
657 CastToJS<std::remove_reference_t<ValueType>>()(isolate, std::forward<ValueForwardT>(const_cast<ValueForwardT>(pair.second)))
664 template<
template<
class...>
class VectorTemplate,
class ValueType,
class... Rest>
667 assert(isolate->InContext());
668 auto context = isolate->GetCurrentContext();
669 auto array = v8::Array::New(isolate);
672 for (
auto & element : vector) {
673 (void) array->Set(context, i,
CastToJS<std::remove_reference_t<ValueType>>()(isolate, std::forward<ValueType>(const_cast<ValueType>(element))));
681 template<
class T,
class... Rest>
689 template<
class U,
class... Rest>
693 return this->operator()(isolate, list);
698 template<
class KeyType,
class ValueType,
class... Rest>
699 struct CastToJS<std::map<KeyType, ValueType, Rest...>> {
711 template<
class A,
class B,
class... Rest>
715 return this->operator()(isolate, multimap);
721 template<
class A,
class B,
class... Rest>
722 struct CastToJS<std::unordered_map<A, B, Rest...>> {
723 v8::Local<v8::Value> operator()(v8::Isolate *isolate, std::unordered_map<A, B, Rest...> & unorderedmap);
725 return this->operator()(isolate, unorderedmap);
730 template<
class T,
class... Rest>
734 return this->operator()(isolate, deque);
739 template<
class T, std::
size_t N>
743 return this->operator()(isolate, arr);
756 template<
class T,
class... Rest>
757 struct CastToJS<std::unique_ptr<T, Rest...>, std::enable_if_t<!is_wrapped_type_v<T>>> {
776 template<
class T,
class... Rest>
777 struct CastToJS<std::unique_ptr<T, Rest...> &, std::enable_if_t<!is_wrapped_type_v<std::unique_ptr<T, Rest...>>>> {
780 if (unique_ptr.get() ==
nullptr) {
781 return v8::Undefined(isolate);
787 template<
class T,
class... Rest>
788 struct CastToJS<std::unique_ptr<T, Rest...> const &, std::enable_if_t<!is_wrapped_type_v<std::unique_ptr<T, Rest...> const>>> {
792 if (unique_ptr.get() ==
nullptr) {
793 return v8::Undefined(isolate);
812 template<
class T,
class... Rest>
817 template<
class T,
class... Rest>
830 CastToJS<std::list<T, Rest...>>::operator()(v8::Isolate * isolate, std::list<T, Rest...> & list) {
831 assert(isolate->InContext());
832 auto context = isolate->GetCurrentContext();
833 auto array = v8::Array::New(isolate);
835 for (
auto & element : list) {
836 (void)array->Set(context, i,
CastToJS<T>()(isolate, element));
845 template<
template<
class,
class,
class...>
class MultiMapLike,
class A,
class B,
class... Rest>
847 assert(isolate->InContext());
848 auto context = isolate->GetCurrentContext();
849 auto object = v8::Object::New(isolate);
850 for(
auto & pair : map){
851 auto key =
CastToJS<A>()(isolate, const_cast<A&>(pair.first));
852 auto value =
CastToJS<B>()(isolate, const_cast<B&>(pair.second));
855 bool default_value =
true;
856 bool object_has_key =
object->Has(context, key).FromMaybe(default_value);
857 if(!object_has_key) {
859 auto array = v8::Array::New(isolate);
860 (void)array->Set(context, 0, value);
861 (void)object->Set(context, key, array);
864 auto existing_array_value =
object->Get(context, key).ToLocalChecked();
865 v8::Handle<v8::Array> existing_array = v8::Handle<v8::Array>::Cast(existing_array_value);
869 while(existing_array->Has(context, i).FromMaybe(default_value)){i++;}
870 (void)existing_array->Set(context, i, value);
882 CastToJS<std::multimap<
A, B, Rest...>>::operator()(v8::Isolate * isolate, std::multimap<
A, B, Rest...> & map){
894 assert(isolate->InContext());
895 auto context = isolate->GetCurrentContext();
896 auto array = v8::Array::New(isolate);
897 (void) array->Set(context, 0,
CastToJS<T1 &>()(isolate, pair.first));
898 (void) array->Set(context, 1,
CastToJS<T2 &>()(isolate, pair.second));
905 template<
int position,
class T>
908 template<
class...
Args>
911 constexpr
int array_position =
sizeof...(Args) - 0 - 1;
913 assert(isolate->InContext());
914 auto context = isolate->GetCurrentContext();
915 auto array = v8::Array::New(isolate);
916 using TuplePositionType =
typename std::tuple_element<array_position, std::tuple<
Args...>>::type;
918 (void)array->Set(context,
921 std::get<array_position>(tuple)));
926 template<
int position,
class...
Args>
929 constexpr
int array_position =
sizeof...(Args) - position - 1;
930 using TuplePositionType =
typename std::tuple_element<array_position, std::tuple<
Args...>>::type;
932 assert(isolate->InContext());
933 auto context = isolate->GetCurrentContext();
935 (void)array->Set(context,
938 std::get<array_position>(tuple)));
945 template<
class...
Args>
948 return CastTupleToJS<
sizeof...(Args) - 1, std::tuple<Args...>>()(isolate, tuple);
957 CastToJS<std::unordered_map<
A, B, Rest...>>::operator()(v8::Isolate * isolate, std::unordered_map<
A, B, Rest...> & map){
958 assert(isolate->InContext());
959 auto context = isolate->GetCurrentContext();
960 auto object = v8::Object::New(isolate);
961 for(
auto pair : map){
974 CastToJS<std::deque<T, Rest...>>::operator()(v8::Isolate * isolate, std::deque<T, Rest...> & deque) {
975 assert(isolate->InContext());
976 auto context = isolate->GetCurrentContext();
977 auto array = v8::Array::New(isolate);
978 auto size = deque.size();
979 for(
unsigned int i = 0; i < size; i++) {
980 (void)array->Set(context, i,
CastToJS<T>()(isolate, deque.at(i)));
989 assert(isolate->InContext());
990 auto context = isolate->GetCurrentContext();
991 auto array = v8::Array::New(isolate);
993 for(
unsigned int i = 0; i < N; i++) {
994 (void)array->Set(context, i,
CastToJS<T>()(isolate, arr[i]));
1007 template<
class T,
class... Rest>
1026 template<
class ReturnT,
class...
Args>
1034 #ifdef V8TOOLKIT_ENABLE_EASTL_SUPPORT
bool_constant< true > true_type
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
bool_constant< false > false_type
bool Value(const T &value, M matcher)
internal::KeyMatcher< M > Key(M inner_matcher)
const T & move(const T &t)
#define HANDLE_FUNCTION_VALUES