1 #ifndef EINA_JS_ITERATOR_HH
2 #define EINA_JS_ITERATOR_HH
3 
4 #include <type_traits>
5 
6 #include <eina_js_value.hh>
7 
8 namespace efl { namespace eina { namespace js {
9 
10 /* Exports the \p iterator to be manipulated by the JS code. The iterator should
11    remain alive as long as there is JS code referencing it. The JS code is able
12    to destroy the iterator by itself if you register the appropriate function
13    through `register_destroy_iterator`.
14 
15    The exported JS object models part the [iterator concept from ECMAScript
16    6](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol).
17 
18    The iterator will have the `next` function, but the returned object won't
19    have a `done` attribute, because the eina_iterator itself doesn't expose this
20    information.*/
21 template <typename T>
export_iterator(Eina_Iterator * i,v8::Isolate * isolate,const char * class_name)22 inline v8::Local<v8::Object> export_iterator(Eina_Iterator *i,
23                                              v8::Isolate *isolate,
24                                              const char *class_name)
25 {
26     using no_tag_type = typename remove_tag<T>::type;
27     typedef void (*deleter_t)(void*);
28 
29     auto obj_tpl = compatibility_new<v8::ObjectTemplate>(isolate);
30     obj_tpl->SetInternalFieldCount(2);
31 
32     auto ret = obj_tpl->NewInstance();
33 
34     auto next = [](js::compatibility_callback_info_type info) -> compatibility_return_type
35       {
36         if (info.Length() != 0)
37           return compatibility_return();
38 
39         void *ptr = compatibility_get_pointer_internal_field(info.This(), 0);
40         auto it = static_cast<Eina_Iterator*>(ptr);
41         void *value = nullptr;
42         auto done = !::eina_iterator_next(it, &value);
43         v8::Local<v8::Object> o = compatibility_new<v8::Object>(info.GetIsolate());
44         o->Set(compatibility_new<v8::String>(info.GetIsolate(), "done"),
45                compatibility_new<v8::Boolean>(info.GetIsolate(), done));
46         if (!done)
47           {
48              std::string obj_class_name;
49              if (info.Data()->IsString())
50                {
51                   v8::String::Utf8Value str(info.Data());
52                   obj_class_name = *str;
53                }
54              o->Set(compatibility_new<v8::String>(info.GetIsolate(), "value"),
55                     get_value_from_c(js::wrap_value<T>(get_c_container_data<no_tag_type>(value), js::value_tag<T>{}),
56                                      info.GetIsolate(), obj_class_name.c_str()));
57           }
58         return compatibility_return(o, info);
59       };
60 
61     ret->Set(compatibility_new<v8::String>(isolate, "next"),
62              compatibility_new<v8::FunctionTemplate>(isolate, next, js::compatibility_new<v8::String>(isolate, class_name))->GetFunction());
63 
64     {
65         deleter_t deleter = [](void *i) {
66             ::eina_iterator_free(static_cast<Eina_Iterator*>(i));
67         };
68         compatibility_set_pointer_internal_field(ret, 0, i);
69         // compatibility_set_pointer_internal_field
70         //   (ret, 1, reinterpret_cast<void*>(deleter));
71     }
72 
73     return ret;
74 }
75 
76 /* Extracts and returns a copy from the internal iterator object from the JS
77    object. */
78 inline
import_iterator(v8::Handle<v8::Object> o)79 Eina_Iterator* import_iterator(v8::Handle<v8::Object> o)
80 {
81     void* ptr = compatibility_get_pointer_internal_field(o, 0);
82     return static_cast<Eina_Iterator*>(ptr);
83 }
84 
85 void register_destroy_iterator(v8::Isolate *isolate,
86                                v8::Handle<v8::Object> global,
87                                v8::Handle<v8::String> name);
88 
89 } } } // namespace efl::js
90 
91 #endif /* EINA_JS_ITERATOR_HH */
92