diff options
author | VinÃcius dos Santos Oliveira <vini.ipsmaker@expertisesolutions.com.br> | 2015-01-01 19:13:45 -0300 |
---|---|---|
committer | VinÃcius dos Santos Oliveira <vini.ipsmaker@expertisesolutions.com.br> | 2015-01-02 16:50:13 -0300 |
commit | d9c64b3697524bbebd549a57ff2c466629979229 (patch) | |
tree | 4c6c01785d494033abf02f6fa00ab9ae88f7d694 | |
parent | 5c59f25b21f286fd305dfdc7f7d62a497736b8f1 (diff) | |
download | efl-d9c64b3697524bbebd549a57ff2c466629979229.tar.gz |
[eina_js] added binding for Eina_Iterator
-rw-r--r-- | src/Makefile_Eina_Js.am | 25 | ||||
-rw-r--r-- | src/bindings/eina_js/eina_js_iterator.cc | 36 | ||||
-rw-r--r-- | src/bindings/eina_js/eina_js_iterator.hh | 89 | ||||
-rw-r--r-- | src/tests/eina_js/eina_js_iterator.cc | 99 |
4 files changed, 246 insertions, 3 deletions
diff --git a/src/Makefile_Eina_Js.am b/src/Makefile_Eina_Js.am index b04949ebce..f4003e3288 100644 --- a/src/Makefile_Eina_Js.am +++ b/src/Makefile_Eina_Js.am @@ -23,7 +23,8 @@ bindings/eina_js/eina_js_container.cc \ bindings/eina_js/eina_js_value.cc \ bindings/eina_js/eina_js_error.cc \ bindings/eina_js/eina_js_accessor.cc \ -bindings/eina_js/eina_js_log.cc +bindings/eina_js/eina_js_log.cc \ +bindings/eina_js/eina_js_iterator.cc #installed_einacxxmainheadersdir = $(includedir)/eina-cxx-@VMAJ@ #dist_installed_einacxxmainheaders_DATA = \ @@ -64,12 +65,14 @@ check_PROGRAMS += tests/eina_js/eina_js_suite \ tests/eina_js/eina_js_value \ tests/eina_js/eina_js_error \ tests/eina_js/eina_js_accessor \ -tests/eina_js/eina_js_log +tests/eina_js/eina_js_log \ +tests/eina_js/eina_js_iterator TESTS += tests/eina_js/eina_js_suite \ tests/eina_js/eina_js_value \ tests/eina_js/eina_js_error \ tests/eina_js/eina_js_accessor \ -tests/eina_js/eina_js_log +tests/eina_js/eina_js_log \ +tests/eina_js/eina_js_iterator tests_eina_js_eina_js_suite_SOURCES = \ tests/eina_js/eina_js_suite.cc @@ -86,6 +89,9 @@ tests/eina_js/eina_js_accessor.cc tests_eina_js_eina_js_log_SOURCES = \ tests/eina_js/eina_js_log.cc +tests_eina_js_eina_js_iterator_SOURCES = \ +tests/eina_js/eina_js_iterator.cc + tests_eina_js_eina_js_suite_CXXFLAGS = -I$(top_builddir)/src/lib/efl \ -DTESTS_WD=\"`pwd`\" \ -DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eina_js\" \ @@ -152,6 +158,19 @@ tests_eina_js_eina_js_log_CXXFLAGS = -I$(top_builddir)/src/lib/efl \ tests_eina_js_eina_js_log_LDADD = @CHECK_LIBS@ @USE_EINA_JS_LIBS@ @USE_EINA_LIBS@ @USE_EO_LIBS@ tests_eina_js_eina_js_log_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EINA_JS_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ +tests_eina_js_eina_js_iterator_CXXFLAGS = -I$(top_builddir)/src/lib/efl \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eina_js\" \ +-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)/src/tests/eina_js\" \ +-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eina_js\" \ +@CHECK_CFLAGS@ \ +@EINA_CXX_CFLAGS@ \ +@EO_CXX_CFLAGS@ \ +@EO_CFLAGS@ \ +@EINA_JS_CFLAGS@ +tests_eina_js_eina_js_iterator_LDADD = @CHECK_LIBS@ @USE_EINA_JS_LIBS@ @USE_EINA_LIBS@ @USE_EO_LIBS@ +tests_eina_js_eina_js_iterator_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EINA_JS_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ + endif endif diff --git a/src/bindings/eina_js/eina_js_iterator.cc b/src/bindings/eina_js/eina_js_iterator.cc new file mode 100644 index 0000000000..dfacd65d55 --- /dev/null +++ b/src/bindings/eina_js/eina_js_iterator.cc @@ -0,0 +1,36 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <eina_js_iterator.hh> + +namespace efl { namespace js { + +EAPI +void register_destroy_iterator(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::Object; + using v8::Handle; + using v8::FunctionTemplate; + using v8::FunctionCallbackInfo; + + typedef void (*deleter_t)(void*); + + auto f = [](const FunctionCallbackInfo<Value> &info) { + if (info.Length() != 1 || !info[0]->IsObject()) + return; + + Handle<Object> o = info[0]->ToObject(); + + deleter_t deleter = reinterpret_cast<deleter_t> + (o->GetAlignedPointerFromInternalField(1)); + deleter(o->GetAlignedPointerFromInternalField(0)); + }; + + global->Set(name, FunctionTemplate::New(isolate, f)->GetFunction()); +} + +} } // namespace efl { namespace js { diff --git a/src/bindings/eina_js/eina_js_iterator.hh b/src/bindings/eina_js/eina_js_iterator.hh new file mode 100644 index 0000000000..e3b8a3b39c --- /dev/null +++ b/src/bindings/eina_js/eina_js_iterator.hh @@ -0,0 +1,89 @@ +#ifndef EINA_JS_ITERATOR_HH +#define EINA_JS_ITERATOR_HH + +#include <v8.h> +#include <Eina.hh> +#include <type_traits> + +#include <eina_js_value.hh> + +namespace efl { 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) +{ + using v8::Local; + using v8::Value; + using v8::Object; + using v8::String; + using v8::FunctionCallbackInfo; + using v8::FunctionTemplate; + using v8::ObjectTemplate; + + typedef ::efl::eina::iterator<T> value_type; + typedef value_type *ptr_type; + typedef void (*deleter_t)(void*); + + auto obj_tpl = ObjectTemplate::New(isolate); + obj_tpl->SetInternalFieldCount(2); + + auto ret = obj_tpl->NewInstance(); + + auto next = [](const FunctionCallbackInfo<Value> &info) { + if (info.Length() != 0) + return; + + void *ptr = info.This()->GetAlignedPointerFromInternalField(0); + auto &value = *static_cast<ptr_type>(ptr); + Local<Object> o = v8::Object::New(info.GetIsolate()); + o->Set(String::NewFromUtf8(info.GetIsolate(), "value"), + value_cast<Local<Value>>(*value, info.GetIsolate())); + info.GetReturnValue().Set(o); + ++value; + }; + + ret->Set(String::NewFromUtf8(isolate, "next"), + FunctionTemplate::New(isolate, next)->GetFunction()); + + { + deleter_t deleter = [](void *i) { + delete static_cast<ptr_type>(i); + }; + ret->SetAlignedPointerInInternalField(0, i); + ret->SetAlignedPointerInInternalField(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 */ diff --git a/src/tests/eina_js/eina_js_iterator.cc b/src/tests/eina_js/eina_js_iterator.cc new file mode 100644 index 0000000000..8c559587d4 --- /dev/null +++ b/src/tests/eina_js/eina_js_iterator.cc @@ -0,0 +1,99 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cassert> +#include <eina_js_iterator.hh> +#include <Eo.hh> + +void print(const v8::FunctionCallbackInfo<v8::Value> &args) +{ + bool first = true; + for (int i = 0; i < args.Length(); i++) { + v8::HandleScope handle_scope(args.GetIsolate()); + if (first) { + first = false; + } else { + printf(" "); + } + v8::String::Utf8Value str(args[i]); + std::cout << std::string(*str, str.length()); + } + printf("\n"); + fflush(stdout); +} + +static const char script[] = + "function assert(test, message) { if (test !== true) throw message; };" + + "assert(it.next().value === 42, '#1');" + "assert(it.next().value === 24, '#2');" + "destroy_iterator(it);" + ; + +int main(int argc, char *argv[]) +{ + efl::eina::eina_init eina_init; + efl::eo::eo_init eo_init; + + v8::V8::Initialize(); + v8::V8::InitializeICU(); + v8::V8::SetFlagsFromCommandLine(&argc, argv, true); + v8::Isolate* isolate = v8::Isolate::New(); + + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Handle<v8::Context> context + = v8::Context::New(isolate, NULL, v8::ObjectTemplate::New(isolate)); + + if (context.IsEmpty()) { + fprintf(stderr, "Error creating context\n"); + return 1; + } + + { + // Enter the execution environment before evaluating any code. + v8::Context::Scope context_scope(context); + v8::Handle<v8::Object> global = context->Global(); + + global->Set(v8::String::NewFromUtf8(isolate, "print"), + v8::FunctionTemplate::New(isolate, print)->GetFunction()); + efl::js + ::register_destroy_iterator(isolate, global, + v8::String::NewFromUtf8(isolate, + "destroy_iterator")); + + Eina_Array *array = [](){ + static int impl[3] = {42, 24, 0}; + Eina_Array *a = eina_array_new(3); + eina_array_push(a, impl); + eina_array_push(a, impl+1); + eina_array_push(a, impl+2); + return a; + }(); + efl::eina::iterator<int> it(eina_array_iterator_new(array)); + + v8::Local<v8::Object> wrapped_it = efl::js::export_iterator(&it, isolate); + + global->Set(v8::String::NewFromUtf8(isolate, "it"), wrapped_it); + + assert(**efl::js::import_iterator<int>(wrapped_it) == 42); + + { + v8::HandleScope handle_scope(isolate); + v8::TryCatch try_catch; + auto source = v8::String::NewFromUtf8(isolate, script); + v8::Handle<v8::Script> script = v8::Script::Compile(std::move(source)); + + assert(!script.IsEmpty()); + + /*v8::Handle<v8::Value> result = */script->Run(); + + if (try_catch.HasCaught()) { + v8::String::Utf8Value message(try_catch.Message()->Get()); + std::cerr << std::string(*message, message.length()) << std::endl; + std::abort(); + } + } + } +} |