aboutsummaryrefslogtreecommitdiffstats
path: root/src/bindings/eina_js/eina_js_iterator.hh
blob: ed0066bf0be291eee3576fe51a860720b049480b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#ifndef EINA_JS_ITERATOR_HH
#define EINA_JS_ITERATOR_HH

#include <type_traits>

#include <eina_js_value.hh>

namespace efl { namespace eina { namespace js {

/* Exports the \p iterator to be manipulated by the JS code. The iterator should
   remain alive as long as there is JS code referencing it. The JS code is able
   to destroy the iterator by itself if you register the appropriate function
   through `register_destroy_iterator`.

   The exported JS object models part the [iterator concept from ECMAScript
   6](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol).

   The iterator will have the `next` function, but the returned object won't
   have a `done` attribute, because the eina_iterator itself doesn't expose this
   information.*/
template<class T>
v8::Local<v8::Object> export_iterator(::efl::eina::iterator<T> *i,
                                      v8::Isolate *isolate)
{
    typedef ::efl::eina::iterator<T> value_type;
    typedef value_type *ptr_type;
    typedef void (*deleter_t)(void*);

    auto obj_tpl = compatibility_new<v8::ObjectTemplate>(isolate);
    obj_tpl->SetInternalFieldCount(2);

    auto ret = obj_tpl->NewInstance();

    auto next = [](js::compatibility_callback_info_type info) -> compatibility_return_type
      {
        if (info.Length() != 0)
          return compatibility_return();

        void *ptr = compatibility_get_pointer_internal_field(info.This(), 0);
        auto &value = *static_cast<ptr_type>(ptr);
        v8::Local<v8::Object> o = compatibility_new<v8::Object>(info.GetIsolate());
        o->Set(compatibility_new<v8::String>(info.GetIsolate(), "value"),
               value_cast<v8::Local<v8::Value>>(*value, info.GetIsolate()));
        ++value;
        return compatibility_return(o, info);
      };

    ret->Set(compatibility_new<v8::String>(isolate, "next"),
             compatibility_new<v8::FunctionTemplate>(isolate, next)->GetFunction());

    {
        deleter_t deleter = [](void *i) {
            delete static_cast<ptr_type>(i);
        };
        compatibility_set_pointer_internal_field(ret, 0, i);
        compatibility_set_pointer_internal_field
          (ret, 1, reinterpret_cast<void*>(deleter));
    }

    return ret;
}

/* Extracts and returns a copy from the internal iterator object from the JS
   object. */
template<class T>
::efl::eina::iterator<T> *import_iterator(v8::Handle<v8::Object> o)
  ;
// {
//     typedef ::efl::eina::iterator<T> value_type;
//     typedef value_type *ptr_type;

//     return reinterpret_cast<ptr_type>(o->GetAlignedPointerFromInternalField(0));
// }

void register_destroy_iterator(v8::Isolate *isolate,
                               v8::Handle<v8::Object> global,
                               v8::Handle<v8::String> name);

} } } // namespace efl::js

#endif /* EINA_JS_ITERATOR_HH */