diff --git a/src/bindings/js/eina_js/eina_js_compatibility.hh b/src/bindings/js/eina_js/eina_js_compatibility.hh index 7cc16a3fe9..fb36e4ee3d 100644 --- a/src/bindings/js/eina_js/eina_js_compatibility.hh +++ b/src/bindings/js/eina_js/eina_js_compatibility.hh @@ -133,6 +133,22 @@ struct container_wrapper >::type type; }; +template +inline T get_c_container_data(void* ptr, typename std::enable_if< + std::is_pointer::value +>::type* = 0) +{ + return static_cast(ptr); +} + +template +inline T get_c_container_data(void* ptr, typename std::enable_if< + !std::is_pointer::value +>::type* = 0) +{ + return *static_cast(ptr); +} + template T container_wrap(T&& v) { @@ -259,6 +275,12 @@ v8::Local export_accessor(::efl::eina::accessor&, v8::Isolate*, c template ::efl::eina::accessor& import_accessor(v8::Handle); +// Iterator +template +inline v8::Local export_iterator(Eina_Iterator*, v8::Isolate*, const char*); + +inline Eina_Iterator* import_iterator(v8::Handle); + // Wrap value functions template typename std::remove_cv::type>::type diff --git a/src/bindings/js/eina_js/eina_js_get_value.hh b/src/bindings/js/eina_js/eina_js_get_value.hh index 637b48a9c8..5d62b2839c 100644 --- a/src/bindings/js/eina_js/eina_js_get_value.hh +++ b/src/bindings/js/eina_js/eina_js_get_value.hh @@ -333,18 +333,24 @@ inline const Eina_Array* get_value_from_javascript( return get_value_from_javascript(v, isolate, class_name, value_tag>{}, throw_js_exception); } -template +template inline Eina_Iterator* get_value_from_javascript( - v8::Local, + v8::Local v, v8::Isolate* isolate, const char*, - value_tag> tag, + value_tag> /*tag*/, bool throw_js_exception = true) { + if(v->IsNull()) + return nullptr; + else if(v->IsObject()) + { + return import_iterator(v->ToObject()); + } if (throw_js_exception) eina::js::compatibility_throw (isolate, v8::Exception::TypeError - (eina::js::compatibility_new(isolate, "Not implemented yet"))); + (eina::js::compatibility_new(isolate, "Type expected is different. Expected Eolian accessor type"))); throw std::logic_error(""); } diff --git a/src/bindings/js/eina_js/eina_js_get_value_from_c.hh b/src/bindings/js/eina_js/eina_js_get_value_from_c.hh index 9a0089e8b9..204c497431 100644 --- a/src/bindings/js/eina_js/eina_js_get_value_from_c.hh +++ b/src/bindings/js/eina_js/eina_js_get_value_from_c.hh @@ -207,18 +207,22 @@ get_value_from_c(efl::eina::js::complex_tag v, v8::Iso template inline v8::Local -get_value_from_c(efl::eina::js::complex_tag, v8::Isolate*, const char*) +get_value_from_c(efl::eina::js::complex_tag v, v8::Isolate* isolate, const char*) { - std::cerr << "get_value_from_c for Eina_Iterator not implemented. Aborting..." << std::endl; - std::abort(); + bool own = false; // TODO: handle ownership + auto ptr = v.value; + auto obj = export_iterator(ptr , isolate, K::class_name()); + if (own && ptr) + efl::eina::js::make_weak(isolate, obj, [ptr]{ ::eina_iterator_free(ptr); }); + return obj; } template inline v8::Local -get_value_from_c(efl::eina::js::complex_tag, v8::Isolate*, const char*) +get_value_from_c(efl::eina::js::complex_tag v, v8::Isolate* isolate, const char* class_name) { - std::cerr << "get_value_from_c for Eina_Iterator not implemented. Aborting..." << std::endl; - std::abort(); + // TODO: implement const iterators? + return get_value_from_c(efl::eina::js::complex_tag{const_cast(v.value)}, isolate, class_name); } template diff --git a/src/bindings/js/eina_js/eina_js_iterator.cc b/src/bindings/js/eina_js/eina_js_iterator.cc index d2480b8be2..40d0db3b75 100644 --- a/src/bindings/js/eina_js/eina_js_iterator.cc +++ b/src/bindings/js/eina_js/eina_js_iterator.cc @@ -23,6 +23,7 @@ void register_destroy_iterator(v8::Isolate *isolate, deleter_t deleter = compatibility_get_pointer_internal_field(o, 1); deleter(compatibility_get_pointer_internal_field<>(o, 0)); + compatibility_set_pointer_internal_field(o, 0, static_cast(0)); return compatibility_return(); }; diff --git a/src/bindings/js/eina_js/eina_js_iterator.hh b/src/bindings/js/eina_js/eina_js_iterator.hh index ed0066bf0b..7021a7be62 100644 --- a/src/bindings/js/eina_js/eina_js_iterator.hh +++ b/src/bindings/js/eina_js/eina_js_iterator.hh @@ -18,12 +18,12 @@ namespace efl { namespace eina { namespace js { 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 -v8::Local export_iterator(::efl::eina::iterator *i, - v8::Isolate *isolate) +template +inline v8::Local export_iterator(Eina_Iterator *i, + v8::Isolate *isolate, + const char *class_name) { - typedef ::efl::eina::iterator value_type; - typedef value_type *ptr_type; + using no_tag_type = typename remove_tag::type; typedef void (*deleter_t)(void*); auto obj_tpl = compatibility_new(isolate); @@ -37,20 +37,33 @@ v8::Local export_iterator(::efl::eina::iterator *i, return compatibility_return(); void *ptr = compatibility_get_pointer_internal_field(info.This(), 0); - auto &value = *static_cast(ptr); + auto it = static_cast(ptr); + void *value = nullptr; + auto done = !::eina_iterator_next(it, &value); v8::Local o = compatibility_new(info.GetIsolate()); - o->Set(compatibility_new(info.GetIsolate(), "value"), - value_cast>(*value, info.GetIsolate())); - ++value; + o->Set(compatibility_new(info.GetIsolate(), "done"), + compatibility_new(info.GetIsolate(), done)); + if (!done) + { + std::string obj_class_name; + if (info.Data()->IsString()) + { + v8::String::Utf8Value str(info.Data()); + obj_class_name = *str; + } + o->Set(compatibility_new(info.GetIsolate(), "value"), + get_value_from_c(js::wrap_value(get_c_container_data(value), js::value_tag{}), + info.GetIsolate(), obj_class_name.c_str())); + } return compatibility_return(o, info); }; ret->Set(compatibility_new(isolate, "next"), - compatibility_new(isolate, next)->GetFunction()); + compatibility_new(isolate, next, js::compatibility_new(isolate, class_name))->GetFunction()); { deleter_t deleter = [](void *i) { - delete static_cast(i); + ::eina_iterator_free(static_cast(i)); }; compatibility_set_pointer_internal_field(ret, 0, i); compatibility_set_pointer_internal_field @@ -62,15 +75,12 @@ v8::Local export_iterator(::efl::eina::iterator *i, /* Extracts and returns a copy from the internal iterator object from the JS object. */ -template -::efl::eina::iterator *import_iterator(v8::Handle o) - ; -// { -// typedef ::efl::eina::iterator value_type; -// typedef value_type *ptr_type; - -// return reinterpret_cast(o->GetAlignedPointerFromInternalField(0)); -// } +inline +Eina_Iterator* import_iterator(v8::Handle o) +{ + void* ptr = compatibility_get_pointer_internal_field(o, 0); + return static_cast(ptr); +} void register_destroy_iterator(v8::Isolate *isolate, v8::Handle global, diff --git a/src/tests/eolian_js/eolian_js_suite.js b/src/tests/eolian_js/eolian_js_suite.js index 9c66dba956..66e55962f2 100755 --- a/src/tests/eolian_js/eolian_js_suite.js +++ b/src/tests/eolian_js/eolian_js_suite.js @@ -252,6 +252,8 @@ startTest("struct_values", function() { assert(ret.valueEnum === suite.Test.EnumEx.FOURTH); }); +// Events // + startTest("event_simple", function() { var v = false; var obj = new TestObject(null); @@ -332,6 +334,8 @@ startTest("event_stringarg", function() { assert(v); }); +// Array // + // // TODO: disabled. Not implemented yet // startTest("integral_array", function() { // var obj = new TestObject(null); @@ -431,6 +435,8 @@ startTest("method_array_of_structs", function() { assert(s.valueEnum === suite.Test.EnumEx.THIRD); }); +// List // + startTest("list_in_list_out", function() { var obj = new TestObject(null); var newList = obj.checkMethodListWith42(); @@ -524,6 +530,8 @@ startTest("method_list_of_structs", function() { assert(s.valueEnum === suite.Test.EnumEx.THIRD); }); +// Accessor // + startTest("method_accessor_of_objects", function() { var obj = new TestObject(null); var acc = obj.checkMethodAccessorOfObjects(null); @@ -606,6 +614,125 @@ startTest("method_accessor_of_structs", function() { assert(s.valueEnum === suite.Test.EnumEx.THIRD); }); +// Iterator // + +startTest("method_iterator_of_objects", function() { + var obj = new TestObject(null); + var it = obj.checkMethodIteratorOfObjects(null); + assert(it != null); + it = obj.checkMethodIteratorOfObjects(it); + assert(it != null); + var idx = 0; + for (var n = it.next(); !n.done; n = it.next()) { + var v = n.value; + assert(v != null); + var expectedValue = 1234; + v.checkMethodIntegralInA(expectedValue); + var actualValue = v.checkMethodIntegralOutA(); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); + idx++; + } + assert(idx == 2, idx + " == 2"); +}); + +startTest("method_iterator_of_strings", function() { + var obj = new TestObject(null); + var it = obj.checkMethodIteratorOfStrings(null); + assert(it != null); + it = obj.checkMethodIteratorOfStrings(it); + assert(it != null); + var cmp = ["foo", "bar"]; + var idx = 0; + for (var n = it.next(); !n.done; n = it.next()) { + var v = n.value; + assert(v === cmp[idx], idx+": "+v+" === "+cmp[idx]); + idx++; + } + assert(idx == 2, idx + " == 2"); +}); + +startTest("method_iterator_of_ints", function() { + var obj = new TestObject(null); + var it = obj.checkMethodIteratorOfInts(null); + assert(it != null); + it = obj.checkMethodIteratorOfInts(it); + assert(it != null); + var cmp = [42, 24]; + var idx = 0; + for (var n = it.next(); !n.done; n = it.next()) { + var v = n.value; + assert(v === cmp[idx], idx+": "+v+" === "+cmp[idx]); + idx++; + } + assert(idx == 2, idx + " == 2"); +}); + +startTest("method_iterator_of_bools", function() { + var obj = new TestObject(null); + var it = obj.checkMethodIteratorOfBools(null); + assert(it != null); + it = obj.checkMethodIteratorOfBools(it); + assert(it != null); + var cmp = [true, false]; + var idx = 0; + for (var n = it.next(); !n.done; n = it.next()) { + var v = n.value; + assert(v === cmp[idx], idx+": "+v+" === "+cmp[idx]); + idx++; + } + assert(idx == 2, idx + " == 2"); +}); + +startTest("method_iterator_of_doubles", function() { + var obj = new TestObject(null); + var it = obj.checkMethodIteratorOfDoubles(null); + assert(it != null); + it = obj.checkMethodIteratorOfDoubles(it); + assert(it != null); + var cmp = [42.0, 24.0]; + var idx = 0; + for (var n = it.next(); !n.done; n = it.next()) { + var v = n.value; + assert(v === cmp[idx], idx+": "+v+" === "+cmp[idx]); + idx++; + } + assert(idx == 2, idx + " == 2"); +}); + +startTest("method_iterator_of_enums", function() { + var obj = new TestObject(null); + var it = obj.checkMethodIteratorOfEnums(null); + assert(it != null); + it = obj.checkMethodIteratorOfEnums(it); + assert(it != null); + var cmp = [suite.Test.EnumEx.THIRD, suite.Test.EnumEx.FIRST]; + var idx = 0; + for (var n = it.next(); !n.done; n = it.next()) { + var v = n.value; + assert(v === cmp[idx], idx+": "+v+" === "+cmp[idx]); + idx++; + } + assert(idx == 2, idx + " == 2"); +}); + +startTest("method_iterator_of_structs", function() { + var obj = new TestObject(null); + var it = obj.checkMethodIteratorOfStructs(null); + assert(it != null); + it = obj.checkMethodIteratorOfStructs(it); + assert(it != null); + var cmp = [[42, suite.Test.EnumEx.THIRD], [24, suite.Test.EnumEx.FIRST]]; + var idx = 0; + for (var n = it.next(); !n.done; n = it.next()) { + var v = n.value; + assert(v != null); + assert(v.valueInt === cmp[idx][0], idx+": "+v.valueInt+" === "+cmp[idx][0]); + assert(v.valueEnum === cmp[idx][1], idx+": "+v.valueEnum+" === "+cmp[idx][1]); + idx++; + } + assert(idx == 2, idx + " == 2"); +}); + // Combinations of complex types // // FIXME diff --git a/src/tests/eolian_js/eolian_js_test_test_object_impl.c b/src/tests/eolian_js/eolian_js_test_test_object_impl.c index aecfbbf15a..34981a1ec7 100644 --- a/src/tests/eolian_js/eolian_js_test_test_object_impl.c +++ b/src/tests/eolian_js/eolian_js_test_test_object_impl.c @@ -587,6 +587,128 @@ _test_object_method_accessor_of_structs_check(Eo* obj EINA_UNUSED, return eina_array_accessor_new(arr); } +// Iterator // + +EOLIAN static Eina_Iterator * +_test_object_method_iterator_of_objects_check(Eo* obj, + Test_Object_Data *pd EINA_UNUSED, + Eina_Iterator *i_in) +{ + fprintf(stdout, "_test_object_method_iterator_of_objects_check(%p)\n", i_in); + fflush(stdout); + if (i_in) return i_in; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, obj); + eina_array_push(arr, obj); + return eina_array_iterator_new(arr); +} + +EOLIAN static Eina_Iterator * +_test_object_method_iterator_of_strings_check(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Iterator *i_in) +{ + fprintf(stdout, "_test_object_method_iterator_of_strings_check(%p)\n", i_in); + fflush(stdout); + if (i_in) return i_in; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, "foo"); + eina_array_push(arr, "bar"); + return eina_array_iterator_new(arr); +} + +EOLIAN static Eina_Iterator * +_test_object_method_iterator_of_ints_check(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Iterator *i_in) +{ + fprintf(stdout, "_test_object_method_iterator_of_ints_check(%p)\n", i_in); + fflush(stdout); + if (i_in) return i_in; + Eina_Array *arr = eina_array_new(2); + int *v = malloc(sizeof(int)); + *v = 42; + eina_array_push(arr, v); + v = malloc(sizeof(int)); + *v = 24; + eina_array_push(arr, v); + return eina_array_iterator_new(arr); +} + +EOLIAN static Eina_Iterator * +_test_object_method_iterator_of_bools_check(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Iterator *i_in) +{ + fprintf(stdout, "_test_object_method_iterator_of_bools_check(%p)\n", i_in); + fflush(stdout); + if (i_in) return i_in; + Eina_Array *arr = eina_array_new(2); + Eina_Bool *v = malloc(sizeof(Eina_Bool)); + *v = EINA_TRUE; + eina_array_push(arr, v); + v = malloc(sizeof(Eina_Bool)); + *v = EINA_FALSE; + eina_array_push(arr, v); + return eina_array_iterator_new(arr); +} + +EOLIAN static Eina_Iterator * +_test_object_method_iterator_of_doubles_check(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Iterator *i_in) +{ + fprintf(stdout, "_test_object_method_iterator_of_doubles_check(%p)\n", i_in); + fflush(stdout); + if (i_in) return i_in; + Eina_Array *arr = eina_array_new(2); + double *v = malloc(sizeof(double)); + *v = 42.0; + eina_array_push(arr, v); + v = malloc(sizeof(double)); + *v = 24.0; + eina_array_push(arr, v); + return eina_array_iterator_new(arr); +} + +EOLIAN static Eina_Iterator * +_test_object_method_iterator_of_enums_check(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Iterator *i_in) +{ + fprintf(stdout, "_test_object_method_iterator_of_enums_check(%p)\n", i_in); + fflush(stdout); + if (i_in) return i_in; + Eina_Array *arr = eina_array_new(2); + Test_Enum_Ex *v = malloc(sizeof(Test_Enum_Ex)); + *v = TEST_ENUM_EX_THIRD; + eina_array_push(arr, v); + v = malloc(sizeof(Test_Enum_Ex)); + *v = TEST_ENUM_EX_FIRST; + eina_array_push(arr, v); + return eina_array_iterator_new(arr); +} + +EOLIAN static Eina_Iterator * +_test_object_method_iterator_of_structs_check(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Iterator *i_in) +{ + fprintf(stdout, "_test_object_method_iterator_of_structs_check(%p)\n", i_in); + fflush(stdout); + if (i_in) return i_in; + Eina_Array *arr = eina_array_new(2); + Test_Struct_Ex *v = malloc(sizeof(Test_Struct_Ex)); + v->value_int = 42; + v->value_enum = TEST_ENUM_EX_THIRD; + eina_array_push(arr, v); + v = malloc(sizeof(Test_Struct_Ex)); + v->value_int = 24; + v->value_enum = TEST_ENUM_EX_FIRST; + eina_array_push(arr, v); + return eina_array_iterator_new(arr); +} + // Combinations of complex types EOLIAN static Eina_List * diff --git a/src/tests/eolian_js/test_object.eo b/src/tests/eolian_js/test_object.eo index 81043fe81d..4cbfbdc60a 100644 --- a/src/tests/eolian_js/test_object.eo +++ b/src/tests/eolian_js/test_object.eo @@ -251,6 +251,48 @@ class Test.Object (Eo.Base) { } return: accessor *; } + method_iterator_of_objects_check { + params { + @in i_in: iterator *; + } + return: iterator *; + } + method_iterator_of_strings_check { + params { + @in i_in: iterator *; + } + return: iterator *; + } + method_iterator_of_ints_check { + params { + @in i_in: iterator *; + } + return: iterator *; + } + method_iterator_of_bools_check { + params { + @in i_in: iterator *; + } + return: iterator *; + } + method_iterator_of_doubles_check { + params { + @in i_in: iterator *; + } + return: iterator *; + } + method_iterator_of_enums_check { + params { + @in i_in: iterator *; + } + return: iterator *; + } + method_iterator_of_structs_check { + params { + @in i_in: iterator *; + } + return: iterator *; + } method_array_of_arrays_of_ints_check { params { @in a_in: array *> *;