1 #ifndef EINA_JS_VALUE_HH
2 #define EINA_JS_VALUE_HH
3 
4 #include <type_traits>
5 
6 #include <eina_js_compatibility.hh>
7 
8 namespace efl { namespace eina { namespace js {
9 
10 namespace detail {
11 
12 template<class T, class = void>
13 struct is_representable_as_v8_integer: std::false_type {};
14 
15 template<class T>
16 struct is_representable_as_v8_integer
17 <T,
18  typename std::enable_if<std::is_integral<T>::value
19                          /* v8::Integer only stores 32-bit signed and unsigned
20                             numbers. */
21                          && (sizeof(T) <= sizeof(int32_t))>::type>
22 : std::true_type {};
23 
24 template<class T>
25 typename std::enable_if<is_representable_as_v8_integer<T>::value
26                         && std::is_signed<T>::value,
27                         v8::Local<v8::Value>>::type
to_v8_number(const T & v,v8::Isolate * isolate)28 to_v8_number(const T &v, v8::Isolate *isolate)
29 {
30   return compatibility_new<v8::Integer>(isolate, v);
31 }
32 
33 template<class T>
34 typename std::enable_if<is_representable_as_v8_integer<T>::value
35                         && std::is_unsigned<T>::value,
36                         v8::Local<v8::Value>>::type
to_v8_number(const T & v,v8::Isolate * isolate)37 to_v8_number(const T &v, v8::Isolate *isolate)
38 {
39   return compatibility_new<v8::Integer>(isolate, v);
40 }
41 
42 template<class T>
43 typename std::enable_if<(std::is_integral<T>::value
44                          && !is_representable_as_v8_integer<T>::value)
45                         || std::is_floating_point<T>::value,
46                         v8::Local<v8::Value>>::type
to_v8_number(const T & v,v8::Isolate * isolate)47 to_v8_number(const T &v, v8::Isolate *isolate)
48 {
49   return compatibility_new<v8::Number>(isolate, v);
50 }
51 
52 template<class T>
53 typename std::enable_if<std::is_same<T, ::efl::eina::stringshare>::value
54                         || std::is_same<T, std::string>::value,
55     v8::Local<v8::Value>>::type
to_v8_string(const T & v,v8::Isolate * isolate)56 to_v8_string(const T &v, v8::Isolate *isolate)
57 {
58   return compatibility_new<v8::String>(isolate, v.c_str());
59 }
60 
61 } // namespace detail
62 
63 template<class T>
64 typename std::enable_if<std::is_same<T, v8::Local<v8::Value>>::value, T>::type
value_cast(const::efl::eina::value & v,v8::Isolate * isolate)65 value_cast(const ::efl::eina::value &v, v8::Isolate *isolate)
66 {
67     using detail::to_v8_number;
68     using detail::to_v8_string;
69     using ::efl::eina::get;
70 
71     const auto &t = v.type_info();
72     if (t == EINA_VALUE_TYPE_UINT64) {
73         return to_v8_number(get<uint64_t>(v), isolate);
74     } else if (t == EINA_VALUE_TYPE_UCHAR) {
75         return to_v8_number(get<unsigned char>(v), isolate);
76     } else if (t == EINA_VALUE_TYPE_USHORT) {
77         return to_v8_number(get<unsigned short>(v), isolate);
78     } else if (t == EINA_VALUE_TYPE_UINT) {
79         return to_v8_number(get<unsigned int>(v), isolate);
80     } else if (t == EINA_VALUE_TYPE_ULONG) {
81         return to_v8_number(get<unsigned long>(v), isolate);
82     } else if (t == EINA_VALUE_TYPE_CHAR) {
83         return to_v8_number(get<char>(v), isolate);
84     } else if (t == EINA_VALUE_TYPE_SHORT) {
85         return to_v8_number(get<short>(v), isolate);
86     } else if (t == EINA_VALUE_TYPE_INT) {
87         return to_v8_number(get<int>(v), isolate);
88     } else if (t == EINA_VALUE_TYPE_LONG) {
89         return to_v8_number(get<long>(v), isolate);
90     } else if (t == EINA_VALUE_TYPE_FLOAT) {
91         return to_v8_number(get<float>(v), isolate);
92     } else if (t == EINA_VALUE_TYPE_DOUBLE) {
93         return to_v8_number(get<double>(v), isolate);
94     } else if (t == EINA_VALUE_TYPE_STRINGSHARE) {
95         return to_v8_string(get<::efl::eina::stringshare>(v), isolate);
96     } else if (t == EINA_VALUE_TYPE_STRING) {
97         return to_v8_string(get<std::string>(v), isolate);
98     }
99 
100     throw std::bad_cast{};
101 }
102 
103 template<class T>
104 typename std::enable_if<std::is_same<T, ::efl::eina::value>::value, T>::type
value_cast(const v8::Handle<v8::Value> & v)105 value_cast(const v8::Handle<v8::Value> &v)
106 {
107     using ::efl::eina::value;
108 
109     if (v->IsBoolean()) {
110         return value(int{v->BooleanValue()});
111     } else if (v->IsInt32()) {
112         return value(v->Int32Value());
113     } else if (v->IsUint32()) {
114         return value(v->Uint32Value());
115     } else if (v->IsNumber()) {
116         return value(v->NumberValue());
117     } else if (v->IsString()) {
118         v8::String::Utf8Value data(v);
119         return value(std::string(*data, data.length()));
120     }
121 
122     throw std::bad_cast{};
123 }
124 
125 /*
126   # JS binding
127 
128   - There is the `value()` constructor, which accepts a primitive value as input
129     argument and might throw.
130     - The returned object has a `get()` method, which can be used to get the
131       wrapped value as a JavaScript value.
132     - The returned object has a `set()` method, which can be used to change the
133       wrapped value.
134  */
135 void register_value(v8::Isolate *isolate, v8::Handle<v8::Object> global,
136                     v8::Handle<v8::String> name);
137 
138 } } } // namespace efl::js
139 
140 EAPI void eina_value_register(v8::Handle<v8::Object> global, v8::Isolate* isolate);
141 
142 #endif /* EINA_JS_VALUE_HH */
143