summaryrefslogtreecommitdiff
path: root/src/bindings/eina_js/eina_js_container.cc
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2014-09-01 15:08:49 -0300
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2015-12-19 17:05:28 -0200
commit844228b4060c77a41db6232103d8a5a20cd2bf95 (patch)
tree50aa3427c700318e3932b92702aac91a3dec586d /src/bindings/eina_js/eina_js_container.cc
parent105960b24f15140710896710fe94080961e0bb50 (diff)
efl-js: JavaScript Eolian bindingdevs/felipealmeida/js-20151219
To configure efl sources with bindings to use in nodejs add ––with-js=nodejs in configure flags to generate node files $ configure --with-js=nodejs and compile normally with: $ make $ make install To use, you have to require efl: efl = require('efl') The bindings is divided in two parts: generated and manually written. The generation uses the Eolian library for parsing Eo files and generate C++ code that is compiled against V8 interpreter library to create a efl.node file that can be required in a node.js instance. @feature
Diffstat (limited to 'src/bindings/eina_js/eina_js_container.cc')
-rw-r--r--src/bindings/eina_js/eina_js_container.cc495
1 files changed, 495 insertions, 0 deletions
diff --git a/src/bindings/eina_js/eina_js_container.cc b/src/bindings/eina_js/eina_js_container.cc
new file mode 100644
index 0000000..60c53e0
--- /dev/null
+++ b/src/bindings/eina_js/eina_js_container.cc
@@ -0,0 +1,495 @@
1#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4
5#include <Eina.hh>
6#include <Eina.h>
7#include <cstdlib>
8
9#include <Eo.h>
10
11#include <eina_integer_sequence.hh>
12#include <eina_tuple.hh>
13#include <eina_ptrlist.hh>
14
15#include <Eina_Js.hh>
16
17#include <tuple>
18
19#include <iostream>
20
21namespace efl { namespace eina { namespace js {
22
23template <typename T>
24struct tag { typedef T type; };
25
26namespace {
27
28global_ref<v8::ObjectTemplate> instance_persistents[container_type_size];
29global_ref<v8::Function> instance_templates[container_type_size];
30
31v8::Local<v8::Value> push(eina_container_base& self, v8::Isolate* isolate, v8::Local<v8::Value> value)
32{
33 return v8::Integer::New(isolate, self.push(isolate, value));
34}
35
36v8::Local<v8::Value> pop(eina_container_base& self, v8::Isolate* isolate, v8::Local<v8::Value>)
37{
38 return self.pop(isolate);
39}
40
41v8::Local<v8::Value> concat(eina_container_base& lhs, v8::Isolate* isolate, v8::Local<v8::Value> other)
42{
43 const char* error_message = 0;
44 if(other->IsObject())
45 {
46 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(other);
47 v8::String::Utf8Value constructor_name (obj->GetConstructorName());
48 if(obj->GetConstructorName()->Equals(efl::eina::js::compatibility_new<v8::String>(isolate, "eina_list"))
49 || obj->GetConstructorName()->Equals(efl::eina::js::compatibility_new<v8::String>(isolate, "eina_array")))
50 {
51 eina_container_base& rhs = *static_cast<eina_container_base*>
52 (efl::eina::js::compatibility_get_pointer_internal_field(obj, 0));
53 std::type_info const& typeinfo_lhs = typeid(lhs)
54 , &typeinfo_rhs = typeid(rhs);
55 if(!typeinfo_lhs.before(typeinfo_rhs) && !typeinfo_rhs.before(typeinfo_lhs))
56 {
57 v8::Handle<v8::Value> a[] =
58 {efl::eina::js::compatibility_new<v8::External>(isolate, rhs.concat(lhs))};
59 assert(!!*instance_templates[lhs.get_container_type()].handle());
60 v8::Local<v8::Object> result =
61 instance_templates[lhs.get_container_type()].handle()->NewInstance(1, a);
62 return result;
63 }
64 else
65 error_message = "Containers are not of the same type.";
66 }
67 else
68 error_message = "Object to be concatenated is not a container.";
69 }
70 else
71 error_message = "Concatenation argument is not an container";
72
73 eina::js::compatibility_throw
74 (isolate, v8::Exception::TypeError(eina::js::compatibility_new<v8::String>(isolate, error_message)));
75
76 return v8::Undefined(isolate);
77}
78
79v8::Local<v8::Value> slice(eina_container_base& self, v8::Isolate* isolate, v8::Local<v8::Value> begin
80 , v8::Local<v8::Value> end)
81{
82 std::size_t i, j;
83
84 if(begin->IsUint32() || begin->IsInt32())
85 i = begin->IntegerValue();
86 else if (begin->IsUndefined())
87 i = 0;
88 else
89 return v8::Undefined(isolate);
90
91 if(end->IsUint32() || end->IsInt32())
92 j = end->IntegerValue();
93 else if (end->IsUndefined())
94 j = self.size();
95 else
96 return v8::Undefined(isolate);
97
98 v8::Handle<v8::Value> a[] = {efl::eina::js::compatibility_new<v8::External>(isolate, self.slice(i, j))};
99 v8::Local<v8::Object> result = instance_templates[self.get_container_type()].handle()
100 ->NewInstance(1, a);
101 return result;
102}
103
104compatibility_accessor_getter_return_type length
105 (v8::Local<v8::String>, compatibility_accessor_getter_callback_info_type info)
106{
107 v8::Local<v8::Object> self_obj = compatibility_cast<v8::Object>(info.This());
108 eina_container_base* self = static_cast<eina_container_base*>
109 (compatibility_get_pointer_internal_field(self_obj, 0));
110 return compatibility_return(js::get_value_from_c(self->size(), info.GetIsolate(), ""), info);
111}
112
113compatibility_indexed_property_getset_return_type index_get
114 (uint32_t index, compatibility_indexed_property_callback_info_type info)
115{
116 v8::Local<v8::Object> self_obj = v8::Local<v8::Object>::Cast(info.This());
117 eina_container_base* self = static_cast<eina_container_base*>
118 (compatibility_get_pointer_internal_field(self_obj, 0));
119 return compatibility_return(self->get(info.GetIsolate(), index), info);
120}
121
122compatibility_indexed_property_getset_return_type index_set
123 (uint32_t index, v8::Local<v8::Value> value, compatibility_indexed_property_callback_info_type info)
124{
125 v8::Local<v8::Object> self_obj = v8::Local<v8::Object>::Cast(info.This());
126 eina_container_base* self = static_cast<eina_container_base*>
127 (compatibility_get_pointer_internal_field(self_obj, 0));
128
129 return compatibility_return(self->set(info.GetIsolate(), index, value), info);
130}
131
132
133#define GENERATE_CONTAINER_CONSTRUCT_TYPE_IF(x) GENERATE_CONTAINER_CONSTRUCT_TYPE2_IF(x, x)
134#define GENERATE_CONTAINER_CONSTRUCT_TYPE2_IF(x, y) if (!strcmp(class_name, #x)) \
135 return new Container<y, nonclass_cls_name_getter, typename container_wrapper<y>::type>();
136
137template< template<typename, typename, typename> class Container>
138eina_container_base* construct_container(const char* class_name)
139{
140 GENERATE_CONTAINER_CONSTRUCT_TYPE_IF(int);
141 GENERATE_CONTAINER_CONSTRUCT_TYPE_IF(float);
142 GENERATE_CONTAINER_CONSTRUCT_TYPE2_IF(bool, Eina_Bool);
143 GENERATE_CONTAINER_CONSTRUCT_TYPE2_IF(string, char*);
144
145 return 0;
146}
147
148compatibility_return_type new_eina_list_internal(compatibility_callback_info_type args)
149{
150 if(args.IsConstructCall())
151 {
152 if(args.Length() == 0)
153 {
154 eina_container_base* p = new eina_list<int>;
155 compatibility_set_pointer_internal_field
156 (args.This(), 0, dynamic_cast<void*>(p));
157 }
158 else
159 {
160 if(args[0]->IsExternal())
161 {
162 eina_container_base* base = reinterpret_cast<eina_container_base*>
163 (v8::External::Cast(*args[0])->Value());
164 compatibility_set_pointer_internal_field
165 (args.This(), 0, dynamic_cast<void*>(base));
166 }
167 else
168 std::abort();
169 }
170 }
171 else
172 std::abort();
173 return compatibility_return();
174}
175
176compatibility_return_type new_eina_list(compatibility_callback_info_type args)
177{
178 if(args.IsConstructCall())
179 {
180 if(args.Length() == 0) // Default constructor, list of ints. Or should be list of Eo's?
181 {
182 eina_container_base* p = new eina_list<int>;
183 compatibility_set_pointer_internal_field
184 (args.This(), 0, dynamic_cast<void*>(p));
185 return compatibility_return();
186 }
187 else if (args.Length() == 1 && args[0]->IsString())
188 {
189 v8::String::Utf8Value string(args[0]);
190 eina_container_base* p = construct_container<efl::eina::js::eina_list>(*string);
191 if (!p) {
192 return eina::js::compatibility_throw
193 (args.GetIsolate(), v8::Exception::TypeError
194 (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Invalid type for container.")));
195 }
196 compatibility_set_pointer_internal_field
197 (args.This(), 0, dynamic_cast<void*>(p));
198 return compatibility_return();
199 }
200 }
201 return eina::js::compatibility_throw
202 (args.GetIsolate(), v8::Exception::TypeError
203 (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Wrong number of arguments for constructor call")));
204}
205
206compatibility_return_type new_eina_array_internal(compatibility_callback_info_type args)
207{
208 if(args.IsConstructCall())
209 {
210 if(args.Length() == 0)
211 {
212 eina_container_base* p = new eina_array<int>;
213 compatibility_set_pointer_internal_field
214 (args.This(), 0, dynamic_cast<void*>(p));
215 }
216 else
217 {
218 if(args[0]->IsExternal())
219 {
220 eina_container_base* base = reinterpret_cast<eina_container_base*>
221 (v8::External::Cast(*args[0])->Value());
222 compatibility_set_pointer_internal_field
223 (args.This(), 0, dynamic_cast<void*>(base));
224 }
225 else
226 std::abort();
227 }
228 }
229 else
230 std::abort();
231 return compatibility_return();
232}
233
234compatibility_return_type new_eina_array(compatibility_callback_info_type args)
235{
236 if(args.IsConstructCall())
237 {
238 if(args.Length() == 0)
239 {
240 eina_container_base* p = new eina_array<int>;
241 compatibility_set_pointer_internal_field
242 (args.This(), 0, dynamic_cast<void*>(p));
243 return compatibility_return();
244 }
245 else if (args.Length() == 1 && args[0]->IsString())
246 {
247 v8::String::Utf8Value string(args[0]);
248 eina_container_base* p = construct_container<efl::eina::js::eina_array>(*string);
249 if (!p) {
250 return eina::js::compatibility_throw
251 (args.GetIsolate(), v8::Exception::TypeError
252 (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Invalid type for container.")));
253 }
254 compatibility_set_pointer_internal_field
255 (args.This(), 0, dynamic_cast<void*>(p));
256 return compatibility_return();
257 }
258 }
259 return eina::js::compatibility_throw
260 (args.GetIsolate(), v8::Exception::TypeError
261 (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Wrong number of arguments for constructor call")));
262}
263
264template <typename F>
265struct function_params;
266
267template <typename R, typename... Sig>
268struct function_params<R(*)(Sig...)>
269{
270 typedef std::tuple<Sig...> type;
271};
272
273template <typename F>
274struct function_result;
275
276template <typename R, typename... Sig>
277struct function_result<R(*)(Sig...)>
278{
279 typedef R type;
280};
281
282template <typename T>
283struct is_persistent : std::false_type {};
284
285template <typename...A>
286struct is_persistent<v8::Persistent<A...> > : std::true_type {};
287
288template <std::size_t I, typename Sig>
289typename std::tuple_element<I, Sig>::type
290get_element(v8::Isolate* isolate
291 , compatibility_callback_info_type args
292 , typename std::enable_if
293 <is_persistent<typename std::tuple_element<I, Sig>::type>::value>::type* = 0)
294{
295 return typename std::tuple_element<I, Sig>::type(isolate, args[I]);
296}
297
298template <std::size_t I, typename Sig>
299typename std::tuple_element<I, Sig>::type
300get_element(v8::Isolate* /*isolate*/
301 , compatibility_callback_info_type args
302 , typename std::enable_if
303 <!is_persistent<typename std::tuple_element<I, Sig>::type>::value>::type* = 0)
304{
305 return args[I];
306}
307
308template <typename Sig, typename R, typename T, typename F, std::size_t... N>
309R call_impl(v8::Isolate* isolate
310 , compatibility_callback_info_type args
311 , T* self, F* f
312 , eina::index_sequence<N...>)
313{
314 assert(self != 0);
315 return (*f)(*self, isolate, js::get_element<N, Sig>(isolate, args)...);
316}
317
318template <typename Sig, typename T, typename F, typename R>
319compatibility_return_type call_generic_impl(compatibility_callback_info_type args, tag<R>)
320{
321 T* self = static_cast<T*>
322 (compatibility_get_pointer_internal_field<>(args.This(), 0));
323 F* f = reinterpret_cast<F*>(v8::External::Cast(*args.Data())->Value());
324 return compatibility_return
325 (js::get_value_from_c
326 (js::call_impl<Sig, R>(args.GetIsolate(), args, self, f
327 , eina::make_index_sequence<std::tuple_size<Sig>::value>())
328 , args.GetIsolate(), "")
329 , args);
330}
331
332template <typename Sig, typename T, typename F>
333compatibility_return_type call_generic_impl(compatibility_callback_info_type args, tag<void>)
334{
335 T* self = static_cast<T*>
336 (compatibility_get_pointer_internal_field(args.This(), 0));
337 F* f = reinterpret_cast<F*>(v8::External::Cast(*args.Data())->Value());
338 js::call_impl<Sig, void>(args.GetIsolate(), args, self, f
339 , eina::make_index_sequence<std::tuple_size<Sig>::value>());
340 return compatibility_return();
341}
342
343template <typename Sig, typename R, typename T, typename F>
344compatibility_return_type call_generic(compatibility_callback_info_type args)
345{
346 return efl::eina::js::call_generic_impl<Sig, T, F>(args, tag<R>());
347}
348
349template <typename Sig, typename T, typename F, typename R>
350compatibility_return_type call_function_impl(compatibility_callback_info_type args, tag<R>)
351{
352 T* self = static_cast<T*>
353 (compatibility_get_pointer_internal_field(args.This(), 0));
354 F f = reinterpret_cast<F>(v8::External::Cast(*args.Data())->Value());
355 return compatibility_return
356 (/*js::get_value_from_c*/
357 (js::call_impl<Sig, R>(args.GetIsolate(), args, self, f
358 , eina::make_index_sequence<std::tuple_size<Sig>::value>())
359 /*, args.GetIsolate(), ""*/)
360 , args);
361}
362
363template <typename Sig, typename T, typename F>
364compatibility_return_type call_function_impl(compatibility_callback_info_type args, tag<void>)
365{
366 T* self = static_cast<T*>
367 (compatibility_get_pointer_internal_field(args.This(), 0));
368 F f = reinterpret_cast<F>(v8::External::Cast(*args.Data())->Value());
369 js::call_impl<Sig, void>(args.GetIsolate(), args, self, f
370 , eina::make_index_sequence<std::tuple_size<Sig>::value>());
371 return compatibility_return();
372}
373
374template <typename Sig, typename R, typename T, typename F>
375compatibility_return_type call_function(compatibility_callback_info_type args)
376{
377 return efl::eina::js::call_function_impl<Sig, T, F>(args, tag<R>());
378}
379
380template <typename T, typename F>
381void register_(v8::Isolate* isolate, const char* name, F f, v8::Handle<v8::ObjectTemplate> template_
382 , typename std::enable_if<std::is_function<typename std::remove_pointer<F>::type>::value>::type* = 0)
383{
384 template_->Set(compatibility_new<v8::String>(isolate, name)
385 , compatibility_new<v8::FunctionTemplate>
386 (isolate, &efl::eina::js::call_function
387 <typename eina::_mpl::pop_front<typename function_params<F>::type, 2u>::type
388 , typename function_result<F>::type, T, F>
389 , compatibility_new<v8::External>
390 (isolate, reinterpret_cast<void*>(f))));
391}
392
393template <typename T, typename...Sig, typename F>
394void register_(v8::Isolate* isolate, const char* name, F&& f, v8::Handle<v8::ObjectTemplate> template_
395 , typename std::enable_if<!std::is_function<typename std::remove_pointer<F>::type>::value>::type* = 0)
396{
397 using result_type = decltype
398 (std::declval<F>()
399 (std::declval<T&>(), std::declval<v8::Isolate*>()
400 , std::declval<Sig>()...)
401 );
402 template_->Set(compatibility_new<v8::String>(isolate, name)
403 , compatibility_new<v8::FunctionTemplate>
404 (isolate
405 , &efl::eina::js::call_generic<std::tuple<Sig...>, result_type, T, F>
406 , compatibility_new<v8::External>
407 (isolate, new F(std::forward<F>(f)))));
408}
409
410v8::Local<v8::ObjectTemplate> register_template(v8::Isolate* isolate, v8::Handle<v8::FunctionTemplate> constructor)
411{
412 v8::Local<v8::ObjectTemplate> instance_t = constructor->InstanceTemplate();
413 instance_t->SetInternalFieldCount(1);
414
415 instance_t->SetIndexedPropertyHandler(& efl::eina::js::index_get, & efl::eina::js::index_set);
416
417 v8::Local<v8::ObjectTemplate> prototype = constructor->PrototypeTemplate();
418 prototype->SetAccessor(compatibility_new<v8::String>(isolate, "length"), &efl::eina::js::length);
419
420 using namespace std::placeholders;
421 js::register_<js::eina_container_base>
422 (isolate, "push", &js::push, prototype);
423 js::register_<js::eina_container_base>
424 (isolate, "pop", &js::pop, prototype);
425 js::register_<js::eina_container_base>
426 (isolate, "concat", &js::concat, prototype);
427 js::register_<js::eina_container_base>
428 (isolate, "slice", &js::slice, prototype);
429 js::register_<js::eina_container_base>
430 (isolate, "toString", std::bind(&js::eina_container_base::to_string, _1, _2), prototype);
431 js::register_<js::eina_container_base, v8::Local<v8::Value> >
432 (isolate, "join", std::bind(&js::eina_container_base::join, _1, _2, _3), prototype);
433 js::register_<js::eina_container_base, v8::Local<v8::Value> >
434 (isolate, "indexOf", std::bind(&js::eina_container_base::index_of, _1, _2, _3), prototype);
435 js::register_<js::eina_container_base, v8::Local<v8::Value> >
436 (isolate, "lastIndexOf", std::bind(&js::eina_container_base::last_index_of, _1, _2, _3), prototype);
437
438 return instance_t;
439}
440
441void register_class(v8::Isolate* isolate, container_type type, const char* class_name
442 , compatibility_function_callback callback)
443{
444 v8::Handle<v8::FunctionTemplate> constructor
445 = compatibility_new<v8::FunctionTemplate>(isolate, callback);
446 constructor->SetClassName(compatibility_new<v8::String>(isolate, class_name));
447
448 v8::Local<v8::ObjectTemplate> instance_t = efl::eina::js::register_template(isolate, constructor);
449
450 efl::eina::js::instance_persistents[type] = global_ref<v8::ObjectTemplate>{isolate, instance_t};
451 efl::eina::js::instance_templates[type] = global_ref<v8::Function>{isolate, constructor->GetFunction()};
452}
453void register_class(v8::Isolate* isolate, container_type, const char* class_name_
454 , const char* constructor_name_
455 , compatibility_function_callback callback
456 , v8::Handle<v8::Object> exports)
457{
458 v8::Handle<v8::FunctionTemplate> constructor
459 = compatibility_new<v8::FunctionTemplate>(isolate, callback);
460 auto class_name = compatibility_new<v8::String>(isolate, class_name_);
461 auto constructor_name = compatibility_new<v8::String>(isolate, constructor_name_);
462 constructor->SetClassName(class_name);
463
464 v8::Local<v8::ObjectTemplate> instance_t = efl::eina::js::register_template(isolate, constructor);
465 (void)instance_t;
466
467 exports->Set(constructor_name, constructor->GetFunction());
468}
469
470}
471
472EAPI v8::Handle<v8::Function> get_list_instance_template()
473{
474 return efl::eina::js::instance_templates[efl::eina::js::list_container_type].handle();
475}
476
477EAPI v8::Handle<v8::Function> get_array_instance_template()
478{
479 return efl::eina::js::instance_templates[efl::eina::js::array_container_type].handle();
480}
481
482} } }
483
484EAPI void eina_container_register(v8::Handle<v8::Object> exports, v8::Isolate* isolate)
485{
486 efl::eina::js::register_class(isolate, efl::eina::js::list_container_type
487 , "eina_list", &efl::eina::js::new_eina_list_internal);
488 efl::eina::js::register_class(isolate, efl::eina::js::list_container_type
489 , "eina_list", "List", &efl::eina::js::new_eina_list, exports);
490 efl::eina::js::register_class(isolate, efl::eina::js::array_container_type
491 , "eina_array", &efl::eina::js::new_eina_array_internal);
492 efl::eina::js::register_class(isolate, efl::eina::js::array_container_type
493 , "eina_array", "Array", &efl::eina::js::new_eina_array, exports);
494}
495