summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVinícius dos Santos Oliveira <vini.ipsmaker@expertisesolutions.com.br>2015-01-01 19:13:45 -0300
committerVinícius dos Santos Oliveira <vini.ipsmaker@expertisesolutions.com.br>2015-01-02 16:50:13 -0300
commitd9c64b3697524bbebd549a57ff2c466629979229 (patch)
tree4c6c01785d494033abf02f6fa00ab9ae88f7d694
parent5c59f25b21f286fd305dfdc7f7d62a497736b8f1 (diff)
downloadefl-d9c64b3697524bbebd549a57ff2c466629979229.tar.gz
[eina_js] added binding for Eina_Iterator
-rw-r--r--src/Makefile_Eina_Js.am25
-rw-r--r--src/bindings/eina_js/eina_js_iterator.cc36
-rw-r--r--src/bindings/eina_js/eina_js_iterator.hh89
-rw-r--r--src/tests/eina_js/eina_js_iterator.cc99
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();
+ }
+ }
+ }
+}