diff options
141 files changed, 20314 insertions, 137 deletions
diff --git a/.gitignore b/.gitignore index d93f853e29..c779341a62 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ tags *.eo.legacy.h *.eo.hh *.eo.impl.hh +*.eo.js.cc *.eo.lua *.luac .dir-locals.el diff --git a/Makefile.am b/Makefile.am index 8363720df2..2e90bf3cd5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -172,6 +172,14 @@ if HAVE_ELUA pkgconfig_DATA += pc/elua.pc endif +if HAVE_JS +pkgconfig_DATA += \ +pc/eolian-js.pc \ +pc/efl-js.pc \ +pc/eo-js.pc \ +pc/eina-js.pc +endif + if BUILD_ENGINE_SOFTWARE_X11 pkgconfig_DATA += pc/evas-software-x11.pc endif diff --git a/configure.ac b/configure.ac index 08976a5645..6e5953b321 100644 --- a/configure.ac +++ b/configure.ac @@ -1051,6 +1051,191 @@ EFL_EVAL_PKGS([EINA_CXX]) EFL_LIB_END([Eina_Cxx]) #### End of Eina CXX +AC_ARG_WITH([js], + [AS_HELP_STRING([--with-js=@<:@nodejs/libv8/libuv/none@:>@],[enable JavaScript bindings using nodejs or libv8/libuv as build dependencies. The libuv option implies libv8. @<:@default=none@:>@])], + [want_js="${withval}"], [want_js="none"]) + +EFLJS_CXXFLAGS="" +AC_LANG_PUSH([C++]) +case "$want_js" in + nodejs) + AC_CHECK_HEADERS([node/v8.h nodejs/deps/v8/v8.h nodejs/deps/v8/include/v8.h nodejs/src/v8.h v8.h], + [ + v8_header=AC_header + v8_header_define=AS_TR_CPP([HAVE_]AC_header) + EFLJS_CXXFLAGS="$EFLJS_CXXFLAGS -D$v8_header_define" + break + ] + [AC_MSG_ERROR([Could not find v8 include headers from nodejs.])]) + AC_CHECK_HEADERS([node/node.h nodejs/deps/node/node.h nodejs/deps/node/include/node.h nodejs/src/node.h node.h], + [ + node_header_define=AS_TR_CPP([HAVE_]AC_header) + EFLJS_CXXFLAGS="$EFLJS_CXXFLAGS -D$node_header_define" + break + ] + [AC_MSG_ERROR([Could not find node include headers from nodejs.])]) + AC_CHECK_HEADERS([node/uv.h nodejs/deps/uv/uv.h nodejs/deps/uv/include/uv.h nodejs/src/uv.h uv.h], + [ + uv_header_define=AS_TR_CPP([HAVE_]AC_header) + EFLJS_CXXFLAGS="$EFLJS_CXXFLAGS -D$uv_header_define" + break + ] + [AC_MSG_ERROR([Could not find uv include headers from nodejs.])]) + ;; + libv8) + AC_CHECK_HEADERS([v8.h], + [ + v8_header=AC_header + break + ] + [AC_MSG_ERROR([Could not find v8 include headers from libv8.])]) + ;; + libuv) + AC_CHECK_HEADERS([v8.h], + [ + v8_header=AC_header + break + ] + [AC_MSG_ERROR([Could not find v8 include headers from libv8.])]) + AC_CHECK_HEADERS([uv.h], + [break] + [AC_MSG_ERROR([Could not find uv include headers from libuv.])]) + ;; + none) + ;; + *) AC_MSG_ERROR([Invalid javascript dependency (${want_js}): must be none, nodejs, libv8 or libuv]) ;; +esac + +have_v8_global="no" +have_v8_create_params="no" +if test "$want_js" != "none" ; then +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include "$v8_header" + ]], + [[ +v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = nullptr; + ]]) + ], + [ + AC_DEFINE(HAVE_V8_CREATE_PARAMS, 1, [Define to 1 if you must pass create_params explicitly.]) + have_v8_create_params="yes" + AC_MSG_NOTICE([checking for v8::Isolate::CreateParams... yes]) + ], + [ + AC_MSG_NOTICE([checking for v8::Isolate::CreateParams... no]) + ]) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include "$v8_header" +#include <type_traits> + ]], + [[ + static_assert((std::is_same< ::v8::Global<void>, ::v8::UniquePersistent<void>>::value), ""); + ]]) + ], + [ + AC_DEFINE(HAVE_V8_GLOBAL, 1, [Define to 1 if you must pass create_params explicitly.]) + have_v8_global="yes" + AC_MSG_NOTICE([checking for v8::Global<T> class... yes]) + ], + [ + AC_MSG_NOTICE([checking for v8::Global<T> class... no]) + ]) +fi +AM_CONDITIONAL([HAVE_V8_CREATE_PARAMS], [test "x${have_v8_create_params}" = "xyes"]) +AM_CONDITIONAL([HAVE_V8_GLOBAL], [test "x${have_v8_global}" = "xyes"]) +AC_SUBST([HAVE_V8_CREATE_PARAMS]) +AC_SUBST([HAVE_V8_GLOBAL]) +AC_LANG_POP([C++]) + +AM_CONDITIONAL([HAVE_NODEJS], [test "x${want_js}" = "xnodejs"]) +AC_DEFINE_IF([HAVE_NODEJS], [test "x${want_js}" = "xnodejs"], + [1], [Using NodeJS]) +AC_SUBST([want_js]) +AC_SUBST([HAVE_NODEJS]) + +have_js="no" +if test "x${want_js}" != "xnone" ; then + have_js="yes" +fi +AM_CONDITIONAL([HAVE_JS], [test "x${have_js}" = "xyes"]) +AC_DEFINE_IF([HAVE_JS], [test "x${have_js}" = "xyes"], [1], [Compiling bindings for JavaScript]) +AC_SUBST([HAVE_JS]) + +AM_CONDITIONAL([HAVE_LIBUV], [test "x${want_js}" = "xnodejs" -o "x${want_js}" = "xlibuv"]) +AC_DEFINE_IF([HAVE_LIBUV], [test "x${want_js}" = "xnodejs" -o "x${want_js}" = "xlibuv"], + [1], [Compiling libuv event loop integration]) +AC_SUBST([HAVE_LIBUV]) + +# For efljspack mime handling +AM_CONDITIONAL([HAVE_XDG_DATA_HOME], [test "x${XDG_DATA_HOME}" != "x"]) +AM_COND_IF([HAVE_XDG_DATA_HOME], [AC_SUBST([XDG_DATA_HOME])], [AC_SUBST([XDG_DATA_HOME], "$HOME/.local/share")]) + +#### Eina JS +EFL_LIB_START_OPTIONAL([Eina_Js], [test "x${have_js}" = "xyes"]) +EFL_INTERNAL_DEPEND_PKG([EINA_JS], [Eina]) +EFL_INTERNAL_DEPEND_PKG([EINA_JS], [Eo]) +EFL_ADD_CFLAGS([EINA_JS], [${EFL_PTHREAD_CFLAGS}]) +EFL_EVAL_PKGS([EINA_JS]) + +EFL_LIB_END_OPTIONAL([Eina_Js]) +#### End of Eina JS + +#### Ecore JS +EFL_LIB_START_OPTIONAL([Ecore_Js], [test "x${have_js}" = "xyes"]) + +EFL_INTERNAL_DEPEND_PKG([ECORE_JS], [ecore]) +EFL_INTERNAL_DEPEND_PKG([ECORE_JS], [ecore_file]) +EFL_ADD_CFLAGS([ECORE_JS], [${EFL_PTHREAD_CFLAGS}]) +EFL_EVAL_PKGS([ECORE_JS]) + +EFL_LIB_END_OPTIONAL([Ecore_Js]) +#### End of Ecore JS + +#### Eio JS +EFL_LIB_START_OPTIONAL([Eio_Js], [test "x${have_js}" = "xyes"]) + +EFL_INTERNAL_DEPEND_PKG([EIO_JS], [eio]) +EFL_ADD_CFLAGS([EIO_JS], [${EFL_PTHREAD_CFLAGS}]) +EFL_EVAL_PKGS([EIO_JS]) + +EFL_LIB_END_OPTIONAL([Eio_Js]) +#### End of Eio JS + +#### Ethumb JS +EFL_LIB_START_OPTIONAL([Ethumb_Js], [test "x${have_js}" = "xyes"]) + +EFL_INTERNAL_DEPEND_PKG([ETHUMB_JS], [ethumb]) +EFL_INTERNAL_DEPEND_PKG([ETHUMB_JS], [ethumb_client]) +EFL_ADD_CFLAGS([ETHUMB_JS], [${EFL_PTHREAD_CFLAGS}]) +EFL_EVAL_PKGS([ETHUMB_JS]) + +EFL_LIB_END_OPTIONAL([Ethumb_Js]) +#### End of Ethumb JS + +#### Eldbus JS +EFL_LIB_START_OPTIONAL([Eldbus_Js], [test "x${have_js}" = "xyes"]) + +EFL_INTERNAL_DEPEND_PKG([ELDBUS_JS], [eldbus]) +EFL_ADD_CFLAGS([ELDBUS_JS], [${EFL_PTHREAD_CFLAGS}]) +EFL_EVAL_PKGS([ELDBUS_JS]) + +EFL_LIB_END_OPTIONAL([Eldbus_Js]) +#### End of Eldbus JS + +#### Eo JS +EFL_LIB_START_OPTIONAL([Eo_Js], [test "x${have_js}" = "xyes"]) + +EFL_INTERNAL_DEPEND_PKG([EO_JS], [eina]) +EFL_ADD_CFLAGS([EO_JS], [${EFL_PTHREAD_CFLAGS}]) +EFL_EVAL_PKGS([EO_JS]) + +EFL_LIB_END_OPTIONAL([Eo_Js]) +#### End of Eo JS + #### Eo EFL_LIB_START([Eo]) @@ -1244,6 +1429,15 @@ EFL_INTERNAL_DEPEND_PKG([EOLIAN], [eina]) EFL_LIB_END([Eolian]) #### End of Eolian +EFL_LIB_START_OPTIONAL([Eolian_Js], [test "${have_js}" = "yes"]) + +EFL_INTERNAL_DEPEND_PKG([EOLIAN_JS], [eina]) +EFL_INTERNAL_DEPEND_PKG([EOLIAN_JS], [eolian]) + +EFL_LIB_END_OPTIONAL([Eolian_Js]) +#### End of Eolian + + EFL_LIB_START([Eolian_Cxx]) ### Default values @@ -2322,6 +2516,17 @@ AC_ARG_ENABLE([g-main-loop], fi ], [want_g_main_loop="no"]) +AC_ARG_ENABLE([libuv], + [AS_HELP_STRING([--enable-libuv],[enable ecore_main_loop based on libuv. @<:@default=disabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + want_libuv="yes" + CFOPT_WARNING="xyes" + else + want_libuv="no" + fi + ], + [want_libuv="no"]) AC_ARG_ENABLE([gstreamer], [AS_HELP_STRING([--enable-gstreamer],[enable gstreamer 0.10 support. @<:@default=disabled@:>@])], @@ -2410,6 +2615,7 @@ EFL_OPTIONAL_DEPEND_PKG([ECORE], [${want_systemd}], [SYSTEMD], [libsystemd]) EFL_ADD_FEATURE([ECORE], [systemd-daemon], [${want_systemd}]) EFL_ADD_FEATURE([ECORE], [glib]) EFL_ADD_FEATURE([ECORE], [g-main-loop]) +EFL_ADD_FEATURE([ECORE], [libuv]) want_glib_integration_always=no if test "x${with_glib}" = "xalways" ; then @@ -2419,6 +2625,9 @@ fi if test "x${want_g_main_loop}" = "xyes" ; then AC_DEFINE([USE_G_MAIN_LOOP], [1], [Use g_main_loop in ecore]) + if test "x${want_js}" = "xnodejs" -o "x${want_js}" = "xlibuv" ; then + AC_MSG_ERROR([Can't define glib and libuv integration together]) + fi fi # not EFL_OPTIONAL_DEPEND_PKG() because it's only used for ecore examples @@ -4007,7 +4216,7 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [emile]) ECORE_EVAS_MODULE([extn], [${want_ecore_evas_extn}]) ECORE_EVAS_MODULE([ews], [yes]) ECORE_EVAS_MODULE([fb], [${want_fb}]) -ECORE_EVAS_MODULE([drm], [${want_drm}], +ECORE_EVAS_MODULE([drm], [${want_drm}], [EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_drm}], [ecore-drm])]) ECORE_EVAS_MODULE([gl-drm], [${want_gl_drm}], [EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_gl_drm}], [ecore-drm])]) @@ -4677,6 +4886,63 @@ EFL_ADD_LIBS([ELOCATION], [-lm]) EFL_LIB_END([Elocation]) #### End of Elocation + + +#### Efl_Js +EFL_LIB_START_OPTIONAL([Efl_Js], [test "x${have_js}" = "xyes"]) + +### Default values + +### Additional options to configure + +### Checks for programs + +### Checks for libraries +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Eina]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Eo]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Ecore]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Eet]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Ecore_Evas]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Ecore_Con]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Ecore_Audio]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Efl]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Evas]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Edje]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Emotion]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Eldbus]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Emile]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Ethumb_Client]) +EFL_INTERNAL_DEPEND_PKG([EFL_JS], [Eio]) + +AM_COND_IF([HAVE_NODEJS], [], [ EFL_ADD_LIBS([EFL_JS], [-lv8]) ]) + +EFL_EVAL_PKGS([EFL_JS]) + +AM_COND_IF([HAVE_NODEJS], [EFLJS_CXXFLAGS="$EFLJS_CXXFLAGS -DHAVE_NODEJS"], []) +AM_COND_IF([HAVE_LIBUV], [EFLJS_CXXFLAGS="$EFLJS_CXXFLAGS -DHAVE_LIBUV"], []) +AM_COND_IF([HAVE_JS], [EFLJS_CXXFLAGS="$EFLJS_CXXFLAGS -DHAVE_JS"], []) + +AM_COND_IF([HAVE_V8_CREATE_PARAMS], [EFLJS_CXXFLAGS="$EFLJS_CXXFLAGS -DHAVE_V8_CREATE_PARAMS"], []) +AM_COND_IF([HAVE_V8_GLOBAL], [EFLJS_CXXFLAGS="$EFLJS_CXXFLAGS -DHAVE_V8_GLOBAL"], []) +AC_SUBST([EFLJS_CXXFLAGS]) + +### Checks for header files + +### Checks for types + +### Checks for structures + +### Checks for compiler characteristics + +### Checks for linker characteristics + +### Checks for library functions + +### Check availability + +EFL_LIB_END_OPTIONAL([Efl_Js]) +#### End of Efl_Js + ### Add Wayland server library if test is enabled if test "x${want_tests}" = "xyes" -a "x${want_wayland}" = "xyes"; then EFL_DEPEND_PKG([ECORE_WAYLAND_SRV], [WAYLAND], [wayland-server >= 1.8.0]) @@ -4809,6 +5075,10 @@ pc/eo.pc pc/eo-cxx.pc pc/eolian.pc pc/eolian-cxx.pc +pc/eina-js.pc +pc/efl-js.pc +pc/eolian-js.pc +pc/eo-js.pc pc/efl.pc pc/efl-cxx.pc pc/evas-fb.pc @@ -4991,6 +5261,8 @@ echo " Cryptography..: ${build_crypto}" echo " X11...........: ${with_x11}" echo " OpenGL........: ${with_opengl}" echo " C++11.........: ${have_cxx11}" +echo " JavaScript....: ${want_js}" +echo " JavaScript flg: $EINA_JS_LIBS" echo "Eina............: yes (${features_eina} unwind=$have_unwind)" echo "Eo..............: yes (${features_eo})" echo "Eolian..........: yes (${features_eolian})" @@ -5052,6 +5324,7 @@ echo " CPPFLAGS......: $CPPFLAGS" echo " CFLAGS........: $CFLAGS" echo " CXXFLAGS......: $CXXFLAGS" echo " LDFLAGS.......: $LDFLAGS" +echo " EFLJS_CXXFLAGS: $EFLJS_CXXFLAGS" if test "x${with_binary_edje_cc}" != "x"; then echo " edje_cc.......: ${with_binary_edje_cc}" diff --git a/pc/.gitignore b/pc/.gitignore index c6b8eb4447..1858516cab 100644 --- a/pc/.gitignore +++ b/pc/.gitignore @@ -28,6 +28,7 @@ /efreet.pc /eina.pc /eina-cxx.pc +/eina-js.pc /eet-cxx.pc /eio.pc /eio-cxx.pc @@ -36,6 +37,7 @@ /embryo.pc /emotion.pc /eo.pc +/eo-js.pc /ephysics.pc /escape.pc /ethumb.pc @@ -57,6 +59,7 @@ /evil.pc /eolian.pc /eolian-cxx.pc +/eolian-js.pc /eo-cxx.pc /evas-cxx.pc /ecore-cxx.pc diff --git a/pc/efl-js.pc.in b/pc/efl-js.pc.in new file mode 100644 index 0000000000..0c1e00c00c --- /dev/null +++ b/pc/efl-js.pc.in @@ -0,0 +1,15 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ +datadir=@datadir@ +want_js=@want_js@ + +Name: EFL JavaScript +Description: JavaScript C++ helpers for data structures +Version: @PACKAGE_VERSION@ +Requires.private: @requirements_pc_eina@ +Libs.private: @requirements_libs_eina@ +Libs: -L${libdir} -lefl_js +Cflags: -I${includedir}/efl-js-@VMAJ@ @EFLJS_CXXFLAGS@ diff --git a/pc/eina-js.pc.in b/pc/eina-js.pc.in new file mode 100644 index 0000000000..6aab608ceb --- /dev/null +++ b/pc/eina-js.pc.in @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ +datadir=@datadir@ +want_js=@want_js@ + +Name: Eina JavaScript +Description: JavaScript C++ helpers for data structures +Version: @PACKAGE_VERSION@ +Requires.private: @requirements_pc_eina@ +Libs.private: @requirements_libs_eina@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eina-@VMAJ@ -I${includedir}/eina-js-@VMAJ@
\ No newline at end of file diff --git a/pc/eo-js.pc.in b/pc/eo-js.pc.in new file mode 100644 index 0000000000..3dedf5c265 --- /dev/null +++ b/pc/eo-js.pc.in @@ -0,0 +1,15 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ +datadir=@datadir@ +eoincludedir=@datadir@/eolian/include +eolian_flags=-I${eoincludedir}/eo-@VMAJ@ + +Name: Eo JavaScript +Description: JavaScript C++ helpers for bindings for EFL's generic object system. +Version: @PACKAGE_VERSION@ +Requires.private: @requirements_pc_eo@ +Libs.private: @requirements_libs_eo@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eo-@VMAJ@ -I${includedir}/eo-js-@VMAJ@
\ No newline at end of file diff --git a/pc/eolian-js.pc.in b/pc/eolian-js.pc.in new file mode 100644 index 0000000000..2dbc1cac73 --- /dev/null +++ b/pc/eolian-js.pc.in @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ +datadir=@datadir@ + +Name: Eolian-JS +Description: EFL's JavaScript bindings generator. +Version: @VERSION@ +Require.private: @requirements_pc_eolian@ +Libs: -L${libdir} +Libs.private: @requirements_libs_eolian@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eolian-js-@VMAJ@ diff --git a/pc/evas.pc.in b/pc/evas.pc.in index 4fd66b99d3..c49c058635 100644 --- a/pc/evas.pc.in +++ b/pc/evas.pc.in @@ -13,4 +13,4 @@ Requires.private: @requirements_pc_evas@ Version: @VERSION@ Libs: -L${libdir} -levas Libs.private: @requirements_libs_evas@ -Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/evas-@VMAJ@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/evas-@VMAJ@ -I${includedir}/evas-@VMAJ@/canvas diff --git a/src/Makefile.am b/src/Makefile.am index 6ac8dc7580..248711bc34 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,6 +15,7 @@ check_PROGRAMS = TESTS = EXTRA_DIST = +GENERATED_JS_BINDINGS = EFL_INSTALL_EXEC_HOOK= @@ -76,6 +77,21 @@ include Makefile_Eio_Cxx.am include Makefile_Elua.am include Makefile_Elocation.am +if HAVE_JS +AM_V_CP = $(am__v_CP_@AM_V@) +am__v_CP_ = $(am__v_CP_@AM_DEFAULT_V@) +am__v_CP_0 = @echo " CP " $@; +CP = cp +if EFL_ENABLE_TESTS +if HAVE_NODEJS +AM_TESTS_ENVIRONMENT = NODE_PATH='$(abs_builddir)/lib/efl_js:$(abs_builddir)/tests/eolian_js:$(abs_builddir)/tests/efl_js'; export NODE_PATH; +endif +endif +endif + +include Makefile_Eolian_Js.am +include Makefile_Efl_Js.am + .PHONY: benchmark examples BENCHMARK_SUBDIRS = \ diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am index b7e0b6b74d..13e5473a21 100644 --- a/src/Makefile_Ecore.am +++ b/src/Makefile_Ecore.am @@ -271,3 +271,13 @@ installed_ecoreluadir = $(datadir)/elua/modules/ecore nodist_installed_ecorelua_DATA = $(generated_ecore_lua_all) endif + +if HAVE_JS + +generated_ecore_js_bindings = $(ecore_eolian_files:%.eo=%.eo.js.cc) + +CLEANFILES += $(generated_ecore_js_bindings) + +GENERATED_JS_BINDINGS += $(generated_ecore_js_bindings) + +endif diff --git a/src/Makefile_Ecore_Audio.am b/src/Makefile_Ecore_Audio.am index ccce8f7fc0..b500118736 100644 --- a/src/Makefile_Ecore_Audio.am +++ b/src/Makefile_Ecore_Audio.am @@ -104,4 +104,15 @@ nodist_installed_ecoreaudiolua_DATA = $(generated_ecore_audio_lua_all) endif +if HAVE_JS + +generated_ecore_audio_js_bindings = $(ecore_audio_eolian_files:%.eo=%.eo.js.cc) + +CLEANFILES += $(generated_ecore_audio_js_bindings) + +GENERATED_JS_BINDINGS += $(generated_ecore_audio_js_bindings) + endif + +endif + diff --git a/src/Makefile_Ecore_Con.am b/src/Makefile_Ecore_Con.am index 87ad889b26..544e6d949f 100644 --- a/src/Makefile_Ecore_Con.am +++ b/src/Makefile_Ecore_Con.am @@ -143,3 +143,13 @@ installed_ecoreconluadir = $(datadir)/elua/modules/ecore_con nodist_installed_ecoreconlua_DATA = $(generated_ecore_con_lua_all) endif + +if HAVE_JS + +generated_ecore_con_js_bindings = $(ecore_con_eolian_files:%.eo=%.eo.js.cc) + +CLEANFILES += $(generated_ecore_con_js_bindings) + +GENERATED_JS_BINDINGS += $(generated_ecore_con_js_bindings) + +endif diff --git a/src/Makefile_Ecore_Js.am b/src/Makefile_Ecore_Js.am new file mode 100644 index 0000000000..df5ac2f5b1 --- /dev/null +++ b/src/Makefile_Ecore_Js.am @@ -0,0 +1,19 @@ + +### Library + +if HAVE_JS +installed_ecorejsheadersdir = $(includedir)/ecore-js-@VMAJ@ +dist_installed_ecorejsheaders_DATA = \ +bindings/js/ecore_js/Ecore_Js.hh \ +bindings/js/ecore_js/ecore_js_init.hh \ +bindings/js/ecore_js/ecore_js_mainloop.hh \ +bindings/js/ecore_js/ecore_js_timer.hh \ +bindings/js/ecore_js/ecore_js_event.hh \ +bindings/js/ecore_js/ecore_js_job.hh \ +bindings/js/ecore_js/ecore_js_idle.hh \ +bindings/js/ecore_js/ecore_js_animator.hh \ +bindings/js/ecore_js/ecore_js_poller.hh \ +bindings/js/ecore_js/ecore_js_throttle.hh \ +bindings/js/ecore_js/ecore_js_file.hh +endif + diff --git a/src/Makefile_Edje.am b/src/Makefile_Edje.am index ca0eefc463..4fa0ecf09f 100644 --- a/src/Makefile_Edje.am +++ b/src/Makefile_Edje.am @@ -130,7 +130,7 @@ if HAVE_WIN32 USE_EDJE_BIN_LIBS = -L$(top_builddir)/src/lib/evil @USE_EDJE_LIBS@ else USE_EDJE_BIN_LIBS = @USE_EDJE_LIBS@ -endif +endif bin_PROGRAMS += \ bin/edje/edje_cc \ @@ -334,3 +334,13 @@ installed_edjeluadir = $(datadir)/elua/modules/edje nodist_installed_edjelua_DATA = $(generated_edje_lua_all) endif + +if HAVE_JS + +generated_edje_js_bindings = $(edje_eolian_files:%.eo=%.eo.js.cc) + +CLEANFILES += $(generated_edje_js_bindings) + +GENERATED_JS_BINDINGS += $(generated_edje_js_bindings) + +endif diff --git a/src/Makefile_Efl.am b/src/Makefile_Efl.am index f6b1c288c6..9e59bf22bf 100644 --- a/src/Makefile_Efl.am +++ b/src/Makefile_Efl.am @@ -80,6 +80,16 @@ nodist_installed_efllua_DATA = $(generated_efl_lua_all) endif +if HAVE_JS + +generated_efl_js_bindings = $(efl_eolian_files:%.eo=%.eo.js.cc) + +CLEANFILES += $(generated_efl_js_bindings) + +GENERATED_JS_BINDINGS += $(generated_efl_js_bindings) + +endif + ### Binary bin_PROGRAMS += \ diff --git a/src/Makefile_Efl_Js.am b/src/Makefile_Efl_Js.am new file mode 100644 index 0000000000..e993120a64 --- /dev/null +++ b/src/Makefile_Efl_Js.am @@ -0,0 +1,333 @@ +if HAVE_JS + +if HAVE_NODEJS + +noinst_lib_LTLIBRARIES = lib/efl_js/libefl_node_js.la +noinst_libdir = $(libdir)/efl_js + +$(top_builddir)/src/lib/efl_js/efl.node: lib/efl_js/libefl_node_js.la + $(AM_V_CP)$(CP) $(top_builddir)/src/lib/efl_js/.libs/libefl_node_js.so $(top_builddir)/src/lib/efl_js/efl.node + +eflnodedir = $(libdir)/node_modules +eflnode_DATA = $(top_builddir)/src/lib/efl_js/efl.node + +CLEANFILES += ${eflnodedir_DATA} +EXTRA_DIST += ${eflnodedir_DATA} + +efljsmimedir = @XDG_DATA_HOME@/mime/packages +efljsmime_DATA = bin/efl_js/efljslaunch.xml + +efljsdesktopdir = @XDG_DATA_HOME@/applications +efljsdesktop_DATA = bin/efl_js/efljslaunch.desktop + +bin_SCRIPTS += \ + bin/efl_js/efljslaunch \ + bin/efl_js/efljspack + +else + +bin_PROGRAMS += bin/efl_js/eflv8js + +bin_efl_js_eflv8js_SOURCES = \ + bin/efl_js/launcher_main.cc + +bin_efl_js_eflv8js_CPPFLAGS = \ + -I$(top_builddir)/src/lib/efl \ + -I$(top_srcdir)/src/bindings/js/efl_js \ + -I$(top_srcdir)/src/bindings/js/eina_js \ + -I$(top_srcdir)/src/bindings/js/eo_js \ + @CHECK_CFLAGS@ \ + @EINA_CXX_CFLAGS@ \ + @EO_CXX_CFLAGS@ \ + @EMILE_CFLAGS@ \ + @ECORE_CFLAGS@ \ + @EET_CFLAGS@ \ + @EO_CFLAGS@ \ + @EFL_JS_CFLAGS@ \ + @EINA_JS_CFLAGS@ \ + @EO_JS_CFLAGS@ + +bin_efl_js_eflv8js_LDFLAGS = \ + -lv8 \ + @USE_EFL_JS_INTERNAL_LIBS@ + +bin_efl_js_eflv8js_LDADD = \ + @USE_EFL_JS_LIBS@ + +endif + +bindings/js/efl_js/eolian_js_bindings.cc: $(GENERATED_JS_BINDINGS) + @echo @ECHO_E@ "#ifdef HAVE_CONFIG_H" > $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include \"config.h\"" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#endif\n" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Efl.h>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Efl_Config.h>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Ecore.h>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Eo.h>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Ecore_Con.h>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Ecore_Audio.h>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Evas.h>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Edje.h>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Ecore_Con_Eet.h>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @echo @ECHO_E@ "#include <Emotion.h>\n" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc + @for i in $(GENERATED_JS_BINDINGS); do echo "#include <$$i>" >> $(top_builddir)/src/bindings/js/efl_js/eolian_js_bindings.cc; done + +CLEANFILES += bindings/js/efl_js/eolian_js_bindings.cc + +## Install Ecore-JS headers +installed_ecorejsheadersdir = $(includedir)/ecore-js-@VMAJ@ +dist_installed_ecorejsheaders_DATA = \ +bindings/js/ecore_js/Ecore_Js.hh + +## Install Eio-JS headers +installed_eiojsheadersdir = $(includedir)/eio-js-@VMAJ@ +dist_installed_eiojsheaders_DATA = \ +bindings/js/eio_js/Eio_Js.hh + +## Install Ethumb-JS headers +installed_ethumbjsheadersdir = $(includedir)/ethumb-js-@VMAJ@ +dist_installed_ethumbjsheaders_DATA = \ +bindings/js/ethumb_js/Ethumb_Js.hh + +## Install Eldbus-JS headers +installed_eldbusjsheadersdir = $(includedir)/eldbus-js-@VMAJ@ +dist_installed_eldbusjsheaders_DATA = \ +bindings/js/eldbus_js/Eldbus_Js.hh + +## Install Eo-JS headers +installed_eojsmainheadersdir = $(includedir)/eo-js-@VMAJ@ +dist_installed_eojsmainheaders_DATA = \ +bindings/js/eo_js/eo_js_call_function.hh \ +bindings/js/eo_js/eo_js_constructor.hh \ +bindings/js/eo_js/eo_js_direction.hh \ +bindings/js/eo_js/eo_js_event.hh \ +bindings/js/eo_js/eo_js_namespace.hh \ +bindings/js/eo_js/eo_js_struct.hh \ +bindings/js/eo_js/eo_js_construct_from_eo.hh \ +bindings/js/eo_js/Eo_Js.hh + +## Install Eina-JS headers +installed_einajsheadersdir = $(includedir)/eina-js-@VMAJ@ +dist_installed_einajsheaders_DATA = \ +bindings/js/eina_js/Eina_Js.hh \ +bindings/js/eina_js/eina_js_accessor.hh \ +bindings/js/eina_js/eina_js_array.hh \ +bindings/js/eina_js/eina_js_compatibility.hh \ +bindings/js/eina_js/eina_js_container.hh \ +bindings/js/eina_js/eina_js_error.hh \ +bindings/js/eina_js/eina_js_get_value_from_c.hh \ +bindings/js/eina_js/eina_js_get_value.hh \ +bindings/js/eina_js/eina_js_iterator.hh \ +bindings/js/eina_js/eina_js_list.hh \ +bindings/js/eina_js/eina_js_log.hh \ +bindings/js/eina_js/eina_js_node.hh \ +bindings/js/eina_js/eina_js_value.hh + +installed_efljsheadersdir = $(includedir)/efl-js-@VMAJ@ +dist_installed_efljsheaders_DATA = \ +bindings/js/efl_js/Efl_Js.hh + +lib_LTLIBRARIES += lib/efl_js/libefl_js.la + +lib_efl_js_libefl_js_la_SOURCES = \ +bindings/js/eina_js/eina_js_container.cc \ +bindings/js/eina_js/eina_js_value.cc \ +bindings/js/eina_js/eina_js_error.cc \ +bindings/js/eina_js/eina_js_accessor.cc \ +bindings/js/eina_js/eina_js_log.cc \ +bindings/js/eina_js/eina_js_iterator.cc \ +bindings/js/eina_js/eina_js_compatibility.cc \ +bindings/js/ecore_js/ecore_js_init.cc \ +bindings/js/ecore_js/ecore_js_mainloop.cc \ +bindings/js/ecore_js/ecore_js_timer.cc \ +bindings/js/ecore_js/ecore_js_event.cc \ +bindings/js/ecore_js/ecore_js_job.cc \ +bindings/js/ecore_js/ecore_js_idle.cc \ +bindings/js/ecore_js/ecore_js_animator.cc \ +bindings/js/ecore_js/ecore_js_poller.cc \ +bindings/js/ecore_js/ecore_js_throttle.cc \ +bindings/js/eldbus_js/eldbus_js_core.cc \ +bindings/js/eldbus_js/eldbus_js_connection.cc \ +bindings/js/eldbus_js/eldbus_js_message.cc \ +bindings/js/eldbus_js/eldbus_js_object_mapper.cc \ +bindings/js/eio_js/eio_js.cc \ +bindings/js/ethumb_js/ethumb_js_client.cc + +nodist_lib_efl_js_libefl_js_la_SOURCES = \ +bindings/js/efl_js/eolian_js_bindings.cc + +bindings/js/efl_js/efl_js.cc $(lib_efl_js_libefl_js_la_SOURCES): $(generated_ecore_cxx_all) $(generated_eo_cxx_bindings) $(generated_efl_cxx_all) + +lib_efl_js_libefl_js_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-I$(top_srcdir)/src/lib/efl \ +-I$(top_builddir)/src/lib/efl/interfaces/ \ +-I$(top_builddir)/src/lib/evas/canvas/ \ +-I$(top_srcdir)/src/bindings/js/eina_js \ +-I$(top_srcdir)/src/bindings/js/ecore_js \ +-I$(top_srcdir)/src/bindings/js/eo_js \ +-I$(top_srcdir)/src/bindings/js/eldbus_js \ +-I$(top_srcdir)/src/bindings/js/eio_js \ +-I$(top_srcdir)/src/bindings/js/ethumb_js \ +@EFL_JS_CFLAGS@ \ +@EO_JS_CFLAGS@ \ +@ECORE_CXX_CFLAGS@ \ +@EO_CXX_CFLAGS@ \ +@ECORE_JS_CFLAGS@ \ +@EINA_JS_CFLAGS@ \ +@ELDBUS_JS_CFLAGS@ \ +@EIO_JS_CFLAGS@ \ +@ETHUMB_JS_CFLAGS@ \ +@EINA_CXX_CFLAGS@ +lib_efl_js_libefl_js_la_LIBADD = @EFL_JS_LIBS@ +lib_efl_js_libefl_js_la_DEPENDENCIES = @EFL_JS_INTERNAL_LIBS@ +lib_efl_js_libefl_js_la_LIBTOOLFLAGS = --tag=disable-static +lib_efl_js_libefl_js_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ + +if HAVE_NODEJS +lib_efl_js_libefl_node_js_la_SOURCES = \ +bindings/js/efl_js/efl_js.cc + +lib_efl_js_libefl_node_js_la_CPPFLAGS = $(lib_efl_js_libefl_js_la_CPPFLAGS) +lib_efl_js_libefl_node_js_la_LIBADD = @USE_EFL_JS_LIBS@ +lib_efl_js_libefl_node_js_la_DEPENDENCIES = @USE_EFL_JS_INTERNAL_LIBS@ +lib_efl_js_libefl_node_js_la_LIBTOOLFLAGS = --tag=disable-static +lib_efl_js_libefl_node_js_la_LDFLAGS = +else +lib_efl_js_libefl_js_la_SOURCES += \ +bindings/js/efl_js/efl_js.cc +endif + +if EFL_ENABLE_TESTS + +SUITE_RUNNER_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-I$(top_srcdir)/src/bindings/js/eina_js \ +-I$(top_srcdir)/src/bindings/js/eo_js \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/efl_js\" \ +-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)/src/tests/efl_js\" \ +-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/efl_js\" \ +@CHECK_CFLAGS@ \ +@EFL_JS_CFLAGS@ \ +@EINA_CXX_CFLAGS@ \ +@EO_CXX_CFLAGS@ \ +@EO_CFLAGS@ \ +@ECORE_CFLAGS@ \ +@ECORE_CXX_CFLAGS@ \ +@ECORE_JS_CFLAGS@ \ +@EINA_JS_CFLAGS@ + +if HAVE_NODEJS +TESTS += tests/efl_js/eina_js_suite.js \ +tests/efl_js/eina_js_containers_suite.js \ +tests/efl_js/ecore_js_suite.js \ +tests/efl_js/eldbus_js_suite.js \ +tests/efl_js/ethumb_js_suite.js \ +tests/efl_js/eio_js_suite.js \ +tests/efl_js/benchmark_js_suite.js + +check_LTLIBRARIES += tests/efl_js/libbenchmark_object.la + +tests/efl_js/eina_js_suite.js tests/efl_js/eina_js_containers_suite.js tests/efl_js/ecore_js_suite.js tests/efl_js/eldbus_js_suite.js tests/efl_js/eio_js_suite.js tests/efl_js/ethumb_js_suite.js: $(top_builddir)/src/lib/efl_js/efl.node + +tests/efl_js/benchmark_object.node: tests/efl_js/libbenchmark_object.la + $(AM_V_CP)$(CP) $(top_builddir)/src/tests/efl_js/.libs/libbenchmark_object.so $(top_builddir)/src/tests/efl_js/benchmark_object.node +tests/efl_js/benchmark_js_suite.js: $(top_builddir)/src/lib/efl_js/efl.node tests/efl_js/benchmark_object.node + +tests_efl_js_libbenchmark_object_la_SOURCES = tests/efl_js/benchmark_object_impl.cc +tests_efl_js_libbenchmark_object_la_CPPFLAGS = \ +-I$(top_builddir)/src/lib/efl \ +-I$(top_srcdir)/src/bindings/js/efl_js \ +-I$(top_builddir)/src/tests/efl_js \ +-I$(top_srcdir)/src/bindings/js/eina_js \ +-I$(top_srcdir)/src/bindings/js/eo_js \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/efl_js\" \ +-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)/src/tests/efl_js\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/efl_js\" \ +-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/efl_js\" \ +@CHECK_CFLAGS@ @EOLIAN_CXX_CFLAGS@ @EINA_JS_CFLAGS@ @EO_JS_CFLAGS@ \ +@EOLIAN_CFLAGS@ @EINA_CFLAGS@ @EO_CFLAGS@ @ECORE_CFLAGS@ @EINA_CXX_CFLAGS@ \ +@EO_JS_CFLAGS@ @EO_CXX_CFLAGS@ +tests_efl_js_libbenchmark_object_la_LIBADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ +tests_efl_js_libbenchmark_object_la_LDFLAGS = -rpath $(abs_top_builddir)/tests/efl_js @EFL_LTLIBRARY_FLAGS@ +tests_efl_js_libbenchmark_object_la_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ +tests_efl_js_libbenchmark_object_la_LIBTOOLFLAGS = --tag=disable-static + +tests/efl_js/tests_efl_js_libbenchmark_object_la-benchmark_object_impl.l$(OBJEXT): tests/efl_js/benchmark_object.eo.js.cc tests/efl_js/benchmark_object.eo.c tests/efl_js/benchmark_object.eo.h +else +check_PROGRAMS += \ +tests/efl_js/eina_js_suite \ +tests/efl_js/eina_js_containers_suite \ +tests/efl_js/ecore_js_suite \ +tests/efl_js/eldbus_js_suite \ +tests/efl_js/ethumb_js_suite \ +tests/efl_js/eio_js_suite \ +tests/efl_js/benchmark_js_suite +TESTS += tests/efl_js/eina_js_suite \ +tests/efl_js/ecore_js_suite \ +tests/efl_js/eldbus_js_suite \ +tests/efl_js/ethumb_js_suite \ +tests/efl_js/eio_js_suite \ +tests/efl_js/benchmark_js_suite + +tests_efl_js_eina_js_suite_SOURCES = \ +tests/efl_js/eina_js_suite.cc + +tests_efl_js_eina_js_suite_CPPFLAGS = $(SUITE_RUNNER_CPPFLAGS) +tests_efl_js_eina_js_suite_LDADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ +tests_efl_js_eina_js_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ + +tests_efl_js_eina_js_containers_suite_SOURCES = \ +tests/efl_js/eina_js_containers_suite.cc + +tests_efl_js_eina_js_containers_suite_CPPFLAGS = $(SUITE_RUNNER_CPPFLAGS) +tests_efl_js_eina_js_containers_suite_LDADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ +tests_efl_js_eina_js_containers_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ + +tests_efl_js_ecore_js_suite_SOURCES = \ +tests/efl_js/ecore_js_suite.cc + +tests_efl_js_ecore_js_suite_CPPFLAGS = $(SUITE_RUNNER_CPPFLAGS) +tests_efl_js_ecore_js_suite_LDADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ +tests_efl_js_ecore_js_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ + +tests_efl_js_eldbus_js_suite_SOURCES = \ +tests/efl_js/eldbus_js_suite.cc + +tests_efl_js_eldbus_js_suite_CPPFLAGS = $(SUITE_RUNNER_CPPFLAGS) +tests_efl_js_eldbus_js_suite_LDADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ +tests_efl_js_eldbus_js_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ + +tests_efl_js_ethumb_js_suite_SOURCES = \ +tests/efl_js/ethumb_js_suite.cc + +tests_efl_js_ethumb_js_suite_CPPFLAGS = $(SUITE_RUNNER_CPPFLAGS) +tests_efl_js_ethumb_js_suite_LDADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ +tests_efl_js_ethumb_js_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ + +tests_efl_js_eio_js_suite_SOURCES = \ +tests/efl_js/eio_js_suite.cc + +tests_efl_js_eio_js_suite_CPPFLAGS = $(SUITE_RUNNER_CPPFLAGS) +tests_efl_js_eio_js_suite_LDADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ +tests_efl_js_eio_js_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ + +tests_efl_js_benchmark_js_suite_SOURCES = \ +tests/efl_js/benchmark_js_suite.cc + +tests_efl_js_benchmark_js_suite_CPPFLAGS = $(SUITE_RUNNER_CPPFLAGS) +tests_efl_js_benchmark_js_suite_LDADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ +tests_efl_js_benchmark_js_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ +endif +endif + + +endif diff --git a/src/Makefile_Eina_Cxx.am b/src/Makefile_Eina_Cxx.am index 70ef18a7bd..e9f7c13eb9 100644 --- a/src/Makefile_Eina_Cxx.am +++ b/src/Makefile_Eina_Cxx.am @@ -14,6 +14,7 @@ bindings/eina_cxx/eina_clone_allocators.hh \ bindings/eina_cxx/eina_error.hh \ bindings/eina_cxx/eina_eo_concrete_fwd.hh \ bindings/eina_cxx/eina_fold.hh \ +bindings/eina_cxx/eina_function.hh \ bindings/eina_cxx/eina_inarray.hh \ bindings/eina_cxx/eina_inlist.hh \ bindings/eina_cxx/eina_integer_sequence.hh \ @@ -21,7 +22,9 @@ bindings/eina_cxx/eina_iterator.hh \ bindings/eina_cxx/eina_lists_auxiliary.hh \ bindings/eina_cxx/eina_list.hh \ bindings/eina_cxx/eina_log.hh \ +bindings/eina_cxx/eina_logical.hh \ bindings/eina_cxx/eina_optional.hh \ +bindings/eina_cxx/eina_pp.hh \ bindings/eina_cxx/eina_ptrarray.hh \ bindings/eina_cxx/eina_ptrlist.hh \ bindings/eina_cxx/eina_range_types.hh \ @@ -31,6 +34,7 @@ bindings/eina_cxx/eina_string_view.hh \ bindings/eina_cxx/eina_thread.hh \ bindings/eina_cxx/eina_throw.hh \ bindings/eina_cxx/eina_tuple.hh \ +bindings/eina_cxx/eina_tuple_c.hh \ bindings/eina_cxx/eina_tuple_unwrap.hh \ bindings/eina_cxx/eina_type_traits.hh \ bindings/eina_cxx/eina_value.hh diff --git a/src/Makefile_Emotion.am b/src/Makefile_Emotion.am index f16a4a4c3d..4da5224060 100644 --- a/src/Makefile_Emotion.am +++ b/src/Makefile_Emotion.am @@ -347,3 +347,14 @@ installed_emotionluadir = $(datadir)/elua/modules/emotion nodist_installed_emotionlua_DATA = $(generated_emotion_lua_all) endif + +# TODO: gives undefined reference to emotion_object_class_get() +if HAVE_JS + +generated_emotion_js_bindings = $(emotion_eolian_files:%.eo=%.eo.js.cc) + +CLEANFILES += $(generated_emotion_js_bindings) + +GENERATED_JS_BINDINGS += $(generated_emotion_js_bindings) + +endif diff --git a/src/Makefile_Eo.am b/src/Makefile_Eo.am index 57b096e795..51924feeff 100644 --- a/src/Makefile_Eo.am +++ b/src/Makefile_Eo.am @@ -197,3 +197,13 @@ endif EXTRA_DIST += tests/eo/eunit_tests.h lib/eo/eo_ptr_indirection.x + +if HAVE_JS + +generated_eo_js_bindings = $(eo_eolian_files:%.eo=%.eo.js.cc) + +CLEANFILES += $(generated_eo_js_bindings) + +GENERATED_JS_BINDINGS += $(generated_eo_js_bindings) + +endif diff --git a/src/Makefile_Eolian_Js.am b/src/Makefile_Eolian_Js.am new file mode 100644 index 0000000000..32cf893bf6 --- /dev/null +++ b/src/Makefile_Eolian_Js.am @@ -0,0 +1,123 @@ + +if HAVE_JS + +### Binary +bin_PROGRAMS += bin/eolian_js/eolian_js + +bin_eolian_js_eolian_js_SOURCES = \ + bin/eolian_js/main.cc + +bin_eolian_js_eolian_js_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-I$(top_srcdir)/src/bin/eolian_js \ +-I$(top_srcdir)/src/bindings/js/eina_js \ +-I$(top_srcdir)/src/bindings/js/eo_js \ +@EOLIAN_JS_CFLAGS@ \ +@EINA_CXX_CFLAGS@ \ +@EOLIAN_CXX_CFLAGS@ + +bin_eolian_js_eolian_js_LDADD = @USE_EO_LIBS@ @USE_EOLIAN_LIBS@ +bin_eolian_js_eolian_js_DEPENDENCIES = @USE_EO_INTERNAL_LIBS@ @USE_EOLIAN_INTERNAL_LIBS@ + +include Makefile_Eolian_Js_Helper.am + +### Unit tests + +if EFL_ENABLE_TESTS +if HAVE_NODEJS + +TESTS += tests/eolian_js/eolian_js_suite.js + +check_LTLIBRARIES += tests/eolian_js/libeolian_js_suite.la + +tests/eolian_js/eolian_js_suite.js: tests/eolian_js/eolian_js_suite_mod.node +tests/eolian_js/eolian_js_suite_mod.node: tests/eolian_js/libeolian_js_suite.la + $(AM_V_CP)$(CP) $(top_builddir)/src/tests/eolian_js/.libs/libeolian_js_suite.so $(top_builddir)/src/tests/eolian_js/eolian_js_suite_mod.node + +tests_eolian_js_libeolian_js_suite_la_SOURCES = \ +tests/eolian_js/eolian_js_suite.cc \ +tests/eolian_js/eolian_js_test_eolian_js_binding.cc \ +tests/eolian_js/eolian_js_test_constructor_method_impl.c \ +tests/eolian_js/eolian_js_test_test_object_impl.c + +tests_eolian_js_libeolian_js_suite_la_CPPFLAGS = \ +-I$(top_builddir)/src/lib/efl \ +-I$(top_srcdir)/src/bin/eolian_js \ +-I$(top_srcdir)/src/bindings/js/eina_js \ +-I$(top_srcdir)/src/bindings/js/eo_js \ +-I$(top_builddir)/src/tests/eolian_js \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eolian_js\" \ +-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)/src/tests/eolian_js\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/eolian_js\" \ +-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eolian_js\" \ +@CHECK_CFLAGS@ @EOLIAN_CXX_CFLAGS@ @EINA_JS_CFLAGS@ @EO_JS_CFLAGS@ \ +@EOLIAN_CFLAGS@ @EINA_CFLAGS@ @EO_CFLAGS@ @ECORE_CFLAGS@ @EINA_CXX_CFLAGS@ \ +@EO_JS_CFLAGS@ @EO_CXX_CFLAGS@ +tests_eolian_js_libeolian_js_suite_la_LIBADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ +tests_eolian_js_libeolian_js_suite_la_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ +tests_eolian_js_libeolian_js_suite_la_CFLAGS = $(tests_eolian_js_libeolian_js_suite_la_CXXFLAGS) +tests_eolian_js_libeolian_js_suite_la_LIBTOOLFLAGS = --tag=disable-static +tests_eolian_js_libeolian_js_suite_la_LDFLAGS = -rpath $(abs_top_builddir)/tests/eolian_js @EFL_LTLIBRARY_FLAGS@ + +# if compiler_o_lo == yes, lo, otherwise $(OBJEXT) + +tests/eolian_js/tests_eolian_js_libeolian_js_suite_la-eolian_js_test_eolian_js_binding.l$(OBJEXT): tests/eolian_js/constructor_method_class.eo.js.cc tests/eolian_js/constructor_method_class.eo.h tests/eolian_js/test_object.eo.js.cc tests/eolian_js/test_object.eo.h +tests/eolian_js/tests_eolian_js_libeolian_js_suite_la-eolian_js_test_constructor_method_impl.l$(OBJEXT): tests/eolian_js/constructor_method_class.eo.c +tests/eolian_js/tests_eolian_js_libeolian_js_suite_la-eolian_js_test_test_object_impl.l$(OBJEXT): tests/eolian_js/test_object.eo.c + +CLEANFILES += \ +tests/eolian_js/constructor_method_class.eo.js.cc \ +tests/eolian_js/constructor_method_class.eo.c \ +tests/eolian_js/constructor_method_class.eo.h \ +tests/eolian_js/test_object.eo.js.cc \ +tests/eolian_js/test_object.eo.c \ +tests/eolian_js/test_object.eo.h +else +check_PROGRAMS += tests/eolian_js/eolian_js_suite +TESTS += tests/eolian_js/eolian_js_suite + +tests_eolian_js_eolian_js_suite_SOURCES = \ +tests/eolian_js/eolian_js_suite.cc \ +tests/eolian_js/eolian_js_test_eolian_js_binding.cc \ +tests/eolian_js/eolian_js_test_constructor_method_impl.c \ +tests/eolian_js/eolian_js_test_test_object_impl.c + +tests/eolian_js/tests_eolian_js_eolian_js_suite-eolian_js_test_eolian_js_binding.$(OBJEXT): tests/eolian_js/constructor_method_class.eo.js.cc tests/eolian_js/constructor_method_class.eo.h tests/eolian_js/test_object.eo.js.cc tests/eolian_js/test_object.eo.h +tests/eolian_js/tests_eolian_js_eolian_js_suite-eolian_js_test_constructor_method_impl.$(OBJEXT): tests/eolian_js/constructor_method_class.eo.c +tests/eolian_js/tests_eolian_js_eolian_js_suite-eolian_js_test_test_object_impl.$(OBJEXT): tests/eolian_js/test_object.eo.c + +CLEANFILES += \ +tests/eolian_js/constructor_method_class.eo.js.cc \ +tests/eolian_js/constructor_method_class.eo.c \ +tests/eolian_js/constructor_method_class.eo.h \ +tests/eolian_js/test_object.eo.js.cc \ +tests/eolian_js/test_object.eo.c \ +tests/eolian_js/test_object.eo.h + +tests_eolian_js_eolian_js_suite_CPPFLAGS = \ +-I$(top_builddir)/src/lib/efl \ +-I$(top_srcdir)/src/bin/eolian_js \ +-I$(top_srcdir)/src/bindings/js/eina_js \ +-I$(top_srcdir)/src/bindings/js/eo_js \ +-I$(top_builddir)/src/tests/eolian_js \ +-I$(top_srcdir)/src/tests/efl_js \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eolian_js\" \ +-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)/src/tests/eolian_js\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/eolian_js\" \ +-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eolian_js\" \ +@CHECK_CFLAGS@ @EOLIAN_CXX_CFLAGS@ @EINA_JS_CFLAGS@ @EO_JS_CFLAGS@ @EFL_JS_CFLAGS@ \ +@EOLIAN_CFLAGS@ @EINA_CFLAGS@ @EO_CFLAGS@ @ECORE_CFLAGS@ @EINA_CXX_CFLAGS@ \ +@EO_JS_CFLAGS@ @EO_CXX_CFLAGS@ @EFL_JS_CFLAGS@ + +tests_eolian_js_eolian_js_suite_LDADD = \ +@CHECK_LIBS@ @USE_EO_LIBS@ @USE_EINA_LIBS@ @USE_EOLIAN_LIBS@ @USE_EFL_JS_LIBS@ @USE_EVAS_LIBS@ @USE_EFL_JS_LIBS@ +tests_eolian_js_eolian_js_suite_DEPENDENCIES = @USE_EOLIAN_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ @USE_EVAS_INTERNAL_LIBS@ @USE_EFL_JS_INTERNAL_LIBS@ +endif +endif + +endif + + + diff --git a/src/Makefile_Eolian_Js_Helper.am b/src/Makefile_Eolian_Js_Helper.am new file mode 100644 index 0000000000..fcc523153f --- /dev/null +++ b/src/Makefile_Eolian_Js_Helper.am @@ -0,0 +1,18 @@ +#if HAVE_EOLIAN_JS +#EOLIAN_JS = @eolian_js@ +#_EOLIAN_JS_DEP = @eolian_js@ +#else +EOLIAN_JS = EFL_RUN_IN_TREE=1 $(top_builddir)/src/bin/eolian_js/eolian_js${EXEEXT} +_EOLIAN_JS_DEP = bin/eolian_js/eolian_js${EXEEXT} +#endif + +AM_V_EOLJS = $(am__v_EOLJS_@AM_V@) +am__v_EOLJS_ = $(am__v_EOLJS_@AM_DEFAULT_V@) +am__v_EOLJS_0 = @echo " EOLJS " $@; + +SUFFIXES += .eo.js.cc + +%.eo.js.cc: %.eo $(_EOLIAN_JS_DEP) + $(AM_V_EOLJS)$(EOLIAN_JS) $(EOLIAN_FLAGS) -o $@ $< + +CLEANFILES += $(BUILT_SOURCES) diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index 3f7dd3941b..ebc5480151 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -2221,3 +2221,13 @@ $(NULL) installed_evasfiltersdir = $(datadir)/evas/filters/lua dist_installed_evasfilters_DATA = $(evas_filters_lua) + +if HAVE_JS + +generated_evas_js_bindings = $(evas_eolian_files:%.eo=%.eo.js.cc) + +CLEANFILES += $(generated_evas_js_bindings) + +GENERATED_JS_BINDINGS += $(generated_evas_js_bindings) + +endif diff --git a/src/bin/efl_js/efljslaunch b/src/bin/efl_js/efljslaunch new file mode 100755 index 0000000000..785c30e3e3 --- /dev/null +++ b/src/bin/efl_js/efljslaunch @@ -0,0 +1,139 @@ +#!/bin/sh +':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@" + +// Core node modules +var path = require('path'); +var os = require('os'); +var zlib = require('zlib'); +var child_process = require('child_process'); + +// 3rd party modules +var fs = require('fs-extra'); +var getopt = require('node-getopt'); +var tar = require('tar'); + +function make_error_cb(message) +{ + return function(e) { + console.error("Error %s: %s", message, e); + process.exit(1); + }; +} + +function remove_files(options) +{ + if (options.verbose) + console.log("Removing temporary files"); + + fs.remove(options.project_folder); +} + +function run_project(options) +{ + if (options.verbose) + console.log("Running the project"); + + var current_dir = process.cwd(); + process.chdir(options.project_root); + + var proc = child_process.fork(options.metadata.Entry); + proc.on('exit', function(code){ + if (options.verbose) + console.log('Child exited with code %s', code); + process.chdir(current_dir); + if (!options.keep) + remove_files(options); + }); + +} + +function unpack_project_data(options) +{ + if (options.verbose) + console.log("Unpacking project sources and assets"); + + var datafile = path.join(options.project_folder, "data.tar.gz"); + var project_root = path.join(options.project_folder, "root"); + + options.project_root = project_root; + + var input = fs.createReadStream(datafile); + var unzipper = zlib.createGunzip(); + var extractor = tar.Extract({path: project_root, strip: 0}); + + input.on('error', make_error_cb("reading package data file.")); + extractor.on('error', make_error_cb("unpacking package data file.")); + if (!("only-extract" in options)) + extractor.on('end', function(){ run_project(options); }); + + input.pipe(unzipper) + unzipper.pipe(extractor); +} + +function read_metadata(options) +{ + if (options.verbose) + console.log("Reading project metadata"); + + var project_folder = options.project_folder; + var metadata = JSON.parse(fs.readFileSync(path.join(project_folder, "meta.json"))); + + if (options.verbose) + console.log("Project: %s\nVersion: %s\nEntry point: %s", metadata.Name, metadata.Version, metadata.Entry); + if ("only-dump" in options) + process.exit(0); + + options.metadata = metadata; + + unpack_project_data(options); +} + +function extract(filename, options) +{ + if (options.verbose) + console.log("Extracting ", filename, "with options ", options); + + var project_id = path.basename(filename, ".epk"); + var project_folder = path.join(options['temp-dir'], project_id); + + options.project_folder = project_folder; + options.project_id = project_id; + + var input = fs.createReadStream(filename); + var extractor = tar.Extract({path: options['temp-dir'], strip: 0}); + + input.on('error', make_error_cb("reading package file.")); + extractor.on('error', make_error_cb("unpacking package file.")); + extractor.on('end', function(){ read_metadata(options); }); + + input.pipe(extractor); +} + +function main() { + var options = getopt.create([ + ['d', 'only-dump', 'Only dump information about the package'], + ['e', 'only-extract', 'Only extract the package, do not run'], + ['h', 'help', 'Display this help'], + ['k', 'keep', 'Do not remove the files after exiting'], + ['t', 'temp-dir=ARG', 'Temporary dir to extract files'], + ['v', 'verbose', 'Print information messages'], + ]).bindHelp().parseSystem(); + + var filename = options.argv[0]; + if (filename === undefined) + { + console.error("Must provide a package file."); + process.exit(1); + } + + if (!('temp-dir' in options.options)) + { + options.options["temp-dir"] = path.join(os.tmpdir(), "efljs_apps"); + if (options.verbose) + console.log("Defaulting temp dir to ", options.options["temp-dir"]); + } + + extract(filename, options.options); +} + +main(); diff --git a/src/bin/efl_js/efljslaunch.desktop b/src/bin/efl_js/efljslaunch.desktop new file mode 100644 index 0000000000..53371cba97 --- /dev/null +++ b/src/bin/efl_js/efljslaunch.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Name=EFL JS package launcher +Exec=efljslaunch %f +Type=Application +Categories=EFL +Terminal=true +MimeType=application/x-efljspackage; diff --git a/src/bin/efl_js/efljslaunch.xml b/src/bin/efl_js/efljslaunch.xml new file mode 100644 index 0000000000..b1db6841b2 --- /dev/null +++ b/src/bin/efl_js/efljslaunch.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> + <mime-type type="application/x-efljspackage"> + <comment xml:lang="en">EFL JS package</comment> + <glob pattern="*.epk"/> + </mime-type> +</mime-info>
\ No newline at end of file diff --git a/src/bin/efl_js/efljspack b/src/bin/efl_js/efljspack new file mode 100755 index 0000000000..50e27b6ac4 --- /dev/null +++ b/src/bin/efl_js/efljspack @@ -0,0 +1,251 @@ +#!/bin/sh +':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@" + +var zlib = require('zlib'); +var path = require('path'); + +// external dependencies +var fs = require('fs-extra'); +var tar = require('tar'); +var fstream = require('fstream'); +var getopt = require('node-getopt'); + +/* + * Packing a project. + * The efljs package has a similar format to debian packages. It is a + * tar package containing two files: + * + * meta.txt: Metadata information about this package. + * data.tar.gz: Gzipped data, with the project tree ready to be decompressed + * and run by the package launcher. + * + * During the build, a out/ directory is created in the project root to + * store the package and temporary files. + */ + +// Creates a stub .project file and packs it. +function pack_single(sourcepath, options) +{ + if (options.verbose) + console.log("Creating project file for single file app", sourcepath); + + var dir_name = path.dirname(fs.realpathSync(sourcepath)); + var filename = path.basename(sourcepath); + var projectRegex = /^(.*).js$/g; + var project_name = projectRegex.exec(filename)[1]; + + if (!validade_project_name(project_name)) + { + console.error("Invalid project name. Must start with a letter."); + process.exit(0); + } + + var project_filename = path.join(dir_name, project_name + ".project"); + + var fd = fs.openSync(project_filename, 'w'); + + var jsonData = {}; + + jsonData["Name"] = project_name; + jsonData["Entry"] = filename; + jsonData["Sources"] = [[filename, '.']]; + jsonData["Version"] = "0.1"; + + fs.writeSync(fd, JSON.stringify(jsonData, null, 2)); + + fs.closeSync(fd); + + pack_project(project_filename, options); + +} + +function generate_build_info(configuration, project_file, options) +{ + build_info = {}; + + // project == project_dir + // /out == build_dir + // /data == data_dir + // /name-version == package_dir + + build_info.package_id = configuration.Name + "-" + configuration.Version; + build_info.project_dir = path.dirname(project_file); + build_info.build_dir = path.join(build_info.project_dir, "out"); + build_info.data_dir = path.join(build_info.build_dir, "data"); + build_info.package_dir = path.join(build_info.build_dir, build_info.package_id); + build_info.data_file = path.join(build_info.package_dir, "data.tar.gz"); + build_info.package_file = path.join(build_info.build_dir, build_info.package_id + ".epk") + build_info.metadata_file = path.join(build_info.package_dir, "meta.json"); + + if (options.verbose) + { + console.log("Project id: ", build_info.package_id); + console.log("Project source dir: ", build_info.project_dir); + console.log("Project build dir: ", build_info.build_dir); + console.log("Project data dir:", build_info.data_dir); + console.log("Project package dir:", build_info.package_dir); + } + + return build_info; + +} + +// Project names must start with a letter and contain only +// letters, digits and underscores. +function validade_project_name(name) +{ + return (/^[a-zA-Z][\w-]*$/).test(name) +} + +function pack_project(project_file, options) +{ + if (options.verbose) + console.log("Packing project from project file ", project_file); + + var configuration = JSON.parse(fs.readFileSync(project_file)); + + if (!validade_project_name(configuration.Name)) + { + console.error("Invalid project name. Must start with a letter."); + process.exit(0); + } + + var build_info = generate_build_info(configuration, project_file, options); + + try + { + fs.mkdirSync(build_info.build_dir); + fs.mkdirSync(build_info.data_dir); + fs.mkdirSync(build_info.package_dir); + } + catch (e) + { + console.warn("Warning: Project output directories not empty."); + } + + create_metadata_file(configuration, build_info, options); + + // If not explicitly named on configuration, add the entire directory + if (!('Sources' in configuration)) + { + generate_source_list(configuration, build_info.project_dir, options); + } + + create_project_tree(configuration.Sources, build_info, options); + + pack_data_dir(build_info, options); +} + +function create_project_tree(sources, build_info, options) +{ + for (var i = sources.length - 1; i >= 0; i--) { + if (options.verbose) + console.log("Adding file ", sources[i], "to package."); + var source_file = path.join(build_info.project_dir, sources[i][0]); + var destination_dir = path.join(build_info.data_dir, sources[i][1]); + var destination_filename = path.basename(source_file); + var destination_file = path.join(destination_dir, destination_filename); + + fs.copySync(source_file, destination_file); + }; +} + +function generate_source_list(configuration, project_dir, options) +{ + console.log("Generating source list for project dir", build_info.project_dir); + var dir_entries = fs.readdirSync(project_dir); + var sources = []; + + dir_entries.forEach(function(entry){ + if (entry == "out") + return; + sources.push([entry, "."]); + }); + configuration.Sources = sources; +} + +function create_metadata_file(configuration, build_info, options) +{ + if (options.verbose) + console.log("Creating metadata file", build_info.metadata_file); + + var metadata = {}; + + metadata.Name = configuration.Name; + metadata.Entry = configuration.Entry; + metadata.Version = configuration.Version; + + var output = fs.createWriteStream(build_info.metadata_file); + output.write(JSON.stringify(metadata, null, 2)); + output.close(); +} + +function pack_data_dir(build_info, options) +{ + if (options.verbose) + console.log("Packing data..."); + + pack_directory(build_info.data_dir, build_info.data_file, true, true, function(){ + if (options.verbose) + console.log("Packed data"); + pack_final_package(build_info, options); + }); +} + +function pack_final_package(build_info, options) +{ + if (options.verbose) + console.log("Creating package ", build_info.package_file); + pack_directory(build_info.package_dir, build_info.package_file, false, false, function(){ + if (options.verbose) + console.log("Created project package."); + }); +} + +function pack_directory(source_dir, target_file, strip_base_dir, should_gzip, callback) +{ + var output = fs.createWriteStream(target_file); + var packer = tar.Pack({fromBase: strip_base_dir == true}); + if (callback != undefined) + output.on('close', callback); + + var reader = fstream.Reader({path: source_dir, type: "Directory"}); + var destStr = reader.pipe(packer); + if(should_gzip) + destStr = destStr.pipe(zlib.createGzip()); + destStr.pipe(output); +} + +function main() +{ + + var options = getopt.create([ + ['v', 'verbose', 'Explain what is being done'], + ['h', 'help', 'Display this help'] + ]).bindHelp().parseSystem(); + + filename = options.argv[0]; + + if (typeof filename === 'undefined') + { + console.error('Must provide a valid js or project file.'); + process.exit(1); + } + + if (endsWith(filename, ".js")) + { + pack_single(filename, options.options); + } + else if (endsWith(filename, ".project")) + { + pack_project(filename, options.options); + } +} + +main(); + +//// Helper functions +function endsWith(str, suffix) +{ + return str.indexOf(suffix, str.length - suffix.length) !== -1; +} diff --git a/src/bin/efl_js/launcher_main.cc b/src/bin/efl_js/launcher_main.cc new file mode 100644 index 0000000000..680f16ca52 --- /dev/null +++ b/src/bin/efl_js/launcher_main.cc @@ -0,0 +1,156 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <iostream> +#include <fstream> +#include <sstream> +#include <string> +#include <cerrno> + +#include <Eo_Js.hh> +#include <Eina.hh> +#include <Eo.hh> +// #include <efl_js.hh> + +using namespace std; +using namespace v8; + +const char PATH_SEPARATOR = +#ifdef _WIN32 + '\\'; +#else + '/'; +#endif + +static std::string get_file_contents(const char *filename) { + std::ifstream in(filename, std::ios::in); + if (in) { + std::ostringstream contents; + contents << in.rdbuf(); + in.close(); + return contents.str(); + } else { + throw(errno); + } +} + +static std::string get_filename(std::string path) +{ + int beginIdx = path.rfind(PATH_SEPARATOR); + return path.substr(beginIdx + 1); +} + +static void show_usage(std::string name) +{ + std::cerr << "Usage: " << get_filename(name) << " <option(s)> [SOURCE]\n" << std::endl + << "Options:" << std::endl + << "\t-h, --help\t\t Show this help message" << std::endl; +} + +/* + * Basic console.log implementation with space-separated values, + * no substitution + */ +void Log(const FunctionCallbackInfo<Value>& args) +{ + Isolate* isolate = Isolate::GetCurrent(); + HandleScope scope(isolate); + + for (int i=0; i < args.Length(); i++) + { + if (i != 0) + std::cout << " "; + String::Utf8Value string(args[i]); + std::cout << *string; + } + + std::cout << std::endl; + + args.GetReturnValue().Set(v8::Null(isolate)); +} + + +int main(int argc, char* argv[]) +{ + + std::string script_source; + char *filename = 0; + + for (int i=1; i < argc; i++) + { + if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "--help") == 0)) + { + show_usage(argv[0]); + return 0; + } + else + { + filename = argv[i]; + } + } + + if (!filename) + { + std::cerr << "Error: No source provided." << std::endl; + show_usage(argv[0]); + return 1; + } + + try + { + script_source = get_file_contents(filename); + } catch (int errno) + { + perror("Error: "); + return 1; + } + + + efl::eina::js::compatibility_initialize(); + v8::V8::SetFlagsFromCommandLine(&argc, const_cast<char**>(argv), true); + + v8::Isolate* isolate = efl::eina::js::compatibility_isolate_new(); + { + Isolate::Scope isolate_scope(isolate); + HandleScope handleScope(isolate); + + Local<Context> context = Context::New(isolate, NULL); + Context::Scope context_scope(context); + context->Enter(); + + // Setup the console and log + Local<Object> console = Object::New(isolate); + Local<FunctionTemplate> log = FunctionTemplate::New(isolate, Log); + console->Set(String::NewFromUtf8(isolate, "log"), log->GetFunction()); + + Local<Object> global = context->Global(); + global->Set(String::NewFromUtf8(isolate, "console"), console); + + // Set up the efl exports; Needed to enter the context before this + // due to creating Objects instead of Objects Templates + // WIP: Commented out due to potential missing v8 platform implementation issues + // Local<Object> efl_exports = Object::New(isolate); + // global->Set(String::NewFromUtf8(isolate, "efl"), efl_exports); + // efl_js::init(efl_exports); + + // And now the user's script + Local<String> source = String::NewFromUtf8(isolate, script_source.c_str()); + + Local<Script> script = Script::Compile(source); + + TryCatch tryCatch(isolate); + Local<Value> result = script->Run(); + + if (result.IsEmpty()) + { + Local<Value> exception = tryCatch.Exception(); + String::Utf8Value exception_str(exception); + printf("Exception: %s\n", *exception_str); + } + + } + + V8::Dispose(); + return 0; +} diff --git a/src/bin/eolian_js/.gitignore b/src/bin/eolian_js/.gitignore new file mode 100644 index 0000000000..631f68aa1f --- /dev/null +++ b/src/bin/eolian_js/.gitignore @@ -0,0 +1 @@ +/eolian_js diff --git a/src/bin/eolian_js/eolian/class.hh b/src/bin/eolian_js/eolian/class.hh new file mode 100644 index 0000000000..bd04d5fedd --- /dev/null +++ b/src/bin/eolian_js/eolian/class.hh @@ -0,0 +1,139 @@ +#ifndef EOLIAN_KLASS_HH +#define EOLIAN_KLASS_HH + +#include <Eina.hh> + +#include <eolian/js/domain.hh> + +#include <ostream> + +inline std::string name(Eolian_Class const* klass) +{ + return ::eolian_class_name_get(klass); +} + +inline std::string full_name(Eolian_Class const* klass) +{ + return ::eolian_class_full_name_get(klass); +} + +inline std::string full_name_transformed(Eolian_Class const* klass) +{ + auto r = full_name(klass); + std::replace(r.begin(), r.end(), '.', '_'); + return r; +} + +inline std::size_t namespace_size(Eolian_Class const* klass) +{ + std::size_t size = 0; + for(efl::eina::iterator<const char> first (::eolian_class_namespaces_get(klass)) + , last; first != last; ++first) + ++size; + return size; +} + +inline std::string type_class_name(Eolian_Type const* tp) +{ + if (tp) + { + Eolian_Type_Type tpt = ::eolian_type_type_get(tp); + if (tpt == EOLIAN_TYPE_POINTER || tpt == EOLIAN_TYPE_ALIAS || tpt == EOLIAN_TYPE_REGULAR) + { + return type_class_name(::eolian_type_base_type_get(tp)); + } + else if(tpt == EOLIAN_TYPE_CLASS) + { + Eolian_Class const* klass = ::eolian_type_class_get(tp); + if (klass) + { + Eina_Stringshare* klass_name = ::eolian_class_full_name_get(klass); + if (!klass_name) + throw std::runtime_error("Could not get Eo class name"); + + return klass_name; + } // TODO: else should throw std::runtime_error("Could not get Eo class"); + } + else if(tpt == EOLIAN_TYPE_STRUCT) + { + auto struct_type_full_name = ::eolian_type_full_name_get(tp); + if (!struct_type_full_name) + throw std::runtime_error("Could not get struct name"); + return struct_type_full_name; + } + } + return ""; +} + +inline void print_lower_case_namespace(Eolian_Class const* klass, std::ostream& os) +{ + std::vector<std::string> namespace_; + for(efl::eina::iterator<const char> first (::eolian_class_namespaces_get(klass)) + , last; first != last; ++first) + namespace_.push_back(&*first); + for(auto first = namespace_.begin(), last = namespace_.end() + ; first != last; ++first) + { + std::string lower(*first); + std::transform(lower.begin(), lower.end(), lower.begin(), tolower); + os << lower; + if(std::next(first) != last) os << "::"; + } +} + +inline void print_eo_class(Eolian_Class const* klass, std::ostream& os) +{ + assert(klass != 0); + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "print_eo_class"; + + auto toupper = [] (unsigned char c) { return std::toupper(c); }; + + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "print_eo_class"; + std::vector<std::string> namespace_; + for(efl::eina::iterator<const char> first (::eolian_class_namespaces_get(klass)) + , last; first != last; ++first) + namespace_.push_back(&*first); + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "namespace"; + namespace_.push_back(name(klass)); + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "class"; + switch(eolian_class_type_get(klass)) + { + case EOLIAN_CLASS_REGULAR: + case EOLIAN_CLASS_ABSTRACT: + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << ""; + namespace_.push_back("CLASS"); + break; + case EOLIAN_CLASS_INTERFACE: + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << ""; + namespace_.push_back("INTERFACE"); + break; + case EOLIAN_CLASS_MIXIN: + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << ""; + namespace_.push_back("MIXIN"); + break; + default: + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "default ?"; + std::abort(); + } + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << ""; + for(auto first = namespace_.begin(), last = namespace_.end() + ; first != last; ++first) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << ""; + std::string upper(*first); + std::transform(upper.begin(), upper.end(), upper.begin(), toupper); + os << upper; + if(std::next(first) != last) os << "_"; + } + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << ""; +} + +inline bool is_evas(Eolian_Class const* klass) +{ + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "is_evas"; + efl::eina::iterator<const char> first (::eolian_class_namespaces_get(klass)); + return first != efl::eina::iterator<const char>() + && std::strcmp(&*first, "Evas") == 0; +} + +#endif diff --git a/src/bin/eolian_js/eolian/js/domain.hh b/src/bin/eolian_js/eolian/js/domain.hh new file mode 100644 index 0000000000..38cf542873 --- /dev/null +++ b/src/bin/eolian_js/eolian/js/domain.hh @@ -0,0 +1,8 @@ + +#include <Eina.hh> + +namespace eolian { namespace js { + +extern efl::eina::log_domain domain; + +} } diff --git a/src/bin/eolian_js/eolian/js/format.hh b/src/bin/eolian_js/eolian/js/format.hh new file mode 100644 index 0000000000..a07d541e14 --- /dev/null +++ b/src/bin/eolian_js/eolian/js/format.hh @@ -0,0 +1,44 @@ +#ifndef EOLIAN_JS_FORMAT_HH +#define EOLIAN_JS_FORMAT_HH + +#include <eolian/js/domain.hh> + +#include <algorithm> +#include <string> +#include <cctype> + +namespace eolian { namespace js { + +namespace format { + +std::string generic(std::string const& in) +{ + std::string s = in; + auto i = s.find('_'); + while (i != std::string::npos) + { + if (i <= 0 || i+1 >= s.size() || + !::isalnum(s[i-1]) || !::isalnum(s[i+1])) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "Entity '" << in + << "' can't be conveniently converted to a JavaScript name."; + return in; + } + s[i+1] = static_cast<char>(::toupper(s[i+1])); + s.erase(i, 1); + i = s.find('_', i); + } + return s; +} + +std::string constant(std::string in) +{ + std::transform(in.begin(), in.end(), in.begin(), ::toupper); + return in; +} + +} + +} } + +#endif diff --git a/src/bin/eolian_js/main.cc b/src/bin/eolian_js/main.cc new file mode 100644 index 0000000000..bc575fdf8e --- /dev/null +++ b/src/bin/eolian_js/main.cc @@ -0,0 +1,1090 @@ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Eolian.h> +#include <Eina.hh> + +#include <eolian/js/domain.hh> +#include <eolian/js/format.hh> +#include <eolian/class.hh> + +#include <iostream> +#include <fstream> +#include <unordered_map> +#include <sstream> +#include <stdexcept> + +#include <libgen.h> +#include <getopt.h> +#include <cstdlib> +#include <vector> +#include <set> + +namespace eolian { namespace js { + +efl::eina::log_domain domain("eolian_js"); + +struct incomplete_complex_type_error : public std::exception +{ + explicit incomplete_complex_type_error(std::string const& msg_arg) + : msg(msg_arg) + {} + virtual ~incomplete_complex_type_error() {} + virtual const char* what() const noexcept { return msg.c_str(); } + + std::string msg; +}; + +} } + + +std::string +_lowercase(std::string str) +{ + transform(begin(str), end(str), begin(str), tolower); + return str; +} + +std::string +_uppercase(std::string str) +{ + transform(begin(str), end(str), begin(str), toupper); + return str; +} + +std::string +_class_name_getter(std::string const& caller_class_prefix, std::string class_name) +{ + std::replace(class_name.begin(), class_name.end(), '.', '_'); + return caller_class_prefix + "_" + class_name + "_cls_name_getter"; +} + +void +_final_type_and_type_type_get(Eolian_Type const* tp_in, Eolian_Type const*& tp_out, Eolian_Type_Type& tpt_out) +{ + tp_out = tp_in; + tpt_out = eolian_type_type_get(tp_in); + while ((tpt_out == EOLIAN_TYPE_REGULAR || tpt_out == EOLIAN_TYPE_ALIAS) && !eolian_type_is_extern(tp_out)) + { + auto t = eolian_type_base_type_get(tp_out); + // TODO: shouldn't __undefined_type be flagged as external??? + if (!t || !eolian_type_full_name_get(t) || strcmp(eolian_type_full_name_get(t), "__undefined_type") == 0) break; + tp_out = t; + tpt_out = eolian_type_type_get(t); + } +} + +std::string +_eolian_type_cpp_type_named_get(const Eolian_Type *tp, std::string const& caller_class_prefix, std::set<std::string>& need_name_getter) +{ + const auto is_const = eolian_type_is_const(tp); + + Eolian_Type_Type tpt = EOLIAN_TYPE_UNKNOWN_TYPE; + _final_type_and_type_type_get(tp, tp, tpt); + + if (tpt == EOLIAN_TYPE_UNKNOWN_TYPE) + return "error"; + + std::string result; + + if ((tpt == EOLIAN_TYPE_VOID + || tpt == EOLIAN_TYPE_REGULAR + || tpt == EOLIAN_TYPE_COMPLEX + || tpt == EOLIAN_TYPE_STRUCT + || tpt == EOLIAN_TYPE_STRUCT_OPAQUE + || tpt == EOLIAN_TYPE_ENUM + || tpt == EOLIAN_TYPE_ALIAS + || tpt == EOLIAN_TYPE_CLASS) + && is_const) + { + result += "const "; + } + + + if (tpt == EOLIAN_TYPE_REGULAR + || tpt == EOLIAN_TYPE_COMPLEX + || tpt == EOLIAN_TYPE_STRUCT + || tpt == EOLIAN_TYPE_STRUCT_OPAQUE + || tpt == EOLIAN_TYPE_ENUM + || tpt == EOLIAN_TYPE_ALIAS + || tpt == EOLIAN_TYPE_CLASS) + { + for (efl::eina::iterator<const char> first(::eolian_type_namespaces_get(tp)), last; first != last; ++first) + { + std::string np(&*first); + result += np + "_"; // TODO: transform it to the C++ equivalent? + } + + // this comes from ctypes at eo_lexer.c and KEYWORDS at eo_lexer.h + const static std::unordered_map<std::string, std::string> type_map = { + {"byte", "signed char"}, + {"ubyte", "unsigned char"}, + {"char", "char"}, + {"short", "short"}, + {"ushort", "unsigned short"}, + {"int", "int"}, + {"uint", "unsigned int"}, + {"long", "long"}, + {"ulong", "unsigned long"}, + {"llong", "long long"}, + {"ullong", "unsigned long long"}, + {"int8", "int8_t"}, + {"uint8", "uint8_t"}, + {"int16", "int16_t"}, + {"uint16", "uint16_t"}, + {"int32", "int32_t"}, + {"uint32", "uint32_t"}, + {"int64", "int64_t"}, + {"uint64", "uint64_t"}, + {"int128", "int128_t"}, + {"uint128", "uint128_t"}, + {"size", "size_t"}, + {"ssize", "ssize_t"}, + {"intptr", "intptr_t"}, + {"uintptr", "uintptr_t"}, + {"ptrdiff", "ptrdiff_t"}, + {"time", "time_t"}, + {"float", "float"}, + {"double", "double"}, + {"bool", "Eina_Bool"}, + {"void", "void"}, + {"generic_value", "Eina_Value"}, + {"accessor", "Eina_Accessor"}, + {"array", "Eina_Array"}, + {"iterator", "Eina_Iterator"}, + {"hash", "Eina_Hash"}, + {"list", "Eina_List"} + }; + + std::string type_name = eolian_type_name_get(tp); + auto it = type_map.find(type_name); + if (it != end(type_map)) + type_name = it->second; + result += type_name; + + if (tpt == EOLIAN_TYPE_STRUCT) + { + result = "efl::eina::js::make_struct_tag<" + result + ">"; + } + } + else if (tpt == EOLIAN_TYPE_VOID) + result += "void"; + else // tpt == EOLIAN_TYPE_POINTER + { + auto btp = eolian_type_base_type_get(tp); + result += _eolian_type_cpp_type_named_get(btp, caller_class_prefix, need_name_getter); + + const auto base_is_const = eolian_type_is_const(btp); + + Eolian_Type_Type btpt = EOLIAN_TYPE_UNKNOWN_TYPE; + _final_type_and_type_type_get(btp, btp, btpt); + + if (btpt == EOLIAN_TYPE_STRUCT) + { + std::string f = "::make_struct_tag"; + auto p = result.find(f); + if (p == std::string::npos) + throw std::runtime_error("missing struct type tag"); + result.replace(p, f.size(), "::make_struct_ptr_tag"); + result.pop_back(); + result += " *"; + if (is_const) result += " const"; + result += ">"; + } + else + { + if (btpt != EOLIAN_TYPE_POINTER || base_is_const) + result += ' '; + result += '*'; + if (is_const) result += " const"; + } + + if (btpt == EOLIAN_TYPE_COMPLEX) + { + result = "efl::eina::js::make_complex_tag<" + result; + + bool has_subtypes = false; + auto subtypes = eolian_type_subtypes_get(btp); + const Eolian_Type *subtype; + EINA_ITERATOR_FOREACH(subtypes, subtype) + { + auto t = _eolian_type_cpp_type_named_get(subtype, caller_class_prefix, need_name_getter); + auto k = type_class_name(subtype); + if (!k.empty()) + { + result += ", " + t + ", " + _class_name_getter(caller_class_prefix, k); + need_name_getter.insert(k); + } + else + { + result += ", " + t + ", ::efl::eina::js::nonclass_cls_name_getter"; + } + has_subtypes = true; + } + + if (!has_subtypes) + throw eolian::js::incomplete_complex_type_error("Incomplete complex type"); + + result += ">"; + } + } + + /*if (!name.empty()) + { + if (tpt != EOLIAN_TYPE_POINTER) + result += ' '; + result += name; + }*/ + + return result; +} + +using ParametersIterator = efl::eina::iterator<const ::Eolian_Function_Parameter>; + +std::vector<const ::Eolian_Function_Parameter*> +_eolian_function_keys_get(const Eolian_Function *function_id, Eolian_Function_Type ftype) +{ + std::vector<const ::Eolian_Function_Parameter*> keys; + + for(ParametersIterator it(::eolian_property_keys_get(function_id, ftype)), last; it != last; ++it) + keys.push_back(&*it); + + return keys; +} + +std::vector<const ::Eolian_Function_Parameter*> +_eolian_function_parameters_get(const Eolian_Function *function_id, Eolian_Function_Type function_type) +{ + std::vector<const ::Eolian_Function_Parameter*> parameters; + + ParametersIterator it { (function_type == EOLIAN_METHOD) ? + ::eolian_function_parameters_get(function_id) : + ::eolian_property_values_get(function_id, function_type) + }, last; + + for(; it != last; ++it) + parameters.push_back(&*it); + + return parameters; +} + +bool +_function_return_is_missing(Eolian_Function const* func, Eolian_Function_Type func_type) +{ + // XXX This function shouldn't exist. Eolian should + // forge functions a priori. Bindings generators + // shouldn't be required to convert such thing. + Eolian_Type const* type = + ::eolian_function_return_type_get(func, func_type); + return !type; +} + +void separate_functions(Eolian_Class const* klass, Eolian_Function_Type t, bool ignore_constructors, + std::vector<Eolian_Function const*>& constructor_functions, + std::vector<Eolian_Function const*>& normal_functions) +{ + efl::eina::iterator<Eolian_Function> first ( ::eolian_class_functions_get(klass, t) ) + , last; + for(; first != last; ++first) + { + Eolian_Function const* function = &*first; + if(eolian_function_scope_get(function) == EOLIAN_SCOPE_PUBLIC) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << ::eolian_function_full_c_name_get(function, t, EINA_FALSE); + if(strcmp("elm_obj_entry_input_panel_imdata_get", ::eolian_function_full_c_name_get(function, t, EINA_FALSE)) != 0 && + !eolian_function_is_beta(function) && + // strcmp("data_callback", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("property", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("part_text_anchor_geometry_get", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("children_iterator_new", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("inputs_get", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("constructor", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("render_updates", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("render2_updates", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("event_callback_priority_add", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("event_callback_array_priority_add", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("event_callback_array_del", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("event_callback_call", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("event_callback_forwarder_add", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("event_callback_forwarder_del", ::eolian_function_name_get(function)) != 0 && // TODO: remove this + strcmp("event_callback_del", ::eolian_function_name_get(function)) != 0) + { + if( ::eolian_function_is_constructor(function, klass)) + { + if(!ignore_constructors) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "is a constructor"; + constructor_functions.push_back(function); + } + else + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "ignoring parent's constructors"; + } + } + else /*if( std::strcmp( ::eolian_function_full_c_name_get(function, t, EINA_FALSE) + , "eo_parent") != 0)*/ + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "is a NOT constructor " + << ::eolian_function_full_c_name_get(function, t, EINA_FALSE); + normal_functions.push_back(function); + } + // else + // { + // EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "parent_set as first constructor"; + // constructor_functions.insert(constructor_functions.begin(), function); + // normal_functions.push_back(function); + // } + } + } + } +} + +int main(int argc, char** argv) +{ + namespace format = eolian::js::format; + + std::vector<std::string> include_paths; + std::string out_file, in_file; + + efl::eina::eina_init eina_init; + struct eolian_init + { + eolian_init() { ::eolian_init(); } + ~eolian_init() { ::eolian_shutdown(); } + } eolian_init; + + const struct option long_options[] = + { + { "in", required_argument, 0, 'I' }, + { "out-file", required_argument, 0, 'o' }, + { "version", no_argument, 0, 'v' }, + { "help", no_argument, 0, 'h' }, + { 0, 0, 0, 0 } + }; + const char* options = "I:D:o:c:arvh"; + + // get command line options + int c, idx; + while ( (c = getopt_long(argc, argv, options, long_options, &idx)) != -1) + { + if (c == 'I') + { + include_paths.push_back(optarg); + } + else if (c == 'o') + { + if(!out_file.empty()) + { + // _usage(argv[0]); + return 1; + } + out_file = optarg; + } + else if (c == 'h') + { + // _usage(argv[0]); + return 1; + } + else if (c == 'v') + { + // _print_version(); + // if (argc == 2) exit(EXIT_SUCCESS); + } + } + + if (optind == argc-1) + { + in_file = argv[optind]; + } + + // Add include paths to eolian library + for(auto src : include_paths) + if (!::eolian_directory_scan(src.c_str())) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) + << "Couldn't load eolian from '" << src << "'."; + } + if (!::eolian_all_eot_files_parse()) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) + << "Eolian failed parsing eot files"; + assert(false && "Error parsing eot files"); + } + if (!::eolian_file_parse(in_file.c_str())) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) + << "Failed parsing: " << in_file << "."; + assert(false && "Error parsing input file"); + } + + // Create filename path for output + std::string file_basename; + const Eolian_Class *klass = NULL; + { + char* dup = strdup(in_file.c_str()); + char *bn = basename(dup); + klass = ::eolian_class_get_by_file(bn); + file_basename = bn; + free(dup); + } + if(!klass) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "could not find any class defined in this eo file"; + return -1; + } + + std::vector<Eolian_Function const*> constructor_functions; + std::vector<Eolian_Function const*> normal_functions; + + std::set<Eolian_Class const*> classes; + + // separate normal functions from constructors for all methods and properties + separate_functions(klass, EOLIAN_METHOD, false, constructor_functions, normal_functions); + separate_functions(klass, EOLIAN_PROPERTY, false, constructor_functions, normal_functions); + + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "functions were separated"; + + // function to iterate through all inheritance class + std::function<void(Eolian_Class const*, std::function<void(Eolian_Class const*)>)> + recurse_inherits + = [&] (Eolian_Class const* klass, std::function<void(Eolian_Class const*)> function) + { + for(efl::eina::iterator<const char> first ( ::eolian_class_inherits_get(klass)) + , last; first != last; ++first) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << &*first << std::endl; + Eolian_Class const* base = ::eolian_class_get_by_name(&*first); + function(base); + recurse_inherits(base, function); + } + }; + + // save functions from all inhehritance + auto save_functions = [&](Eolian_Class const* klass) + { + if(classes.find(klass) == classes.end()) + { + classes.insert(klass); + separate_functions(klass, EOLIAN_METHOD, true, constructor_functions, normal_functions); + separate_functions(klass, EOLIAN_PROPERTY, true, constructor_functions, normal_functions); + } + }; + // save functions from all inheritance class without constructors + recurse_inherits(klass, save_functions); + + EINA_CXX_DOM_LOG_DBG(eolian::js::domain) << "inherits were recursed"; + + std::ofstream os (out_file.c_str()); + if(!os.is_open()) + { + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "Couldn't open output file " << out_file; + return -1; + } + + EINA_CXX_DOM_LOG_DBG(eolian::js::domain) << "output was opened"; + + std::string class_name(name(klass)), + class_full_name(full_name(klass)), + upper_case_class_name(_uppercase(class_name)), + lower_case_class_name(_lowercase(class_name)); + + // Start preamble generation + if (getenv("EFL_RUN_IN_TREE")) + { + os << "#ifdef HAVE_CONFIG_H\n"; + os << "#include \"config.h\"\n"; + os << "#endif\n"; + + os << "#include <Efl.h>\n"; + os << "#include <Ecore.h>\n"; + os << "#include <Eo.h>\n\n"; + } + else + { + os << "#ifdef HAVE_CONFIG_H\n"; + os << "#include \"elementary_config.h\"\n"; + os << "#endif\n"; + + os << "#include <Efl.h>\n"; + os << "#include <Ecore.h>\n"; + os << "#include <Eo.h>\n"; + os << "#include <Evas.h>\n"; + os << "#include <Edje.h>\n"; + + os << "#include <Elementary.h>\n\n"; + os << "extern \"C\" {\n"; + os << "#include <elm_widget.h>\n"; + os << "}\n\n"; + } + os << "#include <Eina_Js.hh>\n\n"; + os << "#include <Eo_Js.hh>\n\n"; + os << "#ifdef EAPI\n"; + os << "# undef EAPI\n"; + os << "#endif\n"; + + os << "#ifdef _WIN32\n"; + os << "# define EAPI __declspec(dllimport)\n"; + os << "#else\n"; + os << "# ifdef __GNUC__\n"; + os << "# if __GNUC__ >= 4\n"; + os << "# define EAPI __attribute__ ((visibility(\"default\")))\n"; + os << "# else\n"; + os << "# define EAPI\n"; + os << "# endif\n"; + os << "# else\n"; + os << "# define EAPI\n"; + os << "# endif\n"; + os << "#endif /* ! _WIN32 */\n\n"; + os << "extern \"C\" {\n"; + + // generate include for necessary headers + if(is_evas(klass)) + os << "#include <Evas.h>\n"; + + auto includes_fun = [&os] (Eolian_Class const* klass) + { + os << "#include <" << eolian_class_file_get(klass) << ".h>\n\n"; + }; + // generate include for all inheritance + recurse_inherits(klass, includes_fun); + os << "#include <" << eolian_class_file_get(klass) << ".h>\n\n"; + + os << "}\n\n"; + + os << "#ifdef _WIN32\n"; + os << "# undef EAPI\n"; + os << "# define EAPI __declspec(dllexport)\n"; + os << "#endif /* ! _WIN32 */\n\n"; + + os << "#include <array>\n\n"; + + EINA_CXX_DOM_LOG_DBG(eolian::js::domain) << "includes added"; + + // generate open namespaces + if(namespace_size(klass)) + { + std::string space = ""; + for(efl::eina::iterator<const char> first(::eolian_class_namespaces_get(klass)), last; first != last; ++first) + { + std::string lower(_lowercase(&*first)); + os << "namespace " << lower << " {" << space; + space = " "; + } + + os << "\n"; + } + + // generate event map + std::string event_map = class_name; + event_map += "_ev_info_map"; + + os << "namespace {\n"; + os << "::efl::eo::js::event_information_map " << event_map << ";\n"; + os << "}\n"; + + EINA_CXX_DOM_LOG_DBG(eolian::js::domain) << "namespace"; + + // save functions that need a name getter for structs + std::set<std::string> need_name_getter; + + // generate all structs parsed in this file + std::stringstream structs_ss; + for (efl::eina::iterator<Eolian_Type> first(::eolian_type_structs_get_by_file(file_basename.c_str())) + , last; first != last; ++first) + { + std::stringstream ss; + auto tp = &*first; + if (::eolian_type_type_get(tp) == EOLIAN_TYPE_STRUCT_OPAQUE) + continue; + + auto struct_name = ::eolian_type_name_get(tp); + auto struct_type_full_name = ::eolian_type_full_name_get(tp); + if (!struct_name || !struct_type_full_name) + { + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "Could not get struct type name"; + continue; + } + else if(strcmp(struct_type_full_name, "Eo.Callback_Array_Item") == 0) + continue; + std::string struct_c_name = struct_type_full_name; + std::replace(struct_c_name.begin(), struct_c_name.end(), '.', '_'); + ss << " {\n"; + ss << " auto fields_func = [](v8::Isolate* isolate_, v8::Local<v8::ObjectTemplate> prototype_)\n"; + ss << " {\n"; + for (efl::eina::iterator<Eolian_Struct_Type_Field> sf(::eolian_type_struct_fields_get(tp)) + , sf_end; sf != sf_end; ++sf) + { + auto field_type = ::eolian_type_struct_field_type_get(&*sf); + auto field_name = ::eolian_type_struct_field_name_get(&*sf); + if (!field_name) + { + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "Could not get struct field name"; + continue; + } + std::string field_type_tag_name; + try + { + field_type_tag_name = _eolian_type_cpp_type_named_get(field_type, class_name, need_name_getter); + } + catch(eolian::js::incomplete_complex_type_error const& e) + { + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "Exception while generating '" << field_name << "' fielf of '" << struct_type_full_name << "' struct: " << e.what(); + continue; + } + std::string member_ref = struct_c_name; + member_ref += "::"; + member_ref += field_name; + + auto k = type_class_name(field_type); + if (!k.empty()) + { + need_name_getter.insert(k); + k = _class_name_getter(class_name, k); + } + else + { + k = "::efl::eina::js::nonclass_cls_name_getter"; + } + ss << " prototype_->SetAccessor(::efl::eina::js::compatibility_new<v8::String>(isolate_, \"" << format::generic(field_name) << "\"),\n"; + ss << " static_cast<v8::AccessorGetterCallback>(&::efl::eo::js::get_struct_member<" << struct_c_name << ", decltype(" << member_ref << "), &" << member_ref << ", " << k << ">),\n"; + ss << " static_cast<v8::AccessorSetterCallback>(&::efl::eo::js::set_struct_member<" << struct_c_name << ", " << field_type_tag_name << ", decltype(" << member_ref << "), &" << member_ref << ", " << k << ">));\n"; + } + ss << " };\n"; + ss << " auto to_export = ::efl::eo::js::get_namespace({"; + bool comma = false; + for (efl::eina::iterator<const char> ns_it(::eolian_type_namespaces_get(tp)), ns_end; ns_it != ns_end; ++ns_it) + { + if (comma) + ss << ", "; + comma = true; + ss << '"' << format::generic(&*ns_it) << '"'; + } + ss << "}, isolate, global);\n"; + ss << " ::efl::eo::js::register_struct<" << struct_c_name << ">(isolate, \"" + << format::generic(struct_name) << "\", \"" << struct_type_full_name << "\", to_export, fields_func);\n"; + ss << " }\n"; + + structs_ss << ss.str(); + } + + // generate register function for V8 + std::stringstream register_from_constructor_begin_ss; + register_from_constructor_begin_ss + << "EAPI v8::Local<v8::ObjectTemplate>\n" + << "register_" << lower_case_class_name << "_from_constructor\n" + << "(v8::Isolate* isolate, v8::Handle<v8::FunctionTemplate> constructor, ::efl::eina::js::global_ref<v8::Function>* constructor_from_eo)\n" + << "{\n" + << " v8::Local<v8::ObjectTemplate> instance = constructor->InstanceTemplate();\n" + << " instance->SetInternalFieldCount(1);\n" + << " v8::Handle<v8::ObjectTemplate> prototype = constructor->PrototypeTemplate();\n"; + + std::stringstream functions_ss; + std::set<std::string> member_names; + std::set<std::string> event_member_names; + for(auto function : normal_functions) + { + std::vector<Eolian_Function_Type> function_types; + switch (eolian_function_type_get(function)) + { + case EOLIAN_METHOD: + function_types = {EOLIAN_METHOD}; + break; + case EOLIAN_PROPERTY: + function_types = {EOLIAN_PROP_GET, EOLIAN_PROP_SET}; + break; + case EOLIAN_PROP_GET: + function_types = {EOLIAN_PROP_GET}; + break; + case EOLIAN_PROP_SET: + function_types = {EOLIAN_PROP_SET}; + break; + default: + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "Unresolved function type"; + continue; + } + + // generate function registration + for (const auto function_type : function_types) + { + try + { + std::string member_name; + switch (function_type) + { + case EOLIAN_METHOD: + member_name = eolian_function_name_get(function); + break; + case EOLIAN_PROP_SET: + member_name = std::string("set_") + eolian_function_name_get(function); + break; + case EOLIAN_PROP_GET: + member_name = std::string("get_") + eolian_function_name_get(function); + break; + case EOLIAN_PROPERTY: + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "EOLIAN_PROPERTY function type is invalid at this point"; + return -1; + case EOLIAN_UNRESOLVED: + default: + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "Unresolved function type"; + return -1; + } + + if(member_names.find(member_name) == member_names.end()) + { + member_names.insert(member_name); + std::stringstream ss; + auto output_begin = [&] (std::string name) + { + if(! ::eolian_function_is_constructor(function, klass)) + ss << " prototype->Set( ::efl::eina::js::compatibility_new<v8::String>(isolate, \"" + << format::generic(name) << "\")\n" + << " , ::efl::eina::js::compatibility_new<v8::FunctionTemplate>(isolate, &efl::eo::js::call_function\n" + << " , efl::eo::js::call_function_data<\n" + << " ::efl::eina::_mpl::tuple_c<std::size_t"; + }; + + output_begin(member_name); + + const auto key_params = _eolian_function_keys_get(function, function_type); + const auto parameters = _eolian_function_parameters_get(function, function_type); + + std::vector<const ::Eolian_Function_Parameter*> full_params; + full_params.insert(end(full_params), begin(key_params), end(key_params)); + // only one property_get parameter is translated as the function return in C + const auto param_as_return = (EOLIAN_PROP_GET == function_type) && (parameters.size() == 1) + && _function_return_is_missing(function, function_type); + if (!param_as_return) + full_params.insert(end(full_params), begin(parameters), end(parameters)); + + // call_function_data Ins + std::size_t i = 0; + for (auto parameter : full_params) + { + if (EOLIAN_PROP_SET == function_type) + ss << ", " << i; + else + if (EOLIAN_METHOD == function_type) + { + switch (eolian_parameter_direction_get(parameter)) + { + case EOLIAN_IN_PARAM: + case EOLIAN_INOUT_PARAM: + ss << ", " << i; + default: break; + } + } + ++i; + } + + // call_function_data Outs + ss << ">\n , ::efl::eina::_mpl::tuple_c<std::size_t"; + auto key_count = key_params.size(); + i = 0; + for (auto parameter : full_params) + { + // ignore keys + if (key_count > 0) + { + --key_count; + ++i; + continue; + } + + // properties doesn't support in/out/inout + if (EOLIAN_PROP_GET == function_type) + ss << ", " << i; + else + if (EOLIAN_METHOD == function_type) + { + switch (eolian_parameter_direction_get(parameter)) + { + case EOLIAN_OUT_PARAM: + case EOLIAN_INOUT_PARAM: + ss << ", " << i; + default: break; + } + } + ++i; + } + + // call_function_data Ownership + ss << ">\n , std::tuple<\n"; + auto sep = ""; + for (auto parameter : full_params) + { + auto type = eolian_parameter_type_get(parameter); + if(eolian_type_is_own(type)) + ss << sep << " ::std::true_type"; + else + ss << sep << " ::std::false_type"; + sep = ",\n"; + } + + + // call_function_data Return + ss << ">\n , "; + + const Eolian_Type *return_type = nullptr; + if (param_as_return) + { + return_type = eolian_parameter_type_get(parameters[0]); + } + else + { + return_type = ::eolian_function_return_type_get(function, function_type); + } + std::string param = "void"; + if (nullptr != return_type) + { + param = _eolian_type_cpp_type_named_get(return_type, class_name, need_name_getter); + } + ss << param; + + + // call_function_data Parameters + ss << "\n , std::tuple<\n"; + sep = " "; + key_count = key_params.size(); + for (auto parameter : full_params) + { + // TODO: REVIEW ALL THIS TOO!!! + auto type = eolian_parameter_type_get(parameter); + auto param = _eolian_type_cpp_type_named_get(type, class_name, need_name_getter); + + if (!key_count && EOLIAN_PROP_GET == function_type) + param += "*"; + else + { + switch(eolian_parameter_direction_get(parameter)) + { + case EOLIAN_OUT_PARAM: + case EOLIAN_INOUT_PARAM: + param += "*"; + default: break; + } + } + + ss << sep << param; + sep = ",\n "; + + if (key_count > 0) --key_count; + } + + + std::string param_class_names; + for (auto parameter : full_params) + { + param_class_names += '"' + type_class_name(::eolian_parameter_type_get(parameter)) + "\", "; + } + param_class_names += '"' + type_class_name(return_type) + '"'; + + std::string param_class_names_array = "std::array<const char*, "; + param_class_names_array += std::to_string(full_params.size() + 1); + param_class_names_array += ">{{" + param_class_names + "}}"; + + auto output_end = [&] (std::string const& name) + { + ss << "> >(isolate, " << param_class_names_array << ", & ::" << name << ")));\n"; + }; + switch (function_type) + { + case EOLIAN_METHOD: + output_end(eolian_function_full_c_name_get(function, function_type, EINA_FALSE)); + break; + case EOLIAN_PROP_SET: + output_end(eolian_function_full_c_name_get(function, function_type, EINA_FALSE) /*+ std::string("_set")*/); + break; + case EOLIAN_PROP_GET: + output_end(eolian_function_full_c_name_get(function, function_type, EINA_FALSE) /*+ std::string("_get")*/); + break; + case EOLIAN_PROPERTY: + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "EOLIAN_PROPERTY function type is invalid at this point"; + return -1; + case EOLIAN_UNRESOLVED: + default: + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "Unresolved function type"; + return -1; + } + + // Write function to functions stream + functions_ss << ss.str(); + } + } + catch(eolian::js::incomplete_complex_type_error const& e) + { + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "Exception while generating '" << eolian_function_name_get(function) << "': " << e.what(); + } + } + } + + // generate all events + std::stringstream events_ss; + auto generate_events = [&] (Eolian_Class const* klass) + { + std::stringstream ss; + for(efl::eina::iterator< ::Eolian_Event> first ( ::eolian_class_events_get(klass)) + , last; first != last; ++first) + { + std::string event_name (::eolian_event_name_get(&*first)); + std::replace(event_name.begin(), event_name.end(), ',', '_'); + + if (!eolian_event_is_beta(&*first) && + event_member_names.find(event_name) == event_member_names.end()) + { + auto tp = eolian_event_type_get(&*first); + ss << " {\n"; + ss << " static efl::eo::js::event_information ev_info{&constructor_from_eo, " << eolian_event_c_name_get(&*first); + ss << ", &efl::eo::js::event_callback<"; + ss << (tp ? _eolian_type_cpp_type_named_get(tp, class_name, need_name_getter) : "void"); + ss << ">, \"" << type_class_name(tp) << "\"};\n"; + ss << " " << event_map << "[\"" << event_name << "\"] = &ev_info;\n"; + ss << " }\n"; + event_member_names.insert(event_name); + } + } + events_ss << ss.str(); + }; + generate_events(klass); + recurse_inherits(klass, generate_events); + + std::stringstream register_from_constructor_end_ss; + register_from_constructor_end_ss + << " prototype->Set(::efl::eina::js::compatibility_new<v8::String>(isolate, \"on\")\n" + << " , ::efl::eina::js::compatibility_new<v8::FunctionTemplate>(isolate, &efl::eo::js::on_event\n" + << " , ::efl::eina::js::compatibility_new<v8::External>(isolate, &" << event_map << ")));\n" + << " static_cast<void>(prototype); /* avoid warnings */\n" + << " static_cast<void>(isolate); /* avoid warnings */\n" + << " static_cast<void>(constructor_from_eo); /* avoid warnings */\n" + << " return instance;\n" + << "}\n\n"; + + std::stringstream name_getters_ss; + for (auto const& k : need_name_getter) + { + name_getters_ss << " struct " << _class_name_getter(class_name, k) << " { static char const* class_name() { return \"" << k << "\"; } };\n"; + } + + os << "namespace {\n"; + os << name_getters_ss.str(); + os << "}\n\n"; + + os << register_from_constructor_begin_ss.str(); + os << functions_ss.str(); + os << register_from_constructor_end_ss.str(); + + // generate main entry-point for generation + os << "EAPI void register_" << lower_case_class_name + << "(v8::Handle<v8::Object> global, v8::Isolate* isolate)\n"; + os << "{\n"; + os << " v8::Handle<v8::FunctionTemplate> constructor = ::efl::eina::js::compatibility_new<v8::FunctionTemplate>\n"; + os << " (isolate, efl::eo::js::constructor\n" + << " , efl::eo::js::constructor_data(isolate\n" + " , "; + + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "before print eo_class"; + + print_eo_class(klass, os); + + EINA_CXX_DOM_LOG_WARN(eolian::js::domain) << "print eo_class"; + + for(auto function : constructor_functions) + { + auto ftype = eolian_function_type_get(function); + if(ftype == EOLIAN_PROPERTY) + ftype = EOLIAN_PROP_SET; + os << "\n , & ::" + << eolian_function_full_c_name_get(function, ftype, EINA_FALSE); + } + + os << "));\n"; + + os << " static ::efl::eina::js::global_ref<v8::Function> constructor_from_eo;\n"; + os << events_ss.str(); + os << " register_" << lower_case_class_name << "_from_constructor(isolate, constructor, &constructor_from_eo);\n"; + + os << " constructor->SetClassName( ::efl::eina::js::compatibility_new<v8::String>(isolate, \"" + << format::generic(class_name) + << "\"));\n"; + + os << " auto to_export = ::efl::eo::js::get_namespace({"; + if (namespace_size(klass)) + { + bool comma = false; + for (efl::eina::iterator<const char> ns_it(::eolian_class_namespaces_get(klass)), ns_end; ns_it != ns_end; ++ns_it) + { + if (comma) + os << ", "; + comma = true; + os << '"' << format::generic(&*ns_it) << '"'; + } + } + os << "}, isolate, global);\n"; + + os << " to_export->Set( ::efl::eina::js::compatibility_new<v8::String>(isolate, \"" + << format::generic(class_name) << "\")" + << ", constructor->GetFunction());\n"; + + + os << " {\n"; + os << " v8::Handle<v8::FunctionTemplate> constructor = ::efl::eina::js::compatibility_new<v8::FunctionTemplate>\n"; + os << " (isolate, &efl::eo::js::construct_from_eo);\n"; + os << " constructor->SetClassName( ::efl::eina::js::compatibility_new<v8::String>(isolate, \"" + << format::generic(class_name) + << "\"));\n"; + os << " v8::Local<v8::ObjectTemplate> instance = " + << "register_" << lower_case_class_name << "_from_constructor(isolate, constructor, &constructor_from_eo);\n"; + os << " ::efl::eina::js::make_persistent(isolate, instance);\n"; + os << " constructor_from_eo = {isolate, constructor->GetFunction()};\n"; + os << " ::efl::eina::js::register_class_constructor(\"" << class_full_name << "\", constructor_from_eo.handle());\n"; + os << " }\n"; + + os << structs_ss.str(); + + // generate enumerations + for (efl::eina::iterator<Eolian_Type> first(::eolian_type_enums_get_by_file(file_basename.c_str())) + , last; first != last; ++first) + { + auto tp = &*first; + if (::eolian_type_is_extern(tp)) + continue; + std::string enum_name = ::eolian_type_name_get(tp); + os << " {\n"; + os << " auto to_export = ::efl::eo::js::get_namespace({"; + bool comma = false; + for (efl::eina::iterator<const char> ns_it(::eolian_type_namespaces_get(tp)), ns_end; ns_it != ns_end; ++ns_it) + { + if (comma) + os << ", "; + comma = true; + os << '"' << format::generic(&*ns_it) << '"'; + } + os << "}, isolate, global);\n"; + os << " v8::Handle<v8::Object> enum_obj = efl::eina::js::compatibility_new<v8::Object>(isolate);\n"; + os << " to_export->Set(efl::eina::js::compatibility_new<v8::String>(isolate, \"" + << format::generic(enum_name) << "\"), enum_obj);\n"; + for (efl::eina::iterator<Eolian_Enum_Type_Field> ef(::eolian_type_enum_fields_get(tp)) + , ef_end; ef != ef_end; ++ef) + { + auto field_name = ::eolian_type_enum_field_name_get(&*ef); + auto field_c_name = ::eolian_type_enum_field_c_name_get(&*ef); + if (!field_name || !field_c_name) + { + EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "Could not get enum field name"; + continue; + } + os << " enum_obj->Set(efl::eina::js::compatibility_new<v8::String>(isolate, \"" << format::constant(field_name) << "\"),\n"; + os << " efl::eina::js::compatibility_new<v8::Int32>(isolate, static_cast<int32_t>(::" << field_c_name << ")));\n"; + } + os << " }\n"; + } + + os << "}\n\n"; + + for(std::size_t i = 0, j = namespace_size(klass); i != j; ++i) + os << "}"; + os << "\n"; + + +} diff --git a/src/bindings/eina_cxx/Eina.hh b/src/bindings/eina_cxx/Eina.hh index d12b0c930f..8f5462892e 100644 --- a/src/bindings/eina_cxx/Eina.hh +++ b/src/bindings/eina_cxx/Eina.hh @@ -22,6 +22,7 @@ #include <eina_log.hh> #include <eina_optional.hh> #include <eina_integer_sequence.hh> +#include <eina_pp.hh> /** * @page eina_cxx_main Eina C++ (BETA) diff --git a/src/bindings/eina_cxx/eina_accessor.hh b/src/bindings/eina_cxx/eina_accessor.hh index b867f14248..d084918ca8 100644 --- a/src/bindings/eina_cxx/eina_accessor.hh +++ b/src/bindings/eina_cxx/eina_accessor.hh @@ -114,7 +114,10 @@ struct accessor_common_base * @warning It is important to take care when using it, since the * handle will be automatically release upon object destruction. */ - Eina_Accessor* native_handle() const; + Eina_Accessor* native_handle() const + { + return _impl; + } /** * @brief Swap content between both objects. diff --git a/src/bindings/eina_cxx/eina_array.hh b/src/bindings/eina_cxx/eina_array.hh index eb9e5578aa..d352de5ab7 100644 --- a/src/bindings/eina_cxx/eina_array.hh +++ b/src/bindings/eina_cxx/eina_array.hh @@ -32,6 +32,8 @@ public: typedef typename _base_type::reverse_iterator reverse_iterator; /**< Type for reverse iterator for this container. */ typedef typename _base_type::const_reverse_iterator const_reverse_iterator; /**< Type for reverse iterator for this container. */ + typedef typename _base_type::native_handle_type native_handle_type; + using _base_type::_base_type; using _base_type::clear; using _base_type::size; @@ -59,6 +61,7 @@ public: using _base_type::ciend; using _base_type::swap; using _base_type::max_size; + using _base_type::release_native_handle; using _base_type::native_handle; friend bool operator==(array<T, CloneAllocator> const& lhs, array<T, CloneAllocator> const& rhs) @@ -131,6 +134,101 @@ struct _ptr_eo_array_iterator : _ptr_array_iterator<Eo> using _base_type::native_handle; }; +/** + * @internal + */ +struct _eo_array_access_traits : _ptr_array_access_traits +{ + template <typename T> + struct iterator + { + typedef _ptr_eo_array_iterator<T> type; + }; + template <typename T> + struct const_iterator : iterator<T const> {}; + + template <typename T> + static T& back(Eina_Array* array) + { + return *static_cast<T*>(static_cast<void*>(array->data[size<T>(array)-1])); + } + template <typename T> + static T const& back(Eina_Array const* array) + { + return _eo_array_access_traits::back<T>(const_cast<Eina_Array*>(array)); + } + template <typename T> + static T& front(Eina_Array* array) + { + return *static_cast<T*>(static_cast<void*>(array->data[0])); + } + template <typename T> + static T const& front(Eina_Array const* array) + { + return _eo_array_access_traits::front<T>(const_cast<Eina_Array*>(array)); + } + template <typename T> + static typename iterator<T>::type begin(Eina_Array* array) + { + return _ptr_eo_array_iterator<T>(array->data); + } + template <typename T> + static typename iterator<T>::type end(Eina_Array* array) + { + return _ptr_eo_array_iterator<T>(array->data + size<T>(array)); + } + template <typename T> + static typename const_iterator<T>::type begin(Eina_Array const* array) + { + return _eo_array_access_traits::begin<T>(const_cast<Eina_Array*>(array)); + } + template <typename T> + static typename const_iterator<T>::type end(Eina_Array const* array) + { + return _eo_array_access_traits::end<T>(const_cast<Eina_Array*>(array)); + } + template <typename T> + static std::reverse_iterator<typename iterator<T>::type> rbegin(Eina_Array* array) + { + return std::reverse_iterator<_ptr_eo_array_iterator<T> >(_eo_array_access_traits::end<T>(array)); + } + template <typename T> + static std::reverse_iterator<typename iterator<T>::type> rend(Eina_Array* array) + { + return std::reverse_iterator<_ptr_eo_array_iterator<T> >(_eo_array_access_traits::begin<T>(array)); + } + template <typename T> + static std::reverse_iterator<typename const_iterator<T>::type> rbegin(Eina_Array const* array) + { + return std::reverse_iterator<_ptr_eo_array_iterator<T>const>(_eo_array_access_traits::end<T>(array)); + } + template <typename T> + static std::reverse_iterator<typename const_iterator<T>::type> rend(Eina_Array const* array) + { + return std::reverse_iterator<_ptr_eo_array_iterator<T>const>(_eo_array_access_traits::begin<T>(array)); + } + template <typename T> + static typename const_iterator<T>::type cbegin(Eina_Array const* array) + { + return _eo_array_access_traits::begin<T>(array); + } + template <typename T> + static typename const_iterator<T>::type cend(Eina_Array const* array) + { + return _eo_array_access_traits::end<T>(array); + } + template <typename T> + static std::reverse_iterator<typename const_iterator<T>::type> crbegin(Eina_Array const* array) + { + return _eo_array_access_traits::rbegin<T>(array); + } + template <typename T> + static std::reverse_iterator<typename const_iterator<T>::type> crend(Eina_Array const* array) + { + return _eo_array_access_traits::rend<T>(array); + } +}; + template <typename T, typename CloneAllocator> class array<T, CloneAllocator, typename std::enable_if<std::is_base_of<::efl::eo::concrete, T>::value>::type> : ptr_array<Eo, typename std::conditional @@ -156,7 +254,9 @@ public: typedef std::reverse_iterator<iterator> reverse_iterator; /**< Type for reverse iterator for this container. */ typedef std::reverse_iterator<const_iterator> const_reverse_iterator; /**< Type for reverse iterator for this container. */ - explicit array(Eina_Array* handle) + typedef typename _base_type::native_handle_type native_handle_type; /**< Type for the native handle of the container. */ + + explicit array(native_handle_type handle) : _base_type(handle) {} array(clone_allocator_type alloc) : _base_type(alloc) {} array() {} @@ -318,6 +418,7 @@ public: using _base_type::swap; using _base_type::max_size; + using _base_type::release_native_handle; using _base_type::native_handle; friend bool operator==(array<T, CloneAllocator> const& lhs, array<T, CloneAllocator> const& rhs) @@ -331,7 +432,154 @@ bool operator!=(array<T, CloneAllocator> const& lhs, array<T, CloneAllocator> co { return !(lhs == rhs); } + +template <typename T, typename Enable = void> +class range_array : range_ptr_array<T> +{ + typedef range_ptr_array<T> _base_type; +public: + typedef typename _base_type::value_type value_type; + typedef typename _base_type::reference reference; + typedef typename _base_type::const_reference const_reference; + typedef typename _base_type::const_iterator const_iterator; + typedef typename _base_type::iterator iterator; + typedef typename _base_type::pointer pointer; + typedef typename _base_type::const_pointer const_pointer; + typedef typename _base_type::size_type size_type; + typedef typename _base_type::difference_type difference_type; + + typedef typename _base_type::reverse_iterator reverse_iterator; + typedef typename _base_type::const_reverse_iterator const_reverse_iterator; + + typedef typename _base_type::native_handle_type native_handle_type; + + range_array& operator=(range_array&& other) = default; + + using _base_type::_base_type; + using _base_type::size; + using _base_type::empty; + using _base_type::back; + using _base_type::front; + using _base_type::begin; + using _base_type::end; + using _base_type::rbegin; + using _base_type::rend; + using _base_type::cbegin; + using _base_type::cend; + using _base_type::crbegin; + using _base_type::crend; + using _base_type::release_native_handle; + using _base_type::native_handle; +}; + +template <typename T> +class range_array<T, typename std::enable_if<std::is_base_of<::efl::eo::concrete, T>::value>::type> + : range_ptr_array<Eo> +{ + typedef range_ptr_array<Eo> _base_type; + typedef range_array<T> _self_type; +public: + typedef T value_type; + typedef value_type& reference; + typedef value_type const& const_reference; + typedef _ptr_eo_array_iterator<value_type const> const_iterator; + typedef _ptr_eo_array_iterator<value_type> iterator; + typedef value_type* pointer; + typedef value_type const* const_pointer; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + typedef typename _base_type::native_handle_type native_handle_type; + + explicit range_array(native_handle_type handle) + : _base_type(handle) {} + range_array() {} + range_array(range_array<T> const& other) + : _base_type(other.native_handle()) + { + } + range_array<T>& operator=(range_array<T>const& other) + { + _base_type::_handle = other._handle; + return *this; + } + range_array& operator=(range_array&& other) = default; + range_array(range_array&& other) = default; + using _base_type::size; + using _base_type::empty; + + reference front() + { + return _eo_array_access_traits::front<value_type>(native_handle()); + } + reference back() + { + return _eo_array_access_traits::back<value_type>(native_handle()); + } + const_reference front() const { return const_cast<_self_type*>(this)->front(); } + const_reference back() const { return const_cast<_self_type*>(this)->back(); } + iterator begin() + { + return _eo_array_access_traits::begin<value_type>(native_handle()); + } + iterator end() + { + return _eo_array_access_traits::end<value_type>(native_handle()); + } + const_iterator begin() const + { + return const_cast<_self_type*>(this)->begin(); + } + const_iterator end() const + { + return const_cast<_self_type*>(this)->end(); + } + const_iterator cbegin() const + { + return begin(); + } + const_iterator cend() const + { + return end(); + } + reverse_iterator rbegin() + { + return _eo_array_access_traits::rbegin<value_type>(native_handle()); + } + reverse_iterator rend() + { + return _eo_array_access_traits::rend<value_type>(native_handle()); + } + const_reverse_iterator rbegin() const + { + return const_cast<_self_type*>(this)->rbegin(); + } + const_reverse_iterator rend() const + { + return const_cast<_self_type*>(this)->rend(); + } + const_reverse_iterator crbegin() const + { + return rbegin(); + } + const_reverse_iterator crend() const + { + return rend(); + } + using _base_type::swap; + using _base_type::release_native_handle; + using _base_type::native_handle; + + friend bool operator==(range_array<T> const& rhs, range_array<T> const& lhs) + { + return rhs.size() == lhs.size() && std::equal(rhs.begin(), rhs.end(), lhs.begin()); + } +}; + } } #endif diff --git a/src/bindings/eina_cxx/eina_clone_allocators.hh b/src/bindings/eina_cxx/eina_clone_allocators.hh index 824d6d6ce9..76ff620f98 100644 --- a/src/bindings/eina_cxx/eina_clone_allocators.hh +++ b/src/bindings/eina_cxx/eina_clone_allocators.hh @@ -154,7 +154,8 @@ struct malloc_clone_allocator template <typename T> static void deallocate_clone(T const* p) { - static_assert(std::is_pod<T>::value, "malloc_clone_allocator can only be used with POD types"); + static_assert(std::is_pod<T>::value || std::is_void<T>::value + , "malloc_clone_allocator can only be used with POD types"); std::free(const_cast<T*>(p)); } }; diff --git a/src/bindings/eina_cxx/eina_function.hh b/src/bindings/eina_cxx/eina_function.hh new file mode 100644 index 0000000000..cef6da5a43 --- /dev/null +++ b/src/bindings/eina_cxx/eina_function.hh @@ -0,0 +1,26 @@ +#ifndef EFL_EINA_FUNCTION_HH +#define EFL_EINA_FUNCTION_HH + +namespace efl { namespace eina { namespace _mpl { + +template <typename T> +struct function_params; + +template <typename R, typename... P> +struct function_params<R(*)(P...)> +{ + typedef std::tuple<P...> type; +}; + +template <typename T> +struct function_return; + +template <typename R, typename... P> +struct function_return<R(*)(P...)> +{ + typedef R type; +}; + +} } } + +#endif diff --git a/src/bindings/eina_cxx/eina_integer_sequence.hh b/src/bindings/eina_cxx/eina_integer_sequence.hh index 854bb8f3d0..f99c871c34 100644 --- a/src/bindings/eina_cxx/eina_integer_sequence.hh +++ b/src/bindings/eina_cxx/eina_integer_sequence.hh @@ -1,6 +1,8 @@ #ifndef EINA_CXX_EINA_INTEGER_SEQUENCE_HH #define EINA_CXX_EINA_INTEGER_SEQUENCE_HH +#include <cstdlib> + /** * @addtogroup Eina_Cxx_Data_Types_Group * diff --git a/src/bindings/eina_cxx/eina_list.hh b/src/bindings/eina_cxx/eina_list.hh index 760ada3963..1221867c7b 100644 --- a/src/bindings/eina_cxx/eina_list.hh +++ b/src/bindings/eina_cxx/eina_list.hh @@ -190,6 +190,8 @@ public: typedef typename _base_type::reverse_iterator reverse_iterator; typedef typename _base_type::const_reverse_iterator const_reverse_iterator; + using _base_type::native_handle_type; + list& operator=(list&& other) = default; list(list&& other) = default; list() = default; @@ -224,6 +226,7 @@ public: using _base_type::max_size; using _base_type::native_handle; using _base_type::accessor; + using _base_type::release_native_handle; }; template <typename T, typename CloneAllocator> @@ -251,7 +254,9 @@ public: typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - explicit list(Eina_List* handle) + using _base_type::native_handle_type; + + explicit list(typename _self_type::native_handle_type handle) : _base_type(handle) {} list(clone_allocator_type alloc) : _base_type(alloc) {} list() {} @@ -295,6 +300,7 @@ public: using _base_type::get_clone_allocator; using _base_type::pop_back; using _base_type::pop_front; + using _base_type::release_native_handle; void push_back(const_reference w) { @@ -464,6 +470,8 @@ public: typedef typename _base_type::reverse_iterator reverse_iterator; typedef typename _base_type::const_reverse_iterator const_reverse_iterator; + using _base_type::native_handle_type; + using _base_type::_base_type; using _base_type::size; using _base_type::empty; @@ -501,9 +509,9 @@ public: typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - typedef typename _base_type::native_handle_type native_handle_type; + using _base_type::native_handle_type; - explicit range_list(native_handle_type handle) + explicit range_list(typename _self_type::native_handle_type handle) : _base_type(handle) {} range_list() {} range_list(range_list<T> const& other) diff --git a/src/bindings/eina_cxx/eina_logical.hh b/src/bindings/eina_cxx/eina_logical.hh new file mode 100644 index 0000000000..d53d3541ad --- /dev/null +++ b/src/bindings/eina_cxx/eina_logical.hh @@ -0,0 +1,34 @@ +#ifndef EFL_EINA_LOGICAL_HH +#define EFL_EINA_LOGICAL_HH + +#include <type_traits> + +namespace efl { namespace eina { namespace _mpl { + +template <bool... N> +struct or_; + +template <> +struct or_<> : std::integral_constant<bool, false> {}; + +template <bool B> +struct or_<B> : std::integral_constant<bool, B> {}; + +template <bool B1, bool B2, bool... Bs> +struct or_<B1, B2, Bs...> : std::integral_constant<bool, B1 || B2 || or_<Bs...>::value> {}; + +template <bool... N> +struct and_; + +template <> +struct and_<> : std::integral_constant<bool, true> {}; + +template <bool B> +struct and_<B> : std::integral_constant<bool, B> {}; + +template <bool B1, bool B2, bool... Bs> +struct and_<B1, B2, Bs...> : std::integral_constant<bool, B1 && B2 && and_<Bs...>::value> {}; + +} } } + +#endif diff --git a/src/bindings/eina_cxx/eina_pp.hh b/src/bindings/eina_cxx/eina_pp.hh new file mode 100644 index 0000000000..22a6a22ef7 --- /dev/null +++ b/src/bindings/eina_cxx/eina_pp.hh @@ -0,0 +1,8 @@ + +#ifndef EINA_PP_HH +#define EINA_PP_HH + +#define EINA_STRINGIZE_IMPL(x) #x +#define EINA_STRINGIZE(x) EINA_STRINGIZE_IMPL(x) + +#endif diff --git a/src/bindings/eina_cxx/eina_ptrarray.hh b/src/bindings/eina_cxx/eina_ptrarray.hh index 2f40627ce9..f47202ebb5 100644 --- a/src/bindings/eina_cxx/eina_ptrarray.hh +++ b/src/bindings/eina_cxx/eina_ptrarray.hh @@ -295,10 +295,12 @@ struct range_ptr_array : _range_template<T, _ptr_array_access_traits> typedef _range_template<T, _ptr_array_access_traits> _base_type; /**< Type for the base class. */ typedef typename _base_type::value_type value_type; /**< The type of each element. */ + typedef typename _base_type::native_handle_type native_handle_type; + /** * @brief Creates a range from a native Eina array handle. */ - range_ptr_array(Eina_Array* array) + range_ptr_array(native_handle_type array) : _base_type(array) {} @@ -391,7 +393,7 @@ struct _ptr_array_common_base /** * @internal */ - T* _new_clone(T const& a) + T* _new_clone(typename container_value_type<T>::type const& a) { return _get_clone_allocator().allocate_clone(a); } @@ -402,6 +404,7 @@ struct _ptr_array_common_base struct _ptr_array_impl : CloneAllocator { _ptr_array_impl() : _array( ::eina_array_new(32u) ) {} + _ptr_array_impl(Eina_Array* array) : _array(array) {} _ptr_array_impl(CloneAllocator allocator) : clone_allocator_type(allocator), _array( ::eina_array_new(32u)) {} @@ -449,6 +452,8 @@ public: typedef std::unique_ptr<value_type, clone_allocator_deleter<clone_allocator_type> > _unique_ptr; + typedef Eina_Array* native_handle_type; + /** * @brief Default constructor. Create an empty array. * @@ -1210,6 +1215,13 @@ public: */ size_type max_size() const { return -1; } + Eina_Array* release_native_handle() + { + Eina_Array* tmp = this->_impl._array; + this->_impl._array = ::eina_array_new(32u); + return tmp; + } + /** * @brief Get a handle for the wrapped Eina_Array. * @return Handle for the native Eina array. diff --git a/src/bindings/eina_cxx/eina_ptrlist.hh b/src/bindings/eina_cxx/eina_ptrlist.hh index 2f18d10ffb..f7254b1ef2 100644 --- a/src/bindings/eina_cxx/eina_ptrlist.hh +++ b/src/bindings/eina_cxx/eina_ptrlist.hh @@ -9,6 +9,7 @@ #include <eina_eo_concrete_fwd.hh> #include <eina_iterator.hh> #include <eina_throw.hh> +#include <eina_range_types.hh> #include <memory> #include <iterator> @@ -370,7 +371,7 @@ struct _ptr_list_common_base /** * @internal */ - T* _new_clone(T const& a) + T* _new_clone(typename container_value_type<T>::type const& a) { return _get_clone_allocator().allocate_clone(a); } @@ -413,11 +414,12 @@ class ptr_list : protected _ptr_list_common_base<T, CloneAllocator> { typedef _ptr_list_common_base<T, CloneAllocator> _base_type; /**< Type for the base class. */ public: - typedef T value_type; /**< The type of each element. */ - typedef T& reference; /**< Type for a reference to an element. */ - typedef T const& const_reference; /**< Type for a constant reference to an element. */ - typedef _ptr_list_iterator<T const> const_iterator; /**< Type for a iterator for this container. */ - typedef _ptr_list_iterator<T> iterator; /**< Type for a constant iterator for this container. */ + typedef typename container_value_type<T>::type + value_type; /**< The type of each element. */ + typedef value_type& reference; /**< Type for a reference to an element. */ + typedef value_type const& const_reference; /**< Type for a constant reference to an element. */ + typedef _ptr_list_iterator<value_type const> const_iterator; /**< Type for a iterator for this container. */ + typedef _ptr_list_iterator<value_type> iterator; /**< Type for a constant iterator for this container. */ typedef T* pointer; /**< Type for a pointer to an element. */ typedef T const* const_pointer; /**< Type for a constant pointer for an element. */ typedef std::size_t size_type; /**< Type for size information. */ @@ -427,6 +429,8 @@ public: typedef std::reverse_iterator<iterator> reverse_iterator; /**< Type for reverse iterator for this container. */ typedef std::reverse_iterator<const_iterator> const_reverse_iterator; /**< Type for reverse iterator for this container. */ + typedef Eina_List* native_handle_type; + typedef std::unique_ptr<value_type, clone_allocator_deleter<clone_allocator_type> > _unique_ptr; /** @@ -554,7 +558,7 @@ public: */ std::size_t size() const { - return _ptr_list_access_traits::size<T>(this->_impl._list); + return _ptr_list_access_traits::size<value_type>(this->_impl._list); } /** @@ -566,7 +570,7 @@ public: */ bool empty() const { - return _ptr_list_access_traits::empty<T>(this->_impl._list); + return _ptr_list_access_traits::empty<value_type>(this->_impl._list); } /** @@ -940,7 +944,7 @@ public: */ value_type& back() { - return _ptr_list_access_traits::back<T>(this->_impl._list); + return _ptr_list_access_traits::back<value_type>(this->_impl._list); } /** @@ -952,7 +956,7 @@ public: */ value_type const& back() const { - return _ptr_list_access_traits::back<T>(this->_impl._list); + return _ptr_list_access_traits::back<value_type>(this->_impl._list); } /** @@ -961,7 +965,7 @@ public: */ value_type& front() { - return _ptr_list_access_traits::front<T>(this->_impl._list); + return _ptr_list_access_traits::front<value_type>(this->_impl._list); } /** @@ -973,7 +977,7 @@ public: */ value_type const& front() const { - return _ptr_list_access_traits::front<T>(this->_impl._list); + return _ptr_list_access_traits::front<value_type>(this->_impl._list); } /** @@ -985,7 +989,7 @@ public: */ const_iterator begin() const { - return _ptr_list_access_traits::cbegin<T>(this->_impl._list); + return _ptr_list_access_traits::cbegin<value_type>(this->_impl._list); } /** @@ -997,7 +1001,7 @@ public: */ const_iterator end() const { - return _ptr_list_access_traits::cend<T>(this->_impl._list); + return _ptr_list_access_traits::cend<value_type>(this->_impl._list); } /** @@ -1010,7 +1014,7 @@ public: */ iterator begin() { - return _ptr_list_access_traits::begin<T>(this->_impl._list); + return _ptr_list_access_traits::begin<value_type>(this->_impl._list); } /** @@ -1026,7 +1030,7 @@ public: */ iterator end() { - return _ptr_list_access_traits::end<T>(this->_impl._list); + return _ptr_list_access_traits::end<value_type>(this->_impl._list); } /** @@ -1038,7 +1042,7 @@ public: */ const_reverse_iterator rbegin() const { - return _ptr_list_access_traits::rbegin<T>(this->_impl._list); + return _ptr_list_access_traits::rbegin<value_type>(this->_impl._list); } /** @@ -1050,7 +1054,7 @@ public: */ const_reverse_iterator rend() const { - return _ptr_list_access_traits::rend<T>(this->_impl._list); + return _ptr_list_access_traits::rend<value_type>(this->_impl._list); } /** @@ -1063,7 +1067,7 @@ public: */ reverse_iterator rbegin() { - return _ptr_list_access_traits::rbegin<T>(this->_impl._list); + return _ptr_list_access_traits::rbegin<value_type>(this->_impl._list); } /** @@ -1080,7 +1084,7 @@ public: */ reverse_iterator rend() { - return _ptr_list_access_traits::rend<T>(this->_impl._list); + return _ptr_list_access_traits::rend<value_type>(this->_impl._list); } /** @@ -1093,7 +1097,7 @@ public: */ const_iterator cbegin() const { - return _ptr_list_access_traits::cbegin<T>(this->_impl._list); + return _ptr_list_access_traits::cbegin<value_type>(this->_impl._list); } /** @@ -1106,7 +1110,7 @@ public: */ const_iterator cend() const { - return _ptr_list_access_traits::cend<T>(this->_impl._list); + return _ptr_list_access_traits::cend<value_type>(this->_impl._list); } /** @@ -1119,7 +1123,7 @@ public: */ const_reverse_iterator crbegin() const { - return _ptr_list_access_traits::crbegin<T>(this->_impl._list); + return _ptr_list_access_traits::crbegin<value_type>(this->_impl._list); } /** @@ -1132,7 +1136,7 @@ public: */ const_reverse_iterator crend() const { - return _ptr_list_access_traits::crend<T>(this->_impl._list); + return _ptr_list_access_traits::crend<value_type>(this->_impl._list); } /** @@ -1143,9 +1147,9 @@ public: * the first element of the list. If the list is empty the returned * iterator is the same as the one returned by @ref iend(). */ - eina::iterator<T> ibegin() + eina::iterator<value_type> ibegin() { - return _ptr_list_access_traits::ibegin<T>(this->_impl._list); + return _ptr_list_access_traits::ibegin<value_type>(this->_impl._list); } /** @@ -1160,9 +1164,9 @@ public: * @note Note that attempting to access this position causes undefined * behavior. */ - eina::iterator<T> iend() + eina::iterator<value_type> iend() { - return _ptr_list_access_traits::iend<T>(this->_impl._list); + return _ptr_list_access_traits::iend<value_type>(this->_impl._list); } /** @@ -1174,7 +1178,7 @@ public: */ eina::iterator<T const> ibegin() const { - return _ptr_list_access_traits::ibegin<T>(this->_impl._list); + return _ptr_list_access_traits::ibegin<value_type>(this->_impl._list); } /** @@ -1186,7 +1190,7 @@ public: */ eina::iterator<T const> iend() const { - return _ptr_list_access_traits::iend<T>(this->_impl._list); + return _ptr_list_access_traits::iend<value_type>(this->_impl._list); } /** @@ -1199,7 +1203,7 @@ public: */ eina::iterator<T const> cibegin() const { - return _ptr_list_access_traits::cibegin<T>(this->_impl._list); + return _ptr_list_access_traits::cibegin<value_type>(this->_impl._list); } /** @@ -1212,7 +1216,7 @@ public: */ eina::iterator<T const> ciend() const { - return _ptr_list_access_traits::ciend<T>(this->_impl._list); + return _ptr_list_access_traits::ciend<value_type>(this->_impl._list); } /** @@ -1230,6 +1234,13 @@ public: */ size_type max_size() const { return -1; } + Eina_List* release_native_handle() + { + Eina_List* tmp = this->_impl._list; + this->_impl._list = 0; + return tmp; + } + /** * @brief Get a handle for the wrapped @c Eina_List. * @return Handle for the native Eina list. @@ -1275,9 +1286,9 @@ public: * @brief Get a @ref eina::accessor for the list. * @return <tt>eina::accessor</tt> to the list. */ - eina::accessor<T> accessor() + eina::accessor<value_type> accessor() { - return eina::accessor<T>(eina_list_accessor_new(this->_impl._list)); + return eina::accessor<value_type>(eina_list_accessor_new(this->_impl._list)); } }; diff --git a/src/bindings/eina_cxx/eina_range_types.hh b/src/bindings/eina_cxx/eina_range_types.hh index 844e2ef4cc..313ca05cd9 100644 --- a/src/bindings/eina_cxx/eina_range_types.hh +++ b/src/bindings/eina_cxx/eina_range_types.hh @@ -22,11 +22,12 @@ namespace efl { namespace eina { template <typename T, typename Traits> struct _const_range_template { - typedef typename Traits::template const_iterator<T>::type const_iterator; /**< Type for constant iterator to the range. */ - typedef typename Traits::template iterator<T>::type iterator; /**< Type for iterator to the range. */ - typedef T value_type; /**< The type of each element. */ - typedef T& reference; /**< Type for a reference to an element. */ - typedef T const& const_reference; /**< Type for a constant reference to an element. */ + typedef typename container_value_type<T>::type + value_type; /**< The type of each element. */ + typedef typename Traits::template const_iterator<value_type>::type const_iterator; /**< Type for constant iterator to the range. */ + typedef typename Traits::template iterator<value_type>::type iterator; /**< Type for iterator to the range. */ + typedef value_type& reference; /**< Type for a reference to an element. */ + typedef value_type const& const_reference; /**< Type for a constant reference to an element. */ typedef T* pointer; /**< Type for a pointer to an element. */ typedef T const* const_pointer; /**< Type for a constant pointer to an element. */ typedef std::reverse_iterator<iterator> reverse_iterator; /**< Type for reverse iterator to the range. */ @@ -50,6 +51,17 @@ struct _const_range_template : _handle(handle) {} /** + * @brief Release the handle of the native Eina container. + * @return Handle for the native Eina container. + */ + native_handle_type release_native_handle() + { + auto h = _handle; + _handle = nullptr; + return h; + } + + /** * @brief Get a constant handle for the native Eina container. * @return Constant handle for the native Eina container. */ @@ -241,10 +253,13 @@ void swap(_const_range_template<T, Traits>& lhs, _const_range_template<T, Traits template <typename T, typename Traits> struct _mutable_range_template : _const_range_template<T, Traits> { - typedef T value_type; /**< The type of each element. */ - typedef typename Traits::template iterator<T>::type iterator; /**< Type for a iterator to the range. */ + typedef typename container_value_type<T>::type + value_type; /**< The type of each element. */ + typedef value_type& reference_type; + typedef value_type const& const_reference_type; + typedef typename Traits::template iterator<value_type>::type iterator; /**< Type for a iterator to the range. */ typedef std::reverse_iterator<iterator> reverse_iterator; /**< Type for constant reverse iterator to the range. */ - typedef typename Traits::template native_handle<T>::type native_handle_type; /**< Type for the native handle of the container. */ + typedef typename Traits::template native_handle<value_type>::type native_handle_type; /**< Type for the native handle of the container. */ typedef _const_range_template<T, Traits> _base_type; /**< Type for the base class. */ /** @@ -254,6 +269,17 @@ struct _mutable_range_template : _const_range_template<T, Traits> : _base_type(handle) {} /** + * @brief Release the handle of the native Eina container. + * @return Handle for the native Eina container. + */ + native_handle_type release_native_handle() + { + auto h = _handle; + _handle = nullptr; + return h; + } + + /** * @brief Get a constant handle for the native Eina container. * @return Constant handle for the native Eina container. */ @@ -266,7 +292,7 @@ struct _mutable_range_template : _const_range_template<T, Traits> * @brief Get a reference to the last element. * @return Reference to the last element of the range. */ - value_type& back() const + reference_type back() const { return Traits::template back<value_type>(native_handle()); } @@ -275,7 +301,7 @@ struct _mutable_range_template : _const_range_template<T, Traits> * @brief Get a reference to the first element. * @return Reference to the first element of the range. */ - value_type& front() const + reference_type front() const { return Traits::template front<value_type>(native_handle()); } @@ -355,11 +381,12 @@ protected: template <typename T, typename Traits> struct _range_template : private std::conditional <std::is_const<T>::value - , _const_range_template<typename std::remove_const<T>::type, Traits> - , _mutable_range_template<T, Traits> >::type + , _const_range_template<typename nonconst_container_value_type<T>::type, Traits> + , _mutable_range_template<typename nonconst_container_value_type<T>::type, Traits> + >::type { typedef std::integral_constant<bool, !std::is_const<T>::value> is_mutable; /**< Type that specifies if the elements can be modified. */ - typedef typename std::remove_const<T>::type value_type; /**< The type of each element. */ + typedef typename nonconst_container_value_type<T>::type value_type; /**< The type of each element. */ typedef typename std::conditional<is_mutable::value, _mutable_range_template<value_type, Traits> , _const_range_template<value_type, Traits> >::type _base_type; /**< Type for the base class. */ typedef typename _base_type::native_handle_type native_handle_type; /**< Type for the native handle of the container. */ @@ -368,9 +395,9 @@ struct _range_template : private std::conditional typedef value_type const& const_reference; /**< Type for a constant reference to an element. */ typedef value_type* pointer; /**< Type for a pointer to an element. */ typedef value_type const* const_pointer; /**< Type for a constant pointer to an element. */ - typedef typename Traits::template const_iterator<T>::type const_iterator; /**< Type for constant iterator to the range. */ + typedef typename Traits::template const_iterator<value_type>::type const_iterator; /**< Type for constant iterator to the range. */ typedef typename _base_type::const_reverse_iterator const_reverse_iterator; /**< Type for constant reverse iterator to the range. */ - typedef typename Traits::template iterator<T>::type iterator; /**< Type for iterator to the range. */ + typedef typename Traits::template iterator<value_type>::type iterator; /**< Type for iterator to the range. */ typedef typename _base_type::reverse_iterator reverse_iterator; /**< Type for reverse iterator to the range. */ typedef typename _base_type::size_type size_type; /**< Type for size information. */ typedef typename _base_type::difference_type difference_type; /**< Type to represent the distance between two iterators. */ @@ -388,6 +415,7 @@ struct _range_template : private std::conditional : _base_type(handle) {} + using _base_type::release_native_handle; using _base_type::native_handle; using _base_type::back; using _base_type::front; diff --git a/src/bindings/eina_cxx/eina_tuple.hh b/src/bindings/eina_cxx/eina_tuple.hh index f0f22d9cae..45545c3702 100644 --- a/src/bindings/eina_cxx/eina_tuple.hh +++ b/src/bindings/eina_cxx/eina_tuple.hh @@ -1,6 +1,11 @@ #ifndef EFL_EINA_EINA_TUPLE_HH_ #define EFL_EINA_EINA_TUPLE_HH_ +#include <eina_integer_sequence.hh> +#include <eina_logical.hh> + +#include <tuple> + namespace efl { namespace eina { namespace _mpl { template <typename A, typename... Args> @@ -21,15 +26,64 @@ struct push_front<C<Args...>, AArgs...> typedef C<Args..., AArgs...> type; }; -template <typename A> +template <typename A, std::size_t N = 1> struct pop_front; - + template <template <typename...> class C, typename T, typename... Args> -struct pop_front<C<T, Args...> > +struct pop_front<C<T, Args...>, 1> { typedef C<Args...> type; }; +template <typename A, std::size_t N> +struct pop_front : pop_front<typename pop_front<A, 1>::type, N-1> +{ +}; + +template <typename T, typename F, std::size_t... I> +void for_each_impl(T&& t, F&& f, eina::index_sequence<I...>) +{ + std::initializer_list<int> l = { (f(std::get<I>(t)), 0)...}; + static_cast<void>(l); +} + +template <typename T, typename F> +void for_each(T&& t, F&& f) +{ + _mpl::for_each_impl(t, f, eina::make_index_sequence + <std::tuple_size<typename std::remove_reference<T>::type>::value>()); +} + +template <typename T, typename Transform> +struct tuple_transform; + +template <typename...T, typename Transform> +struct tuple_transform<std::tuple<T...>, Transform> +{ + typedef std::tuple<typename Transform::template apply<T>::type...> type; +}; + +template <typename T, typename Tuple> +struct tuple_contains; + + + +template <typename T, typename...Ts> +struct tuple_contains<T, std::tuple<Ts...> > + : _mpl::or_<std::is_same<T, Ts>::value...> +{ +}; + +template <typename T, typename Tuple> +struct tuple_find : std::integral_constant<int, -1> {}; + +template <typename T, typename... Ts> +struct tuple_find<T, std::tuple<T, Ts...> > : std::integral_constant<std::size_t, 0> {}; + +template <typename T, typename T1, typename... Ts> +struct tuple_find<T, std::tuple<T1, Ts...> > : std::integral_constant + <std::size_t, 1 + tuple_find<T, std::tuple<Ts...> >::value> {}; + } } } #endif diff --git a/src/bindings/eina_cxx/eina_tuple_c.hh b/src/bindings/eina_cxx/eina_tuple_c.hh new file mode 100644 index 0000000000..64d67c49a9 --- /dev/null +++ b/src/bindings/eina_cxx/eina_tuple_c.hh @@ -0,0 +1,24 @@ +#ifndef EFL_EINA_EINA_TUPLE_C_HH_ +#define EFL_EINA_EINA_TUPLE_C_HH_ + +#include <tuple> + +namespace efl { namespace eina { namespace _mpl { + +template <typename T, T... Ts> +using tuple_c = std::tuple<std::integral_constant<T, Ts>...>; + +template <typename T, T... Ts> +constexpr std::size_t tuple_c_size(tuple_c<T, Ts...> const&) +{ + return sizeof...(Ts); +} + +constexpr std::size_t tuple_c_size(std::tuple<> const&) +{ + return 0; +} + +} } } + +#endif diff --git a/src/bindings/eina_cxx/eina_type_traits.hh b/src/bindings/eina_cxx/eina_type_traits.hh index 9e8628ad90..ff8bfbbff9 100644 --- a/src/bindings/eina_cxx/eina_type_traits.hh +++ b/src/bindings/eina_cxx/eina_type_traits.hh @@ -64,6 +64,22 @@ struct if_ : if_c<U::value, T, F> { }; +template <typename T> +struct container_value_type +{ + typedef typename std::conditional< + std::is_void<T>::value + , T*, T>::type type; +}; + +template <typename T> +struct nonconst_container_value_type +{ + typedef typename std::conditional< + std::is_void<T>::value + , T*, typename std::remove_const<T>::type>::type type; +}; + /** * @} */ diff --git a/src/bindings/eldbus_cxx/eldbus_freedesktop.hh b/src/bindings/eldbus_cxx/eldbus_freedesktop.hh index e44b9b228d..4af8c58e30 100644 --- a/src/bindings/eldbus_cxx/eldbus_freedesktop.hh +++ b/src/bindings/eldbus_cxx/eldbus_freedesktop.hh @@ -11,7 +11,6 @@ namespace efl { namespace eldbus { namespace _detail { template <typename Callback, typename... Ins> void _callback_wrapper(void* data, Eldbus_Message const* message, Eldbus_Pending* pending) { - std::cout << "_callback_wrapper" << std::endl; Callback* callback(static_cast<Callback*>(data)); const char* errname, *errmsg; diff --git a/src/bindings/eo_cxx/eo_concrete.hh b/src/bindings/eo_cxx/eo_concrete.hh index 9e328b1d92..c975bbc5e3 100644 --- a/src/bindings/eo_cxx/eo_concrete.hh +++ b/src/bindings/eo_cxx/eo_concrete.hh @@ -187,6 +187,13 @@ struct concrete Eo* _eo_raw; ///< The opaque <em>EO Object</em>. }; +template<class CharT, class Traits> +inline std::basic_ostream<CharT, Traits>& +operator<<(std::basic_ostream<CharT, Traits>& os, concrete const& eo) +{ + return os << eo._eo_ptr(); +} + inline bool operator==(concrete const& lhs, concrete const& rhs) { return lhs._eo_ptr() == rhs._eo_ptr(); diff --git a/src/bindings/js/ecore_js/Ecore_Js.hh b/src/bindings/js/ecore_js/Ecore_Js.hh new file mode 100644 index 0000000000..3f877f3fc8 --- /dev/null +++ b/src/bindings/js/ecore_js/Ecore_Js.hh @@ -0,0 +1,58 @@ + +#ifndef EFL_ECORE_JS_HH +#define EFL_ECORE_JS_HH + +#include <Ecore.hh> +#include <Ecore_File.h> +#include <Eina_Js.hh> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_JS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +namespace efl { namespace ecore { namespace js { + +using ::efl::eina::js::compatibility_new; +using ::efl::eina::js::compatibility_return_type; +using ::efl::eina::js::compatibility_callback_info_type; +using ::efl::eina::js::compatibility_return; +using ::efl::eina::js::compatibility_get_pointer_internal_field; +using ::efl::eina::js::compatibility_set_pointer_internal_field; + +EAPI void register_ecore_animator(v8::Isolate *isolate,v8::Handle<v8::Object> exports); +EAPI void register_ecore_event(v8::Isolate* isolate, v8::Handle<v8::Object> exports); +EAPI void register_ecore_file(v8::Isolate* isolate, v8::Handle<v8::Object> exports); +EAPI void register_ecore_idle(v8::Isolate *isolate,v8::Handle<v8::Object> exports); +EAPI void register_ecore_job(v8::Isolate *isolate,v8::Handle<v8::Object> exports); +EAPI void register_ecore_mainloop(v8::Isolate *isolate,v8::Handle<v8::Object> exports); +EAPI void register_ecore_poller(v8::Isolate *isolate,v8::Handle<v8::Object> exports); +EAPI void register_ecore_throttle(v8::Isolate *isolate,v8::Handle<v8::Object> exports); +EAPI void register_ecore_timer(v8::Isolate *isolate,v8::Handle<v8::Object> exports); + +EAPI void register_ecore(v8::Isolate *isolate,v8::Handle<v8::Object> exports); + +} } } + +#endif diff --git a/src/bindings/js/ecore_js/ecore_js_animator.cc b/src/bindings/js/ecore_js/ecore_js_animator.cc new file mode 100644 index 0000000000..849e4d7f34 --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_animator.cc @@ -0,0 +1,608 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ecore_Js.hh> + +namespace efl { namespace ecore { namespace js { + +static Ecore_Animator* extract_animator(v8::Local<v8::Object> object) +{ + auto ptr = v8::External::Cast(*object->GetInternalField(0))->Value(); + return reinterpret_cast<Ecore_Animator*>(ptr); +} + +static v8::Local<v8::Object> wrap_animator(Ecore_Animator *animator, + v8::Isolate *isolate) +{ + using v8::Boolean; + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_animator_del(extract_animator(info.This())); + return compatibility_return(); + }; + + auto freeze = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_animator_freeze(extract_animator(info.This())); + return compatibility_return(); + }; + + auto thaw = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_animator_thaw(extract_animator(info.This())); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "freeze"), + compatibility_new<FunctionTemplate>(isolate, freeze) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "thaw"), + compatibility_new<FunctionTemplate>(isolate, thaw)->GetFunction()); + + ret->SetInternalField(0, compatibility_new<v8::External>(isolate, + animator)); + + return ret; +} + +void register_pos_map_linear(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_POS_MAP_LINEAR)); +} + +void register_pos_map_accelerate(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_POS_MAP_ACCELERATE)); +} + +void register_pos_map_decelerate(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_POS_MAP_DECELERATE)); +} + +void register_pos_map_sinusoidal(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_POS_MAP_SINUSOIDAL)); +} + +void register_pos_map_accelerate_factor(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_POS_MAP_ACCELERATE_FACTOR)); +} + +void register_pos_map_decelerate_factor(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_POS_MAP_DECELERATE_FACTOR)); +} + +void register_pos_map_sinusoidal_factor(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_POS_MAP_SINUSOIDAL_FACTOR)); +} + +void register_pos_map_divisor_interp(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_POS_MAP_DIVISOR_INTERP)); +} + +void register_pos_map_bounce(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_POS_MAP_BOUNCE)); +} + +void register_pos_map_spring(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_POS_MAP_SPRING)); +} + +void register_pos_map_cubic_bezier(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_POS_MAP_CUBIC_BEZIER)); +} + +void register_animator_source_timer(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_ANIMATOR_SOURCE_TIMER)); +} + +void register_animator_frametime_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + ecore_animator_frametime_set(args[0]->NumberValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_animator_frametime_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Number; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ecore_animator_frametime_get(); + return compatibility_return(compatibility_new<Number>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_animator_pos_map(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Number; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 4 || !args[0]->IsNumber() || !args[1]->IsNumber() + || !args[2]->IsNumber() || !args[3]->IsNumber()) + return compatibility_return(); + + Ecore_Pos_Map map; + + switch ((int)(args[1]->NumberValue())) { + case ECORE_POS_MAP_LINEAR: + map = ECORE_POS_MAP_LINEAR; + break; + case ECORE_POS_MAP_ACCELERATE: + map = ECORE_POS_MAP_ACCELERATE; + break; + case ECORE_POS_MAP_DECELERATE: + map = ECORE_POS_MAP_DECELERATE; + break; + case ECORE_POS_MAP_SINUSOIDAL: + map = ECORE_POS_MAP_SINUSOIDAL; + break; + case ECORE_POS_MAP_ACCELERATE_FACTOR: + map = ECORE_POS_MAP_ACCELERATE_FACTOR; + break; + case ECORE_POS_MAP_DECELERATE_FACTOR: + map = ECORE_POS_MAP_DECELERATE_FACTOR; + break; + case ECORE_POS_MAP_SINUSOIDAL_FACTOR: + map = ECORE_POS_MAP_SINUSOIDAL_FACTOR; + break; + case ECORE_POS_MAP_DIVISOR_INTERP: + map = ECORE_POS_MAP_DIVISOR_INTERP; + break; + case ECORE_POS_MAP_BOUNCE: + map = ECORE_POS_MAP_BOUNCE; + break; + case ECORE_POS_MAP_SPRING: + map = ECORE_POS_MAP_SPRING; + break; + case ECORE_POS_MAP_CUBIC_BEZIER: + map = ECORE_POS_MAP_CUBIC_BEZIER; + break; + default: + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + auto ret = ecore_animator_pos_map(args[0]->NumberValue(), map, + args[2]->NumberValue(), + args[3]->NumberValue()); + return compatibility_return(compatibility_new<Number>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_animator_pos_map_n(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Number; + using v8::NumberObject; + using v8::FunctionTemplate; + using v8::Array; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 3 || !args[0]->IsNumber() || !args[1]->IsNumber() + || !args[2]->IsArray()) + return compatibility_return(); + + Ecore_Pos_Map map; + + switch ((int)(args[1]->NumberValue())) { + case ECORE_POS_MAP_LINEAR: + map = ECORE_POS_MAP_LINEAR; + break; + case ECORE_POS_MAP_ACCELERATE: + map = ECORE_POS_MAP_ACCELERATE; + break; + case ECORE_POS_MAP_DECELERATE: + map = ECORE_POS_MAP_DECELERATE; + break; + case ECORE_POS_MAP_SINUSOIDAL: + map = ECORE_POS_MAP_SINUSOIDAL; + break; + case ECORE_POS_MAP_ACCELERATE_FACTOR: + map = ECORE_POS_MAP_ACCELERATE_FACTOR; + break; + case ECORE_POS_MAP_DECELERATE_FACTOR: + map = ECORE_POS_MAP_DECELERATE_FACTOR; + break; + case ECORE_POS_MAP_SINUSOIDAL_FACTOR: + map = ECORE_POS_MAP_SINUSOIDAL_FACTOR; + break; + case ECORE_POS_MAP_DIVISOR_INTERP: + map = ECORE_POS_MAP_DIVISOR_INTERP; + break; + case ECORE_POS_MAP_BOUNCE: + map = ECORE_POS_MAP_BOUNCE; + break; + case ECORE_POS_MAP_SPRING: + map = ECORE_POS_MAP_SPRING; + break; + case ECORE_POS_MAP_CUBIC_BEZIER: + map = ECORE_POS_MAP_CUBIC_BEZIER; + break; + default: + return compatibility_return(); + } + + std::vector<double> v; + { + auto array = Array::Cast(*args[2]); + auto s = array->Length(); + v.reserve(s); + for (decltype(s) i = 0;i != s;++i) { + auto e = array->Get(i); + if (!e->IsNumber()) + return compatibility_return(); + + v.push_back(e->NumberValue()); + } + } + + auto isolate = args.GetIsolate(); + auto ret = ecore_animator_pos_map_n(args[0]->NumberValue(), map, + v.size(), v.data()); + return compatibility_return(compatibility_new<Number>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_animator_source_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + Ecore_Animator_Source source; + + switch ((int)(args[0]->NumberValue())) { + case ECORE_ANIMATOR_SOURCE_TIMER: + source = ECORE_ANIMATOR_SOURCE_TIMER; + break; + case ECORE_ANIMATOR_SOURCE_CUSTOM: + source = ECORE_ANIMATOR_SOURCE_CUSTOM; + break; + default: + return compatibility_return(); + } + + ecore_animator_source_set(source); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_animator_source_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ecore_animator_source_get(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_animator_add(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Local; + using v8::Value; + using v8::Undefined; + using v8::Function; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto f = new efl::eina::js::global_ref<Value>(isolate, args[0]); + + auto cb = [](void *data) -> Eina_Bool { + auto persistent = static_cast<efl::eina::js::global_ref<Value>*>(data); + auto o = persistent->handle(); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + if (!bret) + { + persistent->dispose(); + delete persistent; + } + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_animator_add(cb, f); + return compatibility_return(wrap_animator(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_animator_timeline_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Handle; + using v8::Local; + using v8::Value; + using v8::Undefined; + using v8::Function; + using v8::FunctionTemplate; + using v8::Number; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 2 || !args[0]->IsNumber() + || !args[1]->IsFunction()) { + return compatibility_return(); + } + + auto f = new efl::eina::js::global_ref<Value>(args.GetIsolate(), args[1]); + + auto cb = [](void *data, double pos) -> Eina_Bool { + auto persistent + = reinterpret_cast<efl::eina::js::global_ref<Value>*>(data); + auto o = persistent->handle(); + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = compatibility_new<Number>(isolate, pos); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 1, &args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + if (!bret) + { + persistent->dispose(); + delete persistent; + } + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_animator_timeline_add(args[0]->NumberValue(), cb, f); + return compatibility_return(wrap_animator(ret, args.GetIsolate()), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_ecore_animator(v8::Isolate* isolate, v8::Handle<v8::Object> exports) +{ + register_pos_map_linear(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP_LINEAR")); + register_pos_map_accelerate(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP" + "_ACCELERATE")); + register_pos_map_decelerate(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP" + "_DECELERATE")); + register_pos_map_sinusoidal(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP" + "_SINUSOIDAL")); + register_pos_map_accelerate_factor(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP" + "_ACCELERATE" + "_FACTOR")); + register_pos_map_decelerate_factor(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP" + "_DECELERATE" + "_FACTOR")); + register_pos_map_sinusoidal_factor(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP" + "_SINUSOIDAL" + "_FACTOR")); + register_pos_map_divisor_interp(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP" + "_DIVISOR_INTERP")); + register_pos_map_bounce(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP_BOUNCE")); + register_pos_map_spring(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP_SPRING")); + register_pos_map_cubic_bezier(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POS_MAP_CUBIC" + "_BEZIER")); + register_animator_source_timer(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_ANIMATOR" + "_SOURCE_TIMER")); + register_animator_frametime_set(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_animator" + "_frametime_set")); + register_animator_frametime_get(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_animator" + "_frametime_get")); + register_animator_pos_map(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_animator_pos" + "_map")); + register_animator_pos_map_n(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_animator_pos_map" + "_n")); + register_animator_source_set(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_animator_source" + "_set")); + register_animator_source_get(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_animator_source" + "_get")); + register_animator_add(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_animator_add")); + register_animator_timeline_add(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_animator" + "_timeline_add")); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/ecore_js/ecore_js_event.cc b/src/bindings/js/ecore_js/ecore_js_event.cc new file mode 100644 index 0000000000..a086d989d6 --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_event.cc @@ -0,0 +1,772 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ecore_Js.hh> + +namespace efl { namespace ecore { namespace js { + +static Ecore_Event *extract_event(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field<Ecore_Event*>(object, 0); +} + +static v8::Local<v8::Object> wrap_event(Ecore_Event *event, + v8::Isolate *isolate) +{ + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_event_del(extract_event(info.This())); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, event); + + return ret; +} + +static Ecore_Event_Handler *extract_event_handler(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field<Ecore_Event_Handler*> + (object, 0); +} + +static v8::Local<v8::Object> wrap_event_handler(Ecore_Event_Handler *handler, + v8::Isolate *isolate) +{ + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + using v8::Value; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto p = ecore_event_handler_del(extract_event_handler(info.This())); + + delete static_cast<efl::eina::js::global_ref<Value>*>(p); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, handler); + + return ret; +} + +static Ecore_Event_Filter *extract_event_filter(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field<Ecore_Event_Filter*> + (object, 0); +} + +static v8::Local<v8::Object> wrap_event_filter(Ecore_Event_Filter *filter, + v8::Isolate *isolate) +{ + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + using v8::Value; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto p = ecore_event_filter_del(extract_event_filter(info.This())); + delete[] static_cast<efl::eina::js::global_ref<Value>*>(p); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, filter); + + return ret; +} + +EAPI +void register_event_none(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_EVENT_NONE)); +} + +EAPI +void register_event_signal_user(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_EVENT_SIGNAL_USER)); +} + +EAPI +void register_event_signal_hup(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_EVENT_SIGNAL_HUP)); +} + +EAPI +void register_event_signal_exit(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_EVENT_SIGNAL_EXIT)); +} + +EAPI +void register_event_signal_power(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_EVENT_SIGNAL_POWER)); +} + +EAPI +void register_event_signal_realtime(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_EVENT_SIGNAL_REALTIME)); +} + +EAPI +void register_event_memory_state(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_EVENT_MEMORY_STATE)); +} + +EAPI +void register_event_power_state(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_EVENT_POWER_STATE)); +} + +EAPI +void register_event_locale_changed(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_EVENT_LOCALE_CHANGED)); +} + +EAPI +void register_event_hostname_changed(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_EVENT_HOSTNAME_CHANGED)); +} + +EAPI +void register_event_system_timedate_changed(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ECORE_EVENT_SYSTEM_TIMEDATE_CHANGED)); +} + +EAPI +void register_event_type_new(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ecore_event_type_new(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_event_add(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ecore_event_add(args[0]->NumberValue(), NULL, NULL, NULL); + return compatibility_return(wrap_event(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_event_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::Value; + using v8::Function; + using v8::Handle; + using v8::Local; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 2 || !args[0]->IsNumber() + || !args[1]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto p = new efl::eina::js::global_ref<Value>(isolate, args[1]); + + auto cb = [](void *d, int type, void */*event*/) -> Eina_Bool { + auto persistent = static_cast<efl::eina::js::global_ref<Value>*>(d); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + Handle<Value> args = compatibility_new<Integer>(isolate, type); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 1, &args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_event_handler_add(args[0]->Int32Value(), cb, p); + return compatibility_return(wrap_event_handler(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_event_filter_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::Value; + using v8::Function; + using v8::Handle; + using v8::Local; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 3 || !args[0]->IsFunction() + || !args[1]->IsFunction() || !args[2]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto p = new efl::eina::js::global_ref<Value>[3]{{isolate, args[0]}, + {isolate, args[1]}, + {isolate, args[2]}}; + + auto start_cb = [](void *data) -> void* { + auto p = static_cast<efl::eina::js::global_ref<Value>*>(data); + auto isolate = v8::Isolate::GetCurrent(); + auto o = p->handle(); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + return new efl::eina::js::global_ref<Value>{isolate, ret}; + }; + + auto filter_cb = [](void *data, void *loop_data, int type, + void */*event*/) -> Eina_Bool { + typedef efl::eina::js::global_ref<Value> p_t; + + auto p = static_cast<p_t*>(data) + 1; + auto isolate = v8::Isolate::GetCurrent(); + auto o = p->handle(); + + Handle<Value> args[2]{ + static_cast<p_t*>(loop_data)->handle(), + compatibility_new<Integer>(isolate, type) + }; + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 2, args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto end_cb = [](void *user_data, void *func_data) -> void { + typedef efl::eina::js::global_ref<Value> p_t; + + auto loop_data = std::unique_ptr<p_t>(static_cast<p_t*> + (func_data)); + auto p = static_cast<p_t*>(user_data) + 2; + auto o = p->handle(); + + Handle<Value> args = p->handle(); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + }; + + auto ret = ecore_event_filter_add(start_cb, filter_cb, end_cb, p); + return compatibility_return(wrap_event_filter(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_event_current_type_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ecore_event_current_type_get(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_memory_state_normal(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_MEMORY_STATE_NORMAL)); +} + +EAPI +void register_memory_state_low(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_MEMORY_STATE_LOW)); +} + +EAPI +void register_power_state_mains(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_POWER_STATE_MAINS)); +} + +EAPI +void register_power_state_battery(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_POWER_STATE_BATTERY)); +} + +EAPI +void register_power_state_low(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ECORE_POWER_STATE_LOW)); +} + +EAPI +void register_memory_state_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ecore_memory_state_get(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_power_state_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ecore_power_state_get(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_event_signal_user_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::String; + using v8::Value; + using v8::Object; + using v8::Function; + using v8::Handle; + using v8::Local; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + + auto p = new efl::eina::js::global_ref<Value>(isolate, args[0]); + + auto cb = [](void *d, int type, void *event) -> Eina_Bool { + auto p = static_cast<efl::eina::js::global_ref<Value>*>(d); + auto isolate = v8::Isolate::GetCurrent(); + auto o = p->handle(); + + auto wrapped_event = compatibility_new<Object>(isolate); + + { + auto n + = reinterpret_cast<Ecore_Event_Signal_User*>(event)->number; + wrapped_event->Set(compatibility_new<String>(isolate, "number"), + compatibility_new<Integer>(isolate, n)); + } + + Handle<Value> args[2]{ + compatibility_new<Integer>(isolate, type), + wrapped_event + }; + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 2, args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER, cb, p); + return compatibility_return(wrap_event_handler(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_event_signal_exit_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::Boolean; + using v8::String; + using v8::Value; + using v8::Object; + using v8::Function; + using v8::Handle; + using v8::Local; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + + auto p = new efl::eina::js::global_ref<Value>(isolate, args[0]); + + auto cb = [](void *d, int type, void *ev) -> Eina_Bool { + auto p = static_cast<efl::eina::js::global_ref<Value>*>(d); + auto isolate = v8::Isolate::GetCurrent(); + auto o = p->handle(); + + auto wrapped_event = compatibility_new<Object>(isolate); + + { + auto event = reinterpret_cast<Ecore_Event_Signal_Exit*>(ev); + auto interrupt = event->interrupt; + auto quit = event->quit; + auto terminate = event->terminate; + + wrapped_event->Set(compatibility_new<String>(isolate, + "interrupt"), + compatibility_new<Boolean>(isolate, + interrupt)); + wrapped_event->Set(compatibility_new<String>(isolate, "quit"), + compatibility_new<Boolean>(isolate, quit)); + wrapped_event->Set(compatibility_new<String>(isolate, + "terminate"), + compatibility_new<Boolean>(isolate, + terminate)); + } + + Handle<Value> args[2]{ + compatibility_new<Integer>(isolate, type), + wrapped_event + }; + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 2, args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, cb, p); + return compatibility_return(wrap_event_handler(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_event_signal_realtime_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::String; + using v8::Value; + using v8::Object; + using v8::Function; + using v8::Handle; + using v8::Local; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + + auto p = new efl::eina::js::global_ref<Value>(isolate, args[0]); + + auto cb = [](void *d, int type, void *ev) -> Eina_Bool { + auto p = static_cast<efl::eina::js::global_ref<Value>*>(d); + auto isolate = v8::Isolate::GetCurrent(); + auto o = p->handle(); + + auto wrapped_event = compatibility_new<Object>(isolate); + + { + auto n + = reinterpret_cast<Ecore_Event_Signal_Realtime*>(ev)->num; + wrapped_event->Set(compatibility_new<String>(isolate, "num"), + compatibility_new<Integer>(isolate, n)); + } + + Handle<Value> args[2]{ + compatibility_new<Integer>(isolate, type), + wrapped_event + }; + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 2, args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_event_handler_add(ECORE_EVENT_SIGNAL_REALTIME, cb, p); + return compatibility_return(wrap_event_handler(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_ecore_event(v8::Isolate* isolate, v8::Handle<v8::Object> exports) +{ + register_event_none(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_EVENT_NONE")); + register_event_signal_user(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_EVENT_SIGNAL_USER")); + register_event_signal_hup(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_EVENT_SIGNAL_HUP")); + register_event_signal_exit(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_EVENT_SIGNAL_EXIT")); + register_event_signal_power(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_EVENT_SIGNAL_POWER")); + register_event_signal_realtime(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_EVENT_SIGNAL_REALTIME")); + register_event_memory_state(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_EVENT_MEMORY_STATE")); + register_event_power_state(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_EVENT_POWER_STATE")); + register_event_locale_changed(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_EVENT_LOCALE_CHANGED")); + register_event_hostname_changed(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_EVENT_HOSTNAME_CHANGED")); + register_event_system_timedate_changed(isolate, exports, + compatibility_new<v8::String> + (isolate, + "ECORE_EVENT_SYSTEM_TIMEDATE" + "_CHANGED")); + register_event_type_new(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_event_type_new")); + register_event_add(isolate, exports, + compatibility_new<v8::String>(isolate, "ecore_event_add")); + register_event_handler_add(isolate, exports, + compatibility_new<v8::String> + (isolate, "ecore_event_handler_add")); + register_event_filter_add(isolate, exports, + compatibility_new<v8::String> + (isolate, "ecore_event_filter_add")); + register_event_current_type_get(isolate, exports, + compatibility_new<v8::String> + (isolate, "ecore_event_current_type_get")); + register_memory_state_normal(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_MEMORY_STATE_NORMAL")); + register_memory_state_low(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_MEMORY_STATE_LOW")); + register_power_state_mains(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_POWER_STATE_MAINS")); + register_power_state_battery(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_POWER_STATE_BATTERY")); + register_power_state_low(isolate, exports, + compatibility_new<v8::String>(isolate, + "ECORE_POWER_STATE_LOW")); + register_event_signal_user_handler_add(isolate, exports, + compatibility_new<v8::String> + (isolate, + "ecore_event_signal_user_handler" + "_add")); + register_event_signal_exit_handler_add(isolate, exports, + compatibility_new<v8::String> + (isolate, + "ecore_event_signal_exit_handler" + "_add")); + register_event_signal_realtime_handler_add(isolate, exports, + compatibility_new<v8::String> + (isolate, + "ecore_event_signal_realtime" + "_handler_add")); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/ecore_js/ecore_js_idle.cc b/src/bindings/js/ecore_js/ecore_js_idle.cc new file mode 100644 index 0000000000..293cef2f45 --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_idle.cc @@ -0,0 +1,294 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ecore_Js.hh> + +namespace efl { namespace ecore { namespace js { + +static Ecore_Idler* extract_idler(v8::Local<v8::Object> object) +{ + auto ptr = v8::External::Cast(*object->GetInternalField(0))->Value(); + return reinterpret_cast<Ecore_Idler*>(ptr); +} + +static +v8::Local<v8::Object> wrap_idler(Ecore_Idler *idler, v8::Isolate *isolate) +{ + using v8::Boolean; + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_idler_del(extract_idler(info.This())); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + ret->SetInternalField(0, compatibility_new<v8::External>(isolate, idler)); + + return ret; +} + +static Ecore_Idle_Enterer* extract_idle_enterer(v8::Local<v8::Object> object) +{ + auto ptr = v8::External::Cast(*object->GetInternalField(0))->Value(); + return reinterpret_cast<Ecore_Idle_Enterer*>(ptr); +} + +static v8::Local<v8::Object> wrap_idle_enterer(Ecore_Idle_Enterer *idle_enterer, + v8::Isolate *isolate) +{ + using v8::Boolean; + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + using v8::External; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_idle_enterer_del(extract_idle_enterer(info.This())); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + ret->SetInternalField(0, + compatibility_new<External>(isolate, idle_enterer)); + + return ret; +} + +static Ecore_Idle_Exiter* extract_idle_exiter(v8::Local<v8::Object> object) +{ + auto ptr = v8::External::Cast(*object->GetInternalField(0))->Value(); + return reinterpret_cast<Ecore_Idle_Exiter*>(ptr); +} + +static v8::Local<v8::Object> wrap_idle_exiter(Ecore_Idle_Exiter *idle_exiter, + v8::Isolate *isolate) +{ + using v8::Boolean; + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + using v8::External; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_idle_exiter_del(extract_idle_exiter(info.This())); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + ret->SetInternalField(0, compatibility_new<External>(isolate, idle_exiter)); + + return ret; +} + +void register_idler_add(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Local; + using v8::Value; + using v8::Undefined; + using v8::Function; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto f = new efl::eina::js::global_ref<Value>(args.GetIsolate(), args[0]); + auto ret = ecore_idler_add([](void *data) -> Eina_Bool { + auto persistent = static_cast<efl::eina::js::global_ref<Value>*>(data); + auto o = persistent->handle(); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + if (!bret) + { + persistent->dispose(); + delete persistent; + } + + return bret ? EINA_TRUE : EINA_FALSE; + }, f); + + return compatibility_return(wrap_idler(ret, args.GetIsolate()), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_idle_enterer_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Local; + using v8::Value; + using v8::Undefined; + using v8::Function; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto f = new efl::eina::js::global_ref<Value>(args.GetIsolate(), args[0]); + auto ret = ecore_idle_enterer_add([](void *data) -> Eina_Bool { + auto persistent = static_cast<efl::eina::js::global_ref<Value>*>(data); + auto o = persistent->handle(); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + if (!bret) + { + persistent->dispose(); + delete persistent; + } + + return bret ? EINA_TRUE : EINA_FALSE; + }, f); + + return compatibility_return(wrap_idle_enterer(ret, args.GetIsolate()), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_idle_enterer_before_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Local; + using v8::Value; + using v8::Undefined; + using v8::Function; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto f = new efl::eina::js::global_ref<Value>(args.GetIsolate(), args[0]); + auto ret = ecore_idle_enterer_before_add([](void *data) -> Eina_Bool { + auto persistent = static_cast<efl::eina::js::global_ref<Value>*>(data); + auto o = persistent->handle(); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + if (!bret) + { + persistent->dispose(); + delete persistent; + } + + return bret ? EINA_TRUE : EINA_FALSE; + }, f); + + return compatibility_return(wrap_idle_enterer(ret, args.GetIsolate()), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_idle_exiter_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Local; + using v8::Value; + using v8::Undefined; + using v8::Function; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto f = new efl::eina::js::global_ref<Value>(args.GetIsolate(), args[0]); + auto ret = ecore_idle_exiter_add([](void *data) -> Eina_Bool { + auto persistent = static_cast<efl::eina::js::global_ref<Value>*>(data); + auto o = persistent->handle(); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + if (!bret) + { + persistent->dispose(); + delete persistent; + } + + return bret ? EINA_TRUE : EINA_FALSE; + }, f); + + return compatibility_return(wrap_idle_exiter(ret, args.GetIsolate()), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_ecore_idle(v8::Isolate *isolate,v8::Handle<v8::Object> exports) +{ + register_idler_add(isolate, exports, + compatibility_new<v8::String>(isolate, "ecore_idler_add")); + register_idle_enterer_add(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_idle_enterer" + "_add")); + register_idle_enterer_before_add(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_idle" + "_enterer_before" + "_add")); + register_idle_exiter_add(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_idle_exiter_add")); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/ecore_js/ecore_js_init.cc b/src/bindings/js/ecore_js/ecore_js_init.cc new file mode 100644 index 0000000000..ba2b04f842 --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_init.cc @@ -0,0 +1,76 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ecore_Js.hh> + +namespace efl { namespace ecore { namespace js { + +namespace { + +void register_init(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto init = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ::ecore_init(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, init) + ->GetFunction()); +} + +void register_shutdown(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto shutdown = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ecore_shutdown(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, shutdown) + ->GetFunction()); +} + +} + +EAPI +void register_ecore(v8::Isolate *isolate,v8::Handle<v8::Object> exports) +{ + efl::ecore::js::register_init(isolate, exports, + efl::eina::js::compatibility_new<v8::String> + (isolate, "ecore_init")); + efl::ecore::js::register_shutdown(isolate, exports, + efl::eina::js::compatibility_new<v8::String> + (isolate, "ecore_shutdown")); + register_ecore_animator(isolate, exports); + register_ecore_event(isolate, exports); + register_ecore_idle(isolate, exports); + register_ecore_job(isolate, exports); + register_ecore_mainloop(isolate, exports); + register_ecore_poller(isolate, exports); + register_ecore_throttle(isolate, exports); + register_ecore_timer(isolate, exports); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/ecore_js/ecore_js_job.cc b/src/bindings/js/ecore_js/ecore_js_job.cc new file mode 100644 index 0000000000..4ec438aaaf --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_job.cc @@ -0,0 +1,83 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ecore_Js.hh> + +namespace efl { namespace ecore { namespace js { + +static Ecore_Job* extract_job(v8::Local<v8::Object> object) +{ + auto ptr = v8::External::Cast(*object->GetInternalField(0))->Value(); + return reinterpret_cast<Ecore_Job*>(ptr); +} + +static v8::Local<v8::Object> wrap_job(Ecore_Job *job, v8::Isolate *isolate) +{ + using v8::Boolean; + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_job_del(extract_job(info.This())); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + ret->SetInternalField(0, compatibility_new<v8::External>(isolate, job)); + + return ret; +} + +EAPI +void register_job_add(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Local; + using v8::Value; + using v8::Undefined; + using v8::Function; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto f = new efl::eina::js::global_ref<Value>(args.GetIsolate(), args[0]); + auto ret = ecore_job_add([](void *data) { + auto persistent = static_cast<efl::eina::js::global_ref<Value>*>(data); + auto o = persistent->handle(); + + Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + + persistent->dispose(); + delete persistent; + }, f); + + return compatibility_return(wrap_job(ret, args.GetIsolate()), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_ecore_job(v8::Isolate *isolate,v8::Handle<v8::Object> exports) +{ + register_job_add(isolate, exports, + compatibility_new<v8::String>(isolate, "ecore_job_add")); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/ecore_js/ecore_js_mainloop.cc b/src/bindings/js/ecore_js/ecore_js_mainloop.cc new file mode 100644 index 0000000000..180b35f0f6 --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_mainloop.cc @@ -0,0 +1,207 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ecore_Js.hh> + +namespace efl { namespace ecore { namespace js { + +namespace { + +void register_callback_cancel(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Boolean; + global->Set(name, compatibility_new<Boolean>(isolate, + bool{ECORE_CALLBACK_CANCEL})); +} + +void register_callback_renew(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Boolean; + global->Set(name, compatibility_new<Boolean>(isolate, + bool{ECORE_CALLBACK_RENEW})); +} + +void register_callback_pass_on(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Boolean; + global->Set(name, compatibility_new<Boolean>(isolate, + bool{ECORE_CALLBACK_PASS_ON})); +} + +void register_callback_done(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Boolean; + global->Set(name, compatibility_new<Boolean>(isolate, + bool{ECORE_CALLBACK_DONE})); +} + +void register_mainloop_iterate(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + ecore_main_loop_iterate(); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_mainloop_iterate_may_block(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + auto ret = ecore_main_loop_iterate_may_block(args[0]->NumberValue()); + return compatibility_return(compatibility_new<Integer> + (args.GetIsolate(), ret), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_mainloop_begin(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + ecore_main_loop_begin(); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_mainloop_quit(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + ecore_main_loop_quit(); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_mainloop_animator_ticked_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Boolean; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto ret = ecore_main_loop_animator_ticked_get(); + return compatibility_return(compatibility_new<Boolean> + (args.GetIsolate(), ret), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_mainloop_nested_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Boolean; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto ret = ecore_main_loop_nested_get(); + return compatibility_return(compatibility_new<Boolean> + (args.GetIsolate(), ret), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +} + +EAPI +void register_ecore_mainloop(v8::Isolate *isolate,v8::Handle<v8::Object> exports) +{ + register_callback_cancel(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_CALLBACK_CANCEL")); + register_callback_renew(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_CALLBACK_RENEW")); + register_callback_pass_on(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_CALLBACK_PASS_ON")); + register_callback_done(isolate, exports, + compatibility_new<v8::String> + (isolate, "ECORE_CALLBACK_DONE")); + register_mainloop_iterate(isolate, exports, + compatibility_new<v8::String> + (isolate, "ecore_mainloop_iterate")); + register_mainloop_iterate_may_block(isolate, exports, + compatibility_new<v8::String> + (isolate, + "ecore_mainloop_iterate_may_block")); + register_mainloop_begin(isolate, exports, + compatibility_new<v8::String> + (isolate, "ecore_mainloop_begin")); + register_mainloop_quit(isolate, exports, + compatibility_new<v8::String> + (isolate, "ecore_mainloop_quit")); + register_mainloop_animator_ticked_get(isolate, exports, + compatibility_new<v8::String> + (isolate, + "ecore_mainlop_animator_ticked_get")); + register_mainloop_nested_get(isolate, exports, + compatibility_new<v8::String> + (isolate, "ecore_mainloop_nested_get")); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/ecore_js/ecore_js_poller.cc b/src/bindings/js/ecore_js/ecore_js_poller.cc new file mode 100644 index 0000000000..e3bfbc843a --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_poller.cc @@ -0,0 +1,190 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ecore_Js.hh> + +namespace efl { namespace ecore { namespace js { + +namespace { + +Ecore_Poller* extract_poller(v8::Local<v8::Object> object) +{ + auto ptr = v8::External::Cast(*object->GetInternalField(0))->Value(); + return reinterpret_cast<Ecore_Poller*>(ptr); +} + +v8::Local<v8::Object> wrap_poller(Ecore_Poller *poller, + v8::Isolate *isolate) +{ + using v8::Boolean; + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_poller_del(extract_poller(info.This())); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + ret->SetInternalField(0, compatibility_new<v8::External>(isolate, poller)); + + return ret; +} + +void register_poller_core(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + + global->Set(name, compatibility_new<Integer>(isolate, ECORE_POLLER_CORE)); +} + +void register_poller_poll_interval_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) + return compatibility_return(); + + Ecore_Poller_Type type; + + switch ((int)(args[0]->NumberValue())) { + case ECORE_POLLER_CORE: + type = ECORE_POLLER_CORE; + break; + default: + return compatibility_return(); + } + + ecore_poller_poll_interval_set(type, args[1]->NumberValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_poller_poll_interval_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + Ecore_Poller_Type type; + + switch ((int)(args[0]->NumberValue())) { + case ECORE_POLLER_CORE: + type = ECORE_POLLER_CORE; + break; + default: + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + auto ret = ecore_poller_poll_interval_get(type); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_poller_add(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::Value; + using v8::FunctionTemplate; + using v8::Isolate; + using v8::Function; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 3 || !args[0]->IsNumber() || !args[1]->IsNumber() + || !args[2]->IsFunction()) { + return compatibility_return(); + } + + Ecore_Poller_Type type; + + switch ((int)(args[0]->NumberValue())) { + case ECORE_POLLER_CORE: + type = ECORE_POLLER_CORE; + break; + default: + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + auto f = new efl::eina::js::global_ref<Value>(isolate, args[2]); + + auto cb = [](void *data) -> Eina_Bool { + auto persistent = static_cast<efl::eina::js::global_ref<Value>*>(data); + auto o = persistent->handle(); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + if (!bret) + { + persistent->dispose(); + delete persistent; + } + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_poller_add(type, args[1]->NumberValue(), cb, f); + return compatibility_return(wrap_poller(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +} + +EAPI +void register_ecore_poller(v8::Isolate *isolate,v8::Handle<v8::Object> exports) +{ + register_poller_core(isolate, exports, + compatibility_new<v8::String>(isolate, "ECORE_POLLER_CORE")); + register_poller_poll_interval_set(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_poller" + "_poll_interval" + "_set")); + register_poller_poll_interval_get(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_poller" + "_poll_interval" + "_get")); + register_poller_add(isolate, exports, + compatibility_new<v8::String>(isolate, "ecore_poller_add")); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/ecore_js/ecore_js_throttle.cc b/src/bindings/js/ecore_js/ecore_js_throttle.cc new file mode 100644 index 0000000000..830a40fec6 --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_throttle.cc @@ -0,0 +1,63 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ecore_Js.hh> + +namespace efl { namespace ecore { namespace js { + +namespace { + +void register_throttle_adjust(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + ecore_throttle_adjust(args[0]->NumberValue()); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_throttle_get(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Number; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ecore_throttle_get(); + return compatibility_return(compatibility_new<Number>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +} + +EAPI +void register_ecore_throttle(v8::Isolate *isolate,v8::Handle<v8::Object> exports) +{ + register_throttle_adjust(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_throttle_adjust")); + register_throttle_get(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_throttle_get")); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/ecore_js/ecore_js_timer.cc b/src/bindings/js/ecore_js/ecore_js_timer.cc new file mode 100644 index 0000000000..f22100c6a7 --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_timer.cc @@ -0,0 +1,232 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ecore_Js.hh> + +#include <memory> +#include <cstdlib> + +namespace efl { namespace ecore { namespace js { + +namespace { + +Ecore_Timer* extract_timer(v8::Local<v8::Object> object) +{ + auto ptr = v8::External::Cast(*object->GetInternalField(0))->Value(); + return reinterpret_cast<Ecore_Timer*>(ptr); +} + +v8::Local<v8::Object> wrap_timer(Ecore_Timer *timer, + v8::Isolate *isolate) +{ + using v8::Boolean; + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_timer_del(extract_timer(info.This())); + return compatibility_return(); + }; + + auto freeze = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_timer_freeze(extract_timer(info.This())); + return compatibility_return(); + }; + + auto freeze_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto ret = ecore_timer_freeze_get(extract_timer(info.This())); + return compatibility_return(compatibility_new<Boolean> + (info.GetIsolate(), bool(ret)), + info); + }; + + auto thaw = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ecore_timer_thaw(extract_timer(info.This())); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "freeze"), + compatibility_new<FunctionTemplate>(isolate, freeze) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "freeze_get"), + compatibility_new<FunctionTemplate>(isolate, freeze_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "thaw"), + compatibility_new<FunctionTemplate>(isolate, thaw)->GetFunction()); + + ret->SetInternalField(0, compatibility_new<v8::External>(isolate, timer)); + + return ret; +} + +void register_timer_precision_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Number; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto ret = ecore_timer_precision_get(); + return compatibility_return(compatibility_new<Number> + (args.GetIsolate(), ret), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_timer_precision_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + ecore_timer_precision_set(args[0]->NumberValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_timer_add(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Local; + using v8::Value; + using v8::Undefined; + using v8::Function; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 2 || !args[0]->IsNumber() + || !args[1]->IsFunction()) { + return compatibility_return(); + } + + auto f = new efl::eina::js::global_ref<Value>(args.GetIsolate(), args[1]); + + auto cb = [](void *data) -> Eina_Bool { + auto persistent = reinterpret_cast<efl::eina::js::global_ref<Value>*>(data); + auto o = persistent->handle(); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + if (!bret) + { + persistent->dispose(); + delete persistent; + } + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_timer_add(args[0]->NumberValue(), cb, f); + return compatibility_return(wrap_timer(ret, args.GetIsolate()), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_timer_loop_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Local; + using v8::Value; + using v8::Undefined; + using v8::Function; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 2 || !args[0]->IsNumber() + || !args[1]->IsFunction()) { + return compatibility_return(); + } + + auto f = new efl::eina::js::global_ref<Value>(args.GetIsolate(), args[1]); + + auto cb = [](void *d) -> Eina_Bool { + auto persistent = static_cast<efl::eina::js::global_ref<Value>*>(d); + auto o = persistent->handle(); + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 0, NULL); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + if (!bret) + { + persistent->dispose(); + delete persistent; + } + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_timer_loop_add(args[0]->NumberValue(), cb, f); + + return compatibility_return(wrap_timer(ret, args.GetIsolate()), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +} + +EAPI +void register_ecore_timer(v8::Isolate *isolate,v8::Handle<v8::Object> exports) +{ + register_timer_precision_get(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_timer_precision" + "_get")); + register_timer_precision_set(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_timer_precision" + "_set")); + register_timer_add(isolate, exports, + compatibility_new<v8::String>(isolate, "ecore_timer_add")); + register_timer_loop_add(isolate, exports, + compatibility_new<v8::String>(isolate, + "ecore_timer_loop_add")); +} + +} } } // namespace efl { namespace ecore { namespace js { diff --git a/src/bindings/js/ecore_js/ecore_js_timer.hh b/src/bindings/js/ecore_js/ecore_js_timer.hh new file mode 100644 index 0000000000..e002587ee4 --- /dev/null +++ b/src/bindings/js/ecore_js/ecore_js_timer.hh @@ -0,0 +1,38 @@ +#ifndef ECORE_JS_TIMER_HH +#define ECORE_JS_TIMER_HH + +#include <Eina.hh> + +#include <Eina_Js.hh> + +namespace efl { namespace ecore { namespace js { + +using ::efl::eina::js::compatibility_new; +using ::efl::eina::js::compatibility_return_type; +using ::efl::eina::js::compatibility_callback_info_type; +using ::efl::eina::js::compatibility_return; +using ::efl::eina::js::compatibility_get_pointer_internal_field; +using ::efl::eina::js::compatibility_set_pointer_internal_field; +using ::efl::eina::js::compatibility_persistent; + +void register_timer_precision_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_timer_precision_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_timer_dump(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_timer_add(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_timer_loop_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +} } } // namespace efl::js + +#endif /* ECORE_JS_TIMER_HH */ diff --git a/src/bindings/js/efl_js/Efl_Js.hh b/src/bindings/js/efl_js/Efl_Js.hh new file mode 100644 index 0000000000..f494b385ce --- /dev/null +++ b/src/bindings/js/efl_js/Efl_Js.hh @@ -0,0 +1,30 @@ +#ifndef EFL_EFL_JS_HH +#define EFL_EFL_JS_HH + +#include <Eina.hh> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# define EAPI __declspec(dllexport) +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +namespace efl_js { + +EAPI void init(v8::Handle<v8::Object> exports); + +} + +#endif diff --git a/src/bindings/js/efl_js/efl_js.cc b/src/bindings/js/efl_js/efl_js.cc new file mode 100644 index 0000000000..5665559b65 --- /dev/null +++ b/src/bindings/js/efl_js/efl_js.cc @@ -0,0 +1,241 @@ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Efl.h> +#include <Efl_Config.h> +#include <Ecore.h> +#include <Ecore_Evas.h> +#include <Eina.hh> +#include <Eina_Js.hh> +#include <Ecore_Js.hh> +#include <Eio_Js.hh> +#include <Eldbus_Js.hh> +#include <Ethumb_Js.hh> + +#include <iostream> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# define EAPI __declspec(dllexport) +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +EAPI void eina_container_register(v8::Handle<v8::Object>, v8::Isolate* isolate); +EAPI void eina_log_register(v8::Handle<v8::Object>, v8::Isolate* isolate); +EAPI void eina_value_register(v8::Handle<v8::Object>, v8::Isolate* isolate); +EAPI void register_ecore_mainloop(v8::Handle<v8::Object> global, v8::Isolate* isolate); + +namespace ecore { +EAPI void register_exe(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_idler(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_ecore(v8::Isolate* isolate, v8::Handle<v8::Object> exports); +namespace idle { +EAPI void register_enterer(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_exiter(v8::Handle<v8::Object> global, v8::Isolate* isolate); +} +EAPI void register_job(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_parent(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_poller(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_timer(v8::Handle<v8::Object> global, v8::Isolate* isolate); +namespace con { +EAPI void register_base(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_client(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_connector(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_server(v8::Handle<v8::Object> global, v8::Isolate* isolate); +} +} + +namespace efl { namespace network { +EAPI void register_url(v8::Handle<v8::Object> global, v8::Isolate* isolate); +}} + +EAPI void register_ecore_audio(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_ecore_audio_in(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_ecore_audio_in_sndfile(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_ecore_audio_in_tone(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_ecore_audio_out(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_ecore_audio_out_pulse(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_ecore_audio_out_sndfile(v8::Handle<v8::Object> global, v8::Isolate* isolate); + +namespace efl { +EAPI void register_control(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_file(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_image(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_player(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_text(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_text_properties(v8::Handle<v8::Object> global, v8::Isolate* isolate); +} + +namespace eo { +EAPI void register_abstract_class(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_base(v8::Handle<v8::Object> global, v8::Isolate* isolate); +} + +namespace evas { +EAPI void register_box(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_canvas(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_clickable_interface(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_common_interface(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_draggable_interface(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_grid(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_image(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_line(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_object(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_object_smart(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_out(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_polygon(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_rectangle(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_scrollable_interface(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_selectable_interface(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_signal_interface(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_smart_clipped(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_table(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_text(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_textblock(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_textgrid(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_zoomable_interface(v8::Handle<v8::Object> global, v8::Isolate* isolate); + +namespace canvas3d { +EAPI void register_camera(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_light(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_material(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_mesh(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_node(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_object(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_scene(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_texture(v8::Handle<v8::Object> global, v8::Isolate* isolate); +} } + +namespace edje { +EAPI void register_edit(v8::Handle<v8::Object> global, v8::Isolate* isolate); +EAPI void register_object(v8::Handle<v8::Object> global, v8::Isolate* isolate); +} + +namespace emotion { +EAPI void register_object(v8::Handle<v8::Object> global, v8::Isolate* isolate); +} + +#ifdef HAVE_NODEJS + +#include <eina_js_node.hh> + +namespace { +#else +namespace efl_js { +#endif + +EAPI void init(v8::Handle<v8::Object> exports) +{ + ::eina_init(); + ::ecore_init(); + ::ecore_file_init(); + ::ecore_evas_init(); + ::eo_init(); + ::eio_init(); + ::evas_init(); + try + { + eina_container_register(exports, v8::Isolate::GetCurrent()); + eina_log_register(exports, v8::Isolate::GetCurrent()); + eina_value_register(exports, v8::Isolate::GetCurrent()); + register_ecore_mainloop(exports, v8::Isolate::GetCurrent()); + efl::ecore::js::register_ecore(v8::Isolate::GetCurrent(), exports); + efl::eio::js::register_eio(v8::Isolate::GetCurrent(), exports); + efl::eldbus::js::register_eldbus(v8::Isolate::GetCurrent(), exports); + efl::ethumb::js::register_ethumb(v8::Isolate::GetCurrent(), exports); + ecore::register_exe(exports, v8::Isolate::GetCurrent()); + ecore::register_idler(exports, v8::Isolate::GetCurrent()); + ecore::idle::register_enterer(exports, v8::Isolate::GetCurrent()); + ecore::idle::register_exiter(exports, v8::Isolate::GetCurrent()); + ecore::register_job(exports, v8::Isolate::GetCurrent()); + ecore::register_parent(exports, v8::Isolate::GetCurrent()); + ecore::register_poller(exports, v8::Isolate::GetCurrent()); + ecore::register_timer(exports, v8::Isolate::GetCurrent()); + ecore::con::register_base(exports, v8::Isolate::GetCurrent()); + ecore::con::register_client(exports, v8::Isolate::GetCurrent()); + ecore::con::register_connector(exports, v8::Isolate::GetCurrent()); + ecore::con::register_server(exports, v8::Isolate::GetCurrent()); + efl::network::register_url(exports, v8::Isolate::GetCurrent()); +#if 1 + register_ecore_audio(exports, v8::Isolate::GetCurrent()); + register_ecore_audio_in(exports, v8::Isolate::GetCurrent()); + register_ecore_audio_in_sndfile(exports, v8::Isolate::GetCurrent()); + register_ecore_audio_in_tone(exports, v8::Isolate::GetCurrent()); + register_ecore_audio_out(exports, v8::Isolate::GetCurrent()); + register_ecore_audio_out_pulse(exports, v8::Isolate::GetCurrent()); + register_ecore_audio_out_sndfile(exports, v8::Isolate::GetCurrent()); +#endif + efl::register_control(exports, v8::Isolate::GetCurrent()); + efl::register_file(exports, v8::Isolate::GetCurrent()); + efl::register_image(exports, v8::Isolate::GetCurrent()); + efl::register_player(exports, v8::Isolate::GetCurrent()); + efl::register_text(exports, v8::Isolate::GetCurrent()); + efl::register_text_properties(exports, v8::Isolate::GetCurrent()); + eo::register_abstract_class(exports, v8::Isolate::GetCurrent()); + eo::register_base(exports, v8::Isolate::GetCurrent()); +#if 1 + evas::register_box(exports, v8::Isolate::GetCurrent()); + evas::register_canvas(exports, v8::Isolate::GetCurrent()); + evas::register_clickable_interface(exports, v8::Isolate::GetCurrent()); + evas::register_common_interface(exports, v8::Isolate::GetCurrent()); + evas::register_draggable_interface(exports, v8::Isolate::GetCurrent()); + evas::register_grid(exports, v8::Isolate::GetCurrent()); + evas::register_image(exports, v8::Isolate::GetCurrent()); + evas::register_line(exports, v8::Isolate::GetCurrent()); + evas::register_object(exports, v8::Isolate::GetCurrent()); + evas::register_object_smart(exports, v8::Isolate::GetCurrent()); + evas::register_out(exports, v8::Isolate::GetCurrent()); + evas::register_polygon(exports, v8::Isolate::GetCurrent()); + evas::register_rectangle(exports, v8::Isolate::GetCurrent()); + evas::register_scrollable_interface(exports, v8::Isolate::GetCurrent()); + evas::register_selectable_interface(exports, v8::Isolate::GetCurrent()); + evas::register_signal_interface(exports, v8::Isolate::GetCurrent()); + evas::register_smart_clipped(exports, v8::Isolate::GetCurrent()); + evas::register_table(exports, v8::Isolate::GetCurrent()); + evas::register_text(exports, v8::Isolate::GetCurrent()); + evas::register_textblock(exports, v8::Isolate::GetCurrent()); + evas::register_textgrid(exports, v8::Isolate::GetCurrent()); + evas::register_zoomable_interface(exports, v8::Isolate::GetCurrent()); + evas::canvas3d::register_camera(exports, v8::Isolate::GetCurrent()); + evas::canvas3d::register_light(exports, v8::Isolate::GetCurrent()); + evas::canvas3d::register_material(exports, v8::Isolate::GetCurrent()); + evas::canvas3d::register_mesh(exports, v8::Isolate::GetCurrent()); + evas::canvas3d::register_node(exports, v8::Isolate::GetCurrent()); + evas::canvas3d::register_object(exports, v8::Isolate::GetCurrent()); + evas::canvas3d::register_scene(exports, v8::Isolate::GetCurrent()); + evas::canvas3d::register_texture(exports, v8::Isolate::GetCurrent()); +#endif +#if 1 + edje::register_edit(exports, v8::Isolate::GetCurrent()); + edje::register_object(exports, v8::Isolate::GetCurrent()); +#endif +#if 1 + emotion::register_object(exports, v8::Isolate::GetCurrent()); +#endif + } + catch(...) + { + std::cout << "Exception" << std::endl; + } +} + +#ifdef HAVE_NODEJS +} +NODE_MODULE(efl, init) +#else +} // namespace efl +#endif diff --git a/src/bindings/js/eina_js/Eina_Js.hh b/src/bindings/js/eina_js/Eina_Js.hh new file mode 100644 index 0000000000..b193b5461c --- /dev/null +++ b/src/bindings/js/eina_js/Eina_Js.hh @@ -0,0 +1,50 @@ + +#ifndef EFL_EINA_JS_HH +#define EFL_EINA_JS_HH + +#include <Eina.hh> +#include <eo_concrete.hh> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EINA_JS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +#include <eina_js_container.hh> +#include <eina_js_accessor.hh> +#include <eina_js_array.hh> +#include <eina_js_compatibility.hh> +#include <eina_js_error.hh> +#include <eina_js_get_value_from_c.hh> +#include <eina_js_get_value.hh> +#include <eina_js_iterator.hh> +#include <eina_js_list.hh> +#include <eina_js_log.hh> +#include <eina_js_value.hh> +#include <eina_js_log.hh> + +#undef EAPI +#define EAPI + +#endif diff --git a/src/bindings/js/eina_js/eina_js_accessor.cc b/src/bindings/js/eina_js/eina_js_accessor.cc new file mode 100644 index 0000000000..d6891547ed --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_accessor.cc @@ -0,0 +1,34 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eina.hh> + +#include <Eina_Js.hh> + +#include <iostream> + +namespace efl { namespace eina { namespace js { + +EAPI void register_destroy_accessor(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + typedef void (*deleter_t)(void*); + + auto f = [](compatibility_callback_info_type info) -> compatibility_return_type + { + if (info.Length() != 1 || !info[0]->IsObject()) + return compatibility_return(); + + v8::Handle<v8::Object> o = info[0]->ToObject(); + + deleter_t deleter = compatibility_get_pointer_internal_field<deleter_t>(o, 1); + deleter(compatibility_get_pointer_internal_field<>(o, 0)); + return compatibility_return(); + }; + + global->Set(name, compatibility_new<v8::FunctionTemplate>(isolate, f)->GetFunction()); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/eina_js/eina_js_accessor.hh b/src/bindings/js/eina_js/eina_js_accessor.hh new file mode 100644 index 0000000000..abf3090fed --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_accessor.hh @@ -0,0 +1,87 @@ +#ifndef EINA_JS_ACCESSOR_HH +#define EINA_JS_ACCESSOR_HH + +#include <memory> + +#include <eina_js_value.hh> +#include <eina_js_compatibility.hh> +#include <eina_js_get_value.hh> +#include <eina_js_get_value_from_c.hh> + +#include <iostream> + +namespace efl { namespace eina { namespace js { + +template <typename T, typename A> +js::compatibility_return_type accessor_get(js::compatibility_callback_info_type info) +{ + v8::Isolate* isolate = info.GetIsolate(); + if (info.Length() != 1 || !info[0]->IsNumber()) + return js::compatibility_return(); + + auto idx = js::get_value_from_javascript + (info[0], isolate, "", js::value_tag<std::size_t>()); + + std::string class_name; + if (info.Data()->IsString()) + { + v8::String::Utf8Value str(info.Data()); + class_name = *str; + } + + void *ptr = compatibility_get_pointer_internal_field(info.Holder(), 0); + + return compatibility_return + (::efl::eina::js::get_value_from_c + (js::wrap_value<T>(container_unwrap((*static_cast<A*>(ptr))[idx]), js::value_tag<T>{}) + , isolate, class_name.c_str()), info); +}; + +/* Creates a copy from \p a accessor and exports it to be manipulated by the JS + code */ +template <typename T, typename W> +inline v8::Local<v8::Object> export_accessor(::efl::eina::accessor<W> &a, v8::Isolate *isolate, const char* class_name) +{ + typedef ::efl::eina::accessor<W> accessor_type; + + static efl::eina::js::global_ref<v8::ObjectTemplate> obj_tpl + (isolate, + [&]() + { + auto obj_tpl = compatibility_new<v8::ObjectTemplate>(isolate); + (*obj_tpl)->SetInternalFieldCount(1); + + // TODO: (*obj_tpl)->SetIndexedPropertyHandler(&accessor_get<accessor_type>); + + (*obj_tpl)->Set(js::compatibility_new<v8::String>(isolate, "get") + , js::compatibility_new<v8::FunctionTemplate>(isolate + , &accessor_get<T, accessor_type> + , js::compatibility_new<v8::String>(isolate, class_name))); + return obj_tpl; + }()); + + auto instance = obj_tpl.handle()->NewInstance(); + compatibility_set_pointer_internal_field(instance, 0, &a); + return instance; +} + +/* Extracts and returns a copy from the internal accessor object from the JS + object */ +template <typename T> +::efl::eina::accessor<T>& import_accessor(v8::Handle<v8::Object> o) +{ + typedef ::efl::eina::accessor<T> accessor_type; + + void* ptr = compatibility_get_pointer_internal_field(o, 0); + + return *static_cast<accessor_type*>(ptr); +} + +/* Registers the function to destroy the accessor objects to the JS code */ +void register_destroy_accessor(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +} } } // namespace efl::js + +#endif /* EINA_JS_ACCESSOR_HH */ diff --git a/src/bindings/js/eina_js/eina_js_array.hh b/src/bindings/js/eina_js/eina_js_array.hh new file mode 100644 index 0000000000..9cdd142e7c --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_array.hh @@ -0,0 +1,119 @@ +#ifndef EINA_JS_ARRAY_HH +#define EINA_JS_ARRAY_HH + +#include <iostream> + +#include <iterator> + +#include <eina_js_container.hh> + +namespace efl { namespace eina { namespace js { + +template <typename T, typename K, typename W> +struct eina_array : eina_container_common<efl::eina::array + <W + , typename std::conditional + <std::is_base_of<efl::eo::concrete, W>::value + , efl::eina::eo_clone_allocator + , efl::eina::malloc_clone_allocator + >::type>, T, K> +{ + typedef eina_container_common<efl::eina::array<W + , typename std::conditional + <std::is_base_of<efl::eo::concrete, W>::value + , efl::eina::eo_clone_allocator + , efl::eina::malloc_clone_allocator + >::type>, T, K> base_type; + using base_type::base_type; + typedef typename base_type::container_type container_type; + + eina_container_base* concat(eina_container_base const& other) const + { + return detail::concat(*this, other); + } + eina_container_base* slice(std::int64_t i, std::int64_t j) const + { + return detail::slice(*this, i, j); + } + v8::Local<v8::Value> set(v8::Isolate* isolate, std::size_t index, v8::Local<v8::Value> v) + { + return detail::set<T,W>(isolate, *this, index, v); + } + int push(v8::Isolate* isolate, v8::Local<v8::Value> v) + { + return detail::push<T,W>(isolate, *this, v); + } + v8::Local<v8::Value> pop(v8::Isolate* isolate) + { + return detail::pop<T,W,K>(isolate, *this); + } + js::container_type get_container_type() const { return array_container_type; } +}; + +template <typename T, typename K, typename W> +struct range_eina_array : eina_container_common<efl::eina::range_array<W>, T, K> +{ + typedef eina_container_common<efl::eina::range_array<W>, T, K> base_type; + using base_type::base_type; + typedef typename base_type::container_type container_type; + typedef typename std::conditional + <std::is_base_of<efl::eo::concrete, W>::value + , efl::eina::eo_clone_allocator + , efl::eina::malloc_clone_allocator + >::type clone_allocator_type; + + eina_container_base* concat(eina_container_base const& other) const + { + range_eina_array<T, K, W> const& rhs = static_cast<range_eina_array<T, K, W>const&>(other); + efl::eina::array<W, clone_allocator_type> + array(this->_container.begin(), this->_container.end()); + array.insert(array.end(), rhs._container.begin(), rhs._container.end()); + return new eina_array<T, K, W>(array.release_native_handle()); + } + eina_container_base* slice(std::int64_t i, std::int64_t j) const + { + efl::eina::array<W, clone_allocator_type> + array(std::next(this->_container.begin(), i), std::next(this->_container.begin(), j)); + return new eina_array<T, K, W>(array.release_native_handle()); + } + js::container_type get_container_type() const { return array_container_type; } +}; + +// Problematic types. +template <> +struct eina_array<_Elm_Calendar_Mark*, js::nonclass_cls_name_getter, _Elm_Calendar_Mark> + : empty_container_base +{ eina_array(Eina_Array const*){} }; +template <> +struct eina_array<Elm_Gen_Item*, js::nonclass_cls_name_getter, Elm_Gen_Item> + : empty_container_base +{ eina_array(Eina_Array const*){} }; +template <> +struct eina_array<_Evas_Textblock_Rectangle*, js::nonclass_cls_name_getter, _Evas_Textblock_Rectangle> + : empty_container_base +{ eina_array(Eina_Array const*){} }; +template <> +struct eina_array<_Elm_Map_Overlay*, js::nonclass_cls_name_getter, _Elm_Map_Overlay> + : empty_container_base +{ eina_array(Eina_Array const*){} }; + +template <> +struct range_eina_array<_Elm_Calendar_Mark*, js::nonclass_cls_name_getter, _Elm_Calendar_Mark> + : empty_container_base +{ range_eina_array(Eina_Array const*){} }; +template <> +struct range_eina_array<Elm_Gen_Item*, js::nonclass_cls_name_getter, Elm_Gen_Item> + : empty_container_base +{ range_eina_array(Eina_Array const*){} }; +template <> +struct range_eina_array<_Evas_Textblock_Rectangle*, js::nonclass_cls_name_getter, _Evas_Textblock_Rectangle> + : empty_container_base +{ range_eina_array(Eina_Array const*){} }; +template <> +struct range_eina_array<_Elm_Map_Overlay*, js::nonclass_cls_name_getter, _Elm_Map_Overlay> + : empty_container_base +{ range_eina_array(Eina_Array const*){} }; + +} } } + +#endif diff --git a/src/bindings/js/eina_js/eina_js_compatibility.cc b/src/bindings/js/eina_js/eina_js_compatibility.cc new file mode 100644 index 0000000000..a1d992f59e --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_compatibility.cc @@ -0,0 +1,12 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eina.hh> +#include <Eina_Js.hh> + +namespace efl { namespace eina { namespace js { + +std::map<std::string, v8::Local<v8::Function>> constructors_map_; + +} } } diff --git a/src/bindings/js/eina_js/eina_js_compatibility.hh b/src/bindings/js/eina_js/eina_js_compatibility.hh new file mode 100644 index 0000000000..9ef0cb814e --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_compatibility.hh @@ -0,0 +1,918 @@ +#ifndef EFL_EINA_JS_COMPATIBILITY_HH +#define EFL_EINA_JS_COMPATIBILITY_HH + +#include <type_traits> +#include <utility> +#include <map> +#include <string> +#include <cstdlib> + + +#ifdef HAVE_NODE_V8_H +#include <node/v8.h> +#elif defined(HAVE_NODEJS_DEPS_V8_V8_H) +#include <nodejs/deps/v8/v8.h> +#elif defined(HAVE_NODEJS_DEPS_V8_INCLUDE_V8_H) +#include <nodejs/deps/v8/include/v8.h> +#elif defined(HAVE_NODEJS_SRC_V8_H) +#include <nodejs/src/v8.h> +#elif defined(HAVE_V8_H) +#include <v8.h> +#else +#error We must have at least one v8 header to include +#endif + +namespace v8 { + +template <typename T> +struct FunctionCallbackInfo; +template <typename T> +struct PropertyCallbackInfo; +template <typename T> +#ifdef HAVE_V8_GLOBAL +struct Global; +#else +struct UniquePersistent; +#endif + +class AccessorInfo; + +class Arguments; + +} + +namespace efl { namespace eina { namespace js { + +template <typename T> +struct value_tag +{ + typedef T type; +}; + +template <typename T, typename... U> +struct complex_tag +{ + T value; + typedef std::tuple<U...> inner_types; +}; + +template <typename T> +struct make_tag_traits +{ + typedef typename std::remove_reference<T>::type a1; + typedef typename std::conditional + <std::is_pointer<T>::value + , typename std::remove_cv<T>::type + , T>::type type; +}; + +template <typename T, typename... U> +using make_complex_tag = complex_tag<typename make_tag_traits<T>::type + , typename make_tag_traits<U>::type...>; + +template <typename T> +struct struct_tag +{ + T value; +}; + +template <typename T> +using make_struct_tag = struct_tag<typename make_tag_traits<T>::type>; + +template <typename T> +struct struct_ptr_tag +{ + T value; +}; + +template <typename T> +using make_struct_ptr_tag = struct_ptr_tag<typename make_tag_traits<T>::type>; + +template <typename T, typename... Ts> +struct remove_tag +{ + typedef T type; +}; + +template <typename T, typename... U> +struct remove_tag<complex_tag<T, U...>> +{ + typedef typename eina::js::remove_tag<T, U...>::type type; +}; + +template <typename T> +struct remove_tag<struct_tag<T>> +{ + typedef typename eina::js::remove_tag<T>::type type; +}; + +template <typename T> +struct remove_tag<struct_ptr_tag<T>> +{ + typedef typename eina::js::remove_tag<T>::type type; +}; + +template <typename T> +struct is_handable_by_value +{ + static constexpr bool value = !std::is_class<T>::value || std::is_same<T, ::efl::eo::concrete>::value; +}; + +template <typename... T> +struct container_wrapper +{ + typedef typename eina::js::remove_tag<T...>::type _notag_type; + typedef typename std::conditional< + std::is_convertible<_notag_type, Eo const* const>::value + , typename std::conditional< + std::is_const<typename std::remove_pointer<_notag_type>::type>::value + , ::efl::eo::concrete const + , ::efl::eo::concrete + >::type + , _notag_type + >::type type; +}; + +template <typename T> +T container_wrap(T&& v) +{ + return std::forward<T>(v); +} + +inline ::efl::eo::concrete container_wrap(Eo* v) +{ + if(v) + eo_ref(v); + return ::efl::eo::concrete{v}; +} + +inline ::efl::eo::concrete container_wrap(Eo const* v) +{ + if (v) + eo_ref(v); + return ::efl::eo::concrete{const_cast<Eo*>(v)}; +} + +template <typename T> +T& container_unwrap(T& v) +{ + return v; +} + +inline Eo* container_unwrap(::efl::eo::concrete& v) +{ + return v._eo_ptr(); +} + +inline Eo* container_unwrap(::efl::eo::concrete const& v) +{ + return v._eo_ptr(); +} + +template <typename T> +struct is_complex_tag : std::false_type {}; + +template <typename... T> +struct is_complex_tag<complex_tag<T...>> : std::true_type {}; + +template <typename T> +struct is_struct_tag : std::false_type {}; + +template <typename T> +struct is_struct_tag<struct_tag<T>> : std::true_type {}; + +template <typename T> +struct is_struct_ptr_tag : std::false_type {}; + +template <typename T> +struct is_struct_ptr_tag<struct_ptr_tag<T>> : std::true_type {}; + +template <typename T> +struct is_type_tag +{ + static constexpr bool value = + is_complex_tag<T>::value + || is_struct_tag<T>::value + || is_struct_ptr_tag<T>::value; +}; + + +// Class name getters +struct cls_name_getter_base {}; +struct cls_name_getter_generated_base : cls_name_getter_base {}; +/// Name getter for types that are not classes +struct nonclass_cls_name_getter : cls_name_getter_base +{ + static char const* class_name() { return ""; } +}; + +// JS container base +enum container_type +{ + list_container_type + , array_container_type + , container_type_size +}; + +struct eina_container_base +{ + virtual ~eina_container_base() {} + + virtual std::size_t size() const = 0; + virtual eina_container_base* concat(eina_container_base const& rhs) const = 0; + virtual eina_container_base* slice(std::int64_t i, std::int64_t j) const = 0; + virtual int index_of(v8::Isolate* isolate, v8::Local<v8::Value> v) const = 0; + virtual int last_index_of(v8::Isolate* isolate, v8::Local<v8::Value> v) const = 0; + virtual v8::Local<v8::Value> get(v8::Isolate*, std::size_t) const = 0; + virtual v8::Local<v8::Value> set(v8::Isolate* isolate, std::size_t index, v8::Local<v8::Value> v) = 0; + virtual int push(v8::Isolate* isolate, v8::Local<v8::Value> v) = 0; + virtual v8::Local<v8::Value> pop(v8::Isolate* isolate) = 0; + virtual v8::Local<v8::String> to_string(v8::Isolate*) const = 0; + virtual v8::Local<v8::String> join(v8::Isolate*, v8::Local<v8::Value> separator) const = 0; + virtual container_type get_container_type() const = 0; + virtual void* get_container_native_handle() = 0; + virtual void const* get_container_native_handle() const = 0; +}; + +// Containers forward declarations + +// Array +template <typename T, typename K = nonclass_cls_name_getter, typename W = typename container_wrapper<T>::type> +struct eina_array; +template <typename T, typename K = nonclass_cls_name_getter, typename W = typename container_wrapper<T>::type> +struct range_eina_array; + +EAPI v8::Handle<v8::Function> get_array_instance_template(); + +// List +template <typename T, typename K = nonclass_cls_name_getter, typename W = typename container_wrapper<T>::type> +struct eina_list; +template <typename T, typename K = nonclass_cls_name_getter, typename W = typename container_wrapper<T>::type> +struct range_eina_list; + +EAPI v8::Handle<v8::Function> get_list_instance_template(); + +// Accessor +template <typename T, typename W> +v8::Local<v8::Object> export_accessor(::efl::eina::accessor<W>&, v8::Isolate*, const char*); + +template <typename T> +::efl::eina::accessor<T>& import_accessor(v8::Handle<v8::Object>); + +// Wrap value functions +template <typename R, typename T> +typename std::remove_cv<typename std::remove_reference<R>::type>::type +wrap_value(T v, value_tag<R> + , typename std::enable_if<!is_type_tag<typename std::remove_cv<R>::type>::value>::type* = 0) +{ + return v; +} + +template <typename R, typename T> +R wrap_value(T const& v, value_tag<eina::js::struct_tag<T>>) +{ + return R {v}; +} + +template <typename R, typename T> +R wrap_value(T v, value_tag<eina::js::struct_ptr_tag<T>>) +{ + return R {v}; +} + +template <typename R, typename T, typename... U> +R wrap_value(T v, value_tag<eina::js::complex_tag<T, U...>>) +{ + return R {v}; +} + +template <typename T = v8::External> +struct _libv8_isolate_test +{ + using new_signature = v8::Local<T>(*)(v8::Isolate*, void*); + static const bool value = std::is_same<decltype(static_cast<new_signature>(&T::New)), new_signature>::value; +}; + +template <typename T = v8::FunctionTemplate, typename Enable = void> +struct _libv8_callback_info_test; + +typedef v8::Handle<v8::Value>(*_libv8_invocation_callback)(v8::Arguments const&); + +template <typename T> +struct _libv8_callback_info_test +<T, typename std::enable_if + <!std::is_same<decltype( & T::SetCallHandler) + , void (T::*)(_libv8_invocation_callback, v8::Handle<v8::Value>)>::value>::type> + : std::true_type +{ +}; + +template <typename T> +struct _libv8_callback_info_test +<T, typename std::enable_if + <std::is_same<decltype( & T::SetCallHandler) + , void (T::*)(_libv8_invocation_callback, v8::Handle<v8::Value>)>::value>::type> + : std::false_type +{ +}; + +template <typename T = v8::ObjectTemplate, typename Enable = void> +struct _libv8_property_callback_info_test + : std::true_type {}; + +typedef v8::Handle<v8::Value>(*_libv8_getter_callback)(v8::Local<v8::String>, v8::AccessorInfo const&); +typedef void(*_libv8_setter_callback)(v8::Local<v8::String>, v8::Local<v8::Value>, v8::AccessorInfo const&); + +template <typename T> +struct _libv8_property_callback_info_test +<T, typename std::enable_if + <std::is_same<decltype( & T::SetAccessor) + , void (T::*) + (v8::Handle<v8::String> + , _libv8_getter_callback + , _libv8_setter_callback + , v8::Handle<v8::Value> + , v8::AccessControl + , v8::PropertyAttribute + , v8::Handle<v8::AccessorSignature> + )>::value>::type> + : std::false_type +{ +}; + +static constexpr bool const v8_uses_isolate = _libv8_isolate_test<>::value; +static constexpr bool const v8_uses_callback_info = _libv8_callback_info_test<>::value; +static constexpr bool const v8_uses_property_callback_info = _libv8_property_callback_info_test<>::value; + +using compatibility_return_type = std::conditional<v8_uses_callback_info, void, v8::Handle<v8::Value> >::type; +using compatibility_callback_info_type + = std::conditional<v8_uses_callback_info, v8::FunctionCallbackInfo<v8::Value> const&, v8::Arguments const&> + ::type; +using compatibility_callback_info_pointer + = std::conditional<v8_uses_callback_info, v8::FunctionCallbackInfo<v8::Value> const*, v8::Arguments const*> + ::type; + +typedef compatibility_return_type(*compatibility_function_callback)(compatibility_callback_info_type); + +using compatibility_accessor_getter_return_type + = std::conditional<v8_uses_property_callback_info, void, v8::Handle<v8::Value> >::type; +using compatibility_accessor_getter_callback_info_type + = std::conditional<v8_uses_property_callback_info + , v8::PropertyCallbackInfo<v8::Value> const&, v8::AccessorInfo const&> + ::type; + +using compatibility_accessor_setter_return_type + = void; +using compatibility_accessor_setter_callback_info_type + = std::conditional<v8_uses_property_callback_info + , v8::PropertyCallbackInfo<void> const&, v8::AccessorInfo const&> + ::type; + +using compatibility_indexed_property_getset_return_type + = std::conditional<v8_uses_property_callback_info, void, v8::Handle<v8::Value> >::type; +using compatibility_indexed_property_callback_info_type + = std::conditional<v8_uses_property_callback_info + , v8::PropertyCallbackInfo<v8::Value> const&, v8::AccessorInfo const&> + ::type; + +static_assert(v8_uses_property_callback_info == v8_uses_callback_info + && v8_uses_callback_info == v8_uses_isolate, ""); + +template <typename T> +struct compatibility_type_tag {}; + +template <bool = v8_uses_isolate> +struct compatibility_string; + +template <> +struct compatibility_string<true> : v8::String +{ + template <typename... Args> + static v8::Local<v8::String> New(Args...args) + { + return NewFromUtf8(v8::Isolate::GetCurrent(), args...); + } +}; + +template <> +struct compatibility_string<false> : v8::String +{ +}; + +template <typename...Args> +auto compatibility_new_impl(v8::Isolate*, std::true_type, compatibility_type_tag<v8::String> + , Args...args) -> + decltype(compatibility_string<>::New(args...)) +{ + return compatibility_string<>::New(args...); +} + +template <typename...Args> +auto compatibility_new_impl(v8::Isolate*, std::false_type, compatibility_type_tag<v8::String> + , Args...args) -> + decltype(compatibility_string<>::New(args...)) +{ + return compatibility_string<>::New(args...); +} + +template <typename...Args> +auto compatibility_new_impl(std::nullptr_t, std::true_type, compatibility_type_tag<v8::String> + , Args...args) -> + decltype(compatibility_string<>::New(args...)) +{ + return compatibility_string<>::New(args...); +} + +template <typename...Args> +auto compatibility_new_impl(std::nullptr_t, std::false_type, compatibility_type_tag<v8::String> + , Args...args) -> + decltype(compatibility_string<>::New(args...)) +{ + return compatibility_string<>::New(args...); +} + +template <typename T, typename...Args> +auto compatibility_new_impl(v8::Isolate* isolate, std::true_type, compatibility_type_tag<T> + , Args...args) -> + decltype(T::New(isolate, args...)) +{ + return T::New(isolate, args...); +} + +template <typename T, typename...Args> +auto compatibility_new_impl(v8::Isolate*, std::false_type, compatibility_type_tag<T> + , Args...args) -> + decltype(T::New(args...)) +{ + return T::New(args...); +} + +template <typename T, typename...Args> +auto compatibility_new_impl(std::nullptr_t, std::true_type, compatibility_type_tag<T> + , Args...args) -> + decltype(T::New(v8::Isolate::GetCurrent(), args...)) +{ + return T::New(v8::Isolate::GetCurrent(), args...); +} + +template <typename T, typename...Args> +auto compatibility_new_impl(std::nullptr_t, std::false_type, compatibility_type_tag<T> + , Args...args) -> + decltype(T::New(args...)) +{ + return T::New(args...); +} + +template <typename T, typename...Args> +auto compatibility_new(v8::Isolate* isolate, Args...args) -> + decltype(js::compatibility_new_impl<> + (isolate, std::integral_constant<bool, v8_uses_isolate>() + , compatibility_type_tag<T>() + , args...)) +{ + return js::compatibility_new_impl(isolate, std::integral_constant<bool, v8_uses_isolate>() + , compatibility_type_tag<T>() + , args...); +} + +template <typename T, typename...Args> +auto compatibility_new(std::nullptr_t, Args...args) -> + decltype(js::compatibility_new_impl<>(nullptr, std::integral_constant<bool, v8_uses_isolate>() + , compatibility_type_tag<T>() + , args...)) +{ + return js::compatibility_new_impl<>(nullptr, std::integral_constant<bool, v8_uses_isolate>() + , compatibility_type_tag<T>() + , args...); +} + +#ifdef HAVE_V8_CREATE_PARAMS +namespace detail { +class array_buffer_allocator : public v8::ArrayBuffer::Allocator +{ + public: + virtual void* Allocate(std::size_t length) + { + void* data = AllocateUninitialized(length); + return data ? std::memset(data, 0, length) : data; + } + virtual void* AllocateUninitialized(std::size_t length) { return std::malloc(length); } + virtual void Free(void* data, std::size_t) { std::free(data); } +}; +} + +inline v8::Isolate* compatibility_isolate_new() +{ + static detail::array_buffer_allocator allocator; + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = &allocator; + return v8::Isolate::New(create_params); +} + +#else + +inline v8::Isolate* compatibility_isolate_new() +{ + return v8::Isolate::New(); +} + +#endif + +template <typename T, typename U> +inline void compatibility_return_impl(T object, U const& info, std::true_type) +{ + info.GetReturnValue().Set(object); +} + +template <typename T> +inline v8::Handle<v8::Value> +compatibility_return_impl(T object, compatibility_callback_info_type, std::false_type) +{ + return object; +} + +template <typename T> +inline v8::Handle<v8::Value> +compatibility_return_impl(T object, compatibility_accessor_getter_callback_info_type, std::false_type) +{ + return object; +} + +template <typename T> +compatibility_return_type +compatibility_return(T object, compatibility_callback_info_type args) +{ + return compatibility_return_impl(object, args, std::integral_constant<bool, v8_uses_callback_info>()); +} + +template <typename T> +compatibility_return_type +compatibility_return(T object, compatibility_accessor_getter_callback_info_type args) +{ + return compatibility_return_impl(object, args, std::integral_constant<bool, v8_uses_property_callback_info>()); +} + +inline void compatibility_return_nil_impl(std::true_type) {} + +inline v8::Handle<v8::Value> +compatibility_return_nil_impl(std::false_type) +{ + return v8::Handle<v8::Value>(); +} + +inline +compatibility_return_type +compatibility_return() +{ + return compatibility_return_nil_impl(std::integral_constant<bool, v8_uses_callback_info>()); +} + +struct _v8_isolate_throw_exception : v8::Isolate +{ + v8::Handle<v8::Value> ThrowException_impl(v8::Handle<v8::Value> v) + { + using namespace v8; + return ThrowException(v); + } +}; + +inline void +compatibility_throw_impl(v8::Isolate* isolate, v8::Local<v8::Value> exception, std::true_type) +{ + static_cast<_v8_isolate_throw_exception*>(isolate)->ThrowException_impl(exception); +} + +inline v8::Handle<v8::Value> +compatibility_throw_impl(v8::Isolate* isolate, v8::Local<v8::Value> exception, std::false_type) +{ + return static_cast<_v8_isolate_throw_exception*>(isolate)->ThrowException_impl(exception); +} + +inline std::conditional<v8_uses_isolate, void, v8::Handle<v8::Value> >::type +compatibility_throw(v8::Isolate* isolate, v8::Local<v8::Value> exception) +{ + return compatibility_throw_impl(isolate, exception, std::integral_constant<bool, v8_uses_isolate>()); +} + +inline void +compatibility_throw_impl(v8::Local<v8::Value> exception, std::true_type) +{ + static_cast<_v8_isolate_throw_exception*>(v8::Isolate::GetCurrent())->ThrowException_impl(exception); +} + +inline v8::Handle<v8::Value> +compatibility_throw_impl(v8::Local<v8::Value> exception, std::false_type) +{ + return static_cast<_v8_isolate_throw_exception*>(v8::Isolate::GetCurrent())->ThrowException_impl(exception); +} + +inline std::conditional<v8_uses_isolate, void, v8::Handle<v8::Value> >::type +compatibility_throw(v8::Local<v8::Value> exception) +{ + return compatibility_throw_impl(exception, std::integral_constant<bool, v8_uses_isolate>()); +} + +template <typename T, typename U> +v8::Local<T> compatibility_cast(v8::Local<U> v); +template <typename T, typename U> +v8::Local<T> compatibility_cast(U* v); + +template <typename Tag> +struct hack_private_member { + /* export it ... */ + typedef typename Tag::type type; + static type ptr; +}; + +template <typename Tag> +typename hack_private_member<Tag>::type hack_private_member<Tag>::ptr; + +template <typename Tag, typename Tag::type p> +struct rob_private_member : hack_private_member<Tag> { + /* fill it ... */ + struct filler { + filler() { hack_private_member<Tag>::ptr = p; } + }; + static filler filler_obj; +}; + +template<typename Tag, typename Tag::type p> +typename rob_private_member<Tag, p>::filler rob_private_member<Tag, p>::filler_obj; + +template <typename T> +struct persistent_base_new { typedef T*(*type)(v8::Isolate*, T*); }; + +template class rob_private_member<persistent_base_new<v8::Value>, &v8::PersistentBase<v8::Value>::New>; + +template <typename T> +v8::Local<T> make_persistent(v8::Isolate* isolate, v8::Handle<T> v) +{ + v8::Value* p = hack_private_member<persistent_base_new<v8::Value>>::ptr + (isolate, *compatibility_cast<v8::Value>(v)); + return compatibility_cast<T>(compatibility_cast<v8::Value>(p)); +} + +template <typename T, typename F> +v8::Local<T> make_weak(v8::Isolate* isolate, v8::Handle<T> v, F&& f) +{ + v8::Value* p = hack_private_member<persistent_base_new<v8::Value>>::ptr + (isolate, *compatibility_cast<v8::Value>(v)); + v8::PersistentBase<v8::Value>* persistent = static_cast<v8::PersistentBase<v8::Value>*> + (static_cast<void*>(&p)); + + auto callback = [](const v8::WeakCallbackInfo<typename std::remove_reference<F>::type>& data) -> void + { + typename std::remove_reference<F>::type* f = data.GetParameter(); + (*f)(); + delete f; + }; + + persistent->SetWeak(new typename std::remove_reference<F>::type(std::forward<F>(f)), + callback, v8::WeakCallbackType::kParameter); + return compatibility_cast<T>(compatibility_cast<v8::Value>(p)); +} + +template <typename T> +struct global_ref +{ + global_ref() {} + global_ref(v8::Local<T> v) + : _value(make_persistent(nullptr, v)) + { + } + global_ref(v8::Isolate* isolate, v8::Local<T> v) + : _value(make_persistent(isolate, v)) + { + } + + void dispose() const + { + v8::PersistentBase<T>* p = static_cast<v8::PersistentBase<T>*>(static_cast<void*>(&_value)); + p->Reset(); + } + + v8::Handle<T> handle() const { return _value; } +private: + mutable v8::Local<T> _value; +}; + +template <typename T = std::integral_constant<bool, v8_uses_isolate> > +struct _v8_object_internal_field; + +template <> +struct _v8_object_internal_field<std::true_type> : v8::Object +{ +}; + +inline void* GetPointerFromInternalField(int) { return nullptr; } +inline void SetPointerInInternalField(int, void*) {} + +template <> +struct _v8_object_internal_field<std::false_type> : v8::Object +{ + void* GetAlignedPointerFromInternalField(int index) + { + return GetPointerFromInternalField(index); + } + void SetAlignedPointerInInternalField(int index, void* p) + { + SetPointerInInternalField(index, p); + } +}; + +template <typename T = void*> +inline T compatibility_get_pointer_internal_field(v8::Handle<v8::Object> object, std::size_t index) +{ + return reinterpret_cast<T> + (static_cast<_v8_object_internal_field<>*>(*object)->GetAlignedPointerFromInternalField(index)); +} + +template <typename T> +inline void compatibility_set_pointer_internal_field(v8::Handle<v8::Object> object, std::size_t index + , T* pointer) +{ + static_cast<_v8_object_internal_field<>*>(*object)->SetAlignedPointerInInternalField(index, pointer); +} + +template <typename T = void, bool = v8_uses_isolate> +struct compatibility_handle_scope_impl; + +template <typename T> +struct compatibility_handle_scope_impl<T, true> : v8::HandleScope +{ + compatibility_handle_scope_impl() + : HandleScope(v8::Isolate::GetCurrent()) + {} + compatibility_handle_scope_impl(v8::Isolate* isolate) + : HandleScope((assert(isolate != nullptr), isolate)) + {} +}; + +template <typename T> +struct compatibility_handle_scope_impl<T, false> : v8::HandleScope +{ + compatibility_handle_scope_impl() + {} + compatibility_handle_scope_impl(v8::Isolate*) + {} +}; + +using compatibility_handle_scope = compatibility_handle_scope_impl<>; + +template <bool = v8_uses_isolate> +struct _v8_initialize_icu; + +template <> +struct _v8_initialize_icu<true> : v8::V8 +{ +}; + +template <> +struct _v8_initialize_icu<false> : v8::V8 +{ + static bool InitializeICU(const char* = NULL) + { + return true; + } +}; + +inline void compatibility_initialize() +{ +#ifdef HAVE_V8_CREATE_PARAMS + constexpr const char* argv[] = {""}; + static_cast<_v8_initialize_icu<>*>(nullptr)->InitializeICU(); + v8::V8::InitializeExternalStartupData(argv[0]); + v8::V8::Initialize(); +#else + v8::V8::Initialize(); + static_cast<_v8_initialize_icu<>*>(nullptr)->InitializeICU(); +#endif +} + +template <typename T, typename U> +v8::Local<T> compatibility_cast(v8::Local<U> v) +{ + static_assert(sizeof(v8::Local<T>) == sizeof(v8::Local<U>), ""); + v8::Local<T> l; + std::memcpy(&l, &v, sizeof(v8::Local<T>)); + return l; +} + +template <typename T, typename U> +v8::Local<T> compatibility_cast(U* v) +{ + static_assert(sizeof(v8::Local<T>) == sizeof(U*), ""); + v8::Local<T> l; + std::memcpy(&l, &v, sizeof(v8::Local<T>)); + return l; +} + +template <typename T = v8::Isolate, bool = v8_uses_isolate> +struct _v8_get_current_context; + +template <typename T> +struct _v8_get_current_context<T, false> : v8::Context +{ +}; + +template <typename T> +struct _v8_get_current_context<T, true> : T +{ + static v8::Local<v8::Context> GetCurrent() + { + return T::GetCurrent()->GetCurrentContext(); + } +}; + +template <typename T> +inline v8::Local<v8::Value> +new_v8_external_instance(v8::Handle<v8::Function>& ctor, T v, v8::Isolate* isolate) +{ + // TODO: ensure v8::External ownership ??? (memory leak in case NewInstance throws) + v8::Handle<v8::Value> a[] = {efl::eina::js::compatibility_new<v8::External>(isolate, v)}; + return ctor->NewInstance(1, a); +} + +inline +compatibility_return_type cast_function(compatibility_callback_info_type args); + +inline v8::Local<v8::Value> +new_v8_external_instance(v8::Handle<v8::Function>& ctor, Eo* v, v8::Isolate* isolate) +{ + // TODO: ensure v8::External ownership ??? (memory leak in case NewInstance throws) + v8::Handle<v8::Value> a[] = {efl::eina::js::compatibility_new<v8::External>(isolate, v)}; + auto obj = ctor->NewInstance(1, a); + obj->Set(compatibility_new<v8::String>(isolate, "cast"), + compatibility_new<v8::FunctionTemplate>(isolate, &cast_function)->GetFunction()); + return obj; +} + +inline v8::Local<v8::Object> compatibility_global() +{ + return _v8_get_current_context<>::GetCurrent()->Global(); +} + +EAPI extern std::map<std::string, v8::Local<v8::Function>> constructors_map_; + +inline v8::Handle<v8::Function> get_class_constructor(std::string const& class_name) +{ + auto it = constructors_map_.find(class_name); + if (it == constructors_map_.end()) + throw std::runtime_error("Class not found"); + return it->second; +} + +inline void register_class_constructor(std::string const& class_name, + v8::Handle<v8::Function> constructor_ptr) +{ + // TODO: check if already exist? + constructors_map_[class_name] = constructor_ptr; +} + +template<class T = v8::StackTrace> +typename std::enable_if<!v8_uses_isolate, v8::Local<T>>::type +compatibility_current_stack_trace(v8::Isolate*, int frame_limit, + v8::StackTrace::StackTraceOptions options) +{ + return T::CurrentStackTrace(frame_limit, options); +} + +template<class T = v8::StackTrace> +typename std::enable_if<v8_uses_isolate, v8::Local<T>>::type +compatibility_current_stack_trace(v8::Isolate *isolate, int frame_limit, + v8::StackTrace::StackTraceOptions options) +{ + return T::CurrentStackTrace(isolate, frame_limit, options); +} + +inline +compatibility_return_type cast_function(compatibility_callback_info_type args) +{ + auto isolate = args.GetIsolate(); + compatibility_handle_scope scope(isolate); + v8::Local<v8::Value> type; + if(args.Length() == 1 && (type = args[0])->IsString()) + { + v8::Local<v8::Object> self = args.This(); + v8::Local<v8::Value> external = self->GetInternalField(0); + Eo* eo = static_cast<Eo*>(v8::External::Cast(*external)->Value()); + + v8::String::Utf8Value str(type->ToString()); + char* class_name = *str; + + auto ctor = ::efl::eina::js::get_class_constructor(class_name); + return compatibility_return + (new_v8_external_instance(ctor, ::eo_ref(eo), isolate), args); + } + else + { + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected String type"))); + return compatibility_return(); + } +} + +} } } + +#endif diff --git a/src/bindings/js/eina_js/eina_js_container.cc b/src/bindings/js/eina_js/eina_js_container.cc new file mode 100644 index 0000000000..60c53e0e74 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_container.cc @@ -0,0 +1,495 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eina.hh> +#include <Eina.h> +#include <cstdlib> + +#include <Eo.h> + +#include <eina_integer_sequence.hh> +#include <eina_tuple.hh> +#include <eina_ptrlist.hh> + +#include <Eina_Js.hh> + +#include <tuple> + +#include <iostream> + +namespace efl { namespace eina { namespace js { + +template <typename T> +struct tag { typedef T type; }; + +namespace { + +global_ref<v8::ObjectTemplate> instance_persistents[container_type_size]; +global_ref<v8::Function> instance_templates[container_type_size]; + +v8::Local<v8::Value> push(eina_container_base& self, v8::Isolate* isolate, v8::Local<v8::Value> value) +{ + return v8::Integer::New(isolate, self.push(isolate, value)); +} + +v8::Local<v8::Value> pop(eina_container_base& self, v8::Isolate* isolate, v8::Local<v8::Value>) +{ + return self.pop(isolate); +} + +v8::Local<v8::Value> concat(eina_container_base& lhs, v8::Isolate* isolate, v8::Local<v8::Value> other) +{ + const char* error_message = 0; + if(other->IsObject()) + { + v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(other); + v8::String::Utf8Value constructor_name (obj->GetConstructorName()); + if(obj->GetConstructorName()->Equals(efl::eina::js::compatibility_new<v8::String>(isolate, "eina_list")) + || obj->GetConstructorName()->Equals(efl::eina::js::compatibility_new<v8::String>(isolate, "eina_array"))) + { + eina_container_base& rhs = *static_cast<eina_container_base*> + (efl::eina::js::compatibility_get_pointer_internal_field(obj, 0)); + std::type_info const& typeinfo_lhs = typeid(lhs) + , &typeinfo_rhs = typeid(rhs); + if(!typeinfo_lhs.before(typeinfo_rhs) && !typeinfo_rhs.before(typeinfo_lhs)) + { + v8::Handle<v8::Value> a[] = + {efl::eina::js::compatibility_new<v8::External>(isolate, rhs.concat(lhs))}; + assert(!!*instance_templates[lhs.get_container_type()].handle()); + v8::Local<v8::Object> result = + instance_templates[lhs.get_container_type()].handle()->NewInstance(1, a); + return result; + } + else + error_message = "Containers are not of the same type."; + } + else + error_message = "Object to be concatenated is not a container."; + } + else + error_message = "Concatenation argument is not an container"; + + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError(eina::js::compatibility_new<v8::String>(isolate, error_message))); + + return v8::Undefined(isolate); +} + +v8::Local<v8::Value> slice(eina_container_base& self, v8::Isolate* isolate, v8::Local<v8::Value> begin + , v8::Local<v8::Value> end) +{ + std::size_t i, j; + + if(begin->IsUint32() || begin->IsInt32()) + i = begin->IntegerValue(); + else if (begin->IsUndefined()) + i = 0; + else + return v8::Undefined(isolate); + + if(end->IsUint32() || end->IsInt32()) + j = end->IntegerValue(); + else if (end->IsUndefined()) + j = self.size(); + else + return v8::Undefined(isolate); + + v8::Handle<v8::Value> a[] = {efl::eina::js::compatibility_new<v8::External>(isolate, self.slice(i, j))}; + v8::Local<v8::Object> result = instance_templates[self.get_container_type()].handle() + ->NewInstance(1, a); + return result; +} + +compatibility_accessor_getter_return_type length + (v8::Local<v8::String>, compatibility_accessor_getter_callback_info_type info) +{ + v8::Local<v8::Object> self_obj = compatibility_cast<v8::Object>(info.This()); + eina_container_base* self = static_cast<eina_container_base*> + (compatibility_get_pointer_internal_field(self_obj, 0)); + return compatibility_return(js::get_value_from_c(self->size(), info.GetIsolate(), ""), info); +} + +compatibility_indexed_property_getset_return_type index_get + (uint32_t index, compatibility_indexed_property_callback_info_type info) +{ + v8::Local<v8::Object> self_obj = v8::Local<v8::Object>::Cast(info.This()); + eina_container_base* self = static_cast<eina_container_base*> + (compatibility_get_pointer_internal_field(self_obj, 0)); + return compatibility_return(self->get(info.GetIsolate(), index), info); +} + +compatibility_indexed_property_getset_return_type index_set + (uint32_t index, v8::Local<v8::Value> value, compatibility_indexed_property_callback_info_type info) +{ + v8::Local<v8::Object> self_obj = v8::Local<v8::Object>::Cast(info.This()); + eina_container_base* self = static_cast<eina_container_base*> + (compatibility_get_pointer_internal_field(self_obj, 0)); + + return compatibility_return(self->set(info.GetIsolate(), index, value), info); +} + + +#define GENERATE_CONTAINER_CONSTRUCT_TYPE_IF(x) GENERATE_CONTAINER_CONSTRUCT_TYPE2_IF(x, x) +#define GENERATE_CONTAINER_CONSTRUCT_TYPE2_IF(x, y) if (!strcmp(class_name, #x)) \ + return new Container<y, nonclass_cls_name_getter, typename container_wrapper<y>::type>(); + +template< template<typename, typename, typename> class Container> +eina_container_base* construct_container(const char* class_name) +{ + GENERATE_CONTAINER_CONSTRUCT_TYPE_IF(int); + GENERATE_CONTAINER_CONSTRUCT_TYPE_IF(float); + GENERATE_CONTAINER_CONSTRUCT_TYPE2_IF(bool, Eina_Bool); + GENERATE_CONTAINER_CONSTRUCT_TYPE2_IF(string, char*); + + return 0; +} + +compatibility_return_type new_eina_list_internal(compatibility_callback_info_type args) +{ + if(args.IsConstructCall()) + { + if(args.Length() == 0) + { + eina_container_base* p = new eina_list<int>; + compatibility_set_pointer_internal_field + (args.This(), 0, dynamic_cast<void*>(p)); + } + else + { + if(args[0]->IsExternal()) + { + eina_container_base* base = reinterpret_cast<eina_container_base*> + (v8::External::Cast(*args[0])->Value()); + compatibility_set_pointer_internal_field + (args.This(), 0, dynamic_cast<void*>(base)); + } + else + std::abort(); + } + } + else + std::abort(); + return compatibility_return(); +} + +compatibility_return_type new_eina_list(compatibility_callback_info_type args) +{ + if(args.IsConstructCall()) + { + if(args.Length() == 0) // Default constructor, list of ints. Or should be list of Eo's? + { + eina_container_base* p = new eina_list<int>; + compatibility_set_pointer_internal_field + (args.This(), 0, dynamic_cast<void*>(p)); + return compatibility_return(); + } + else if (args.Length() == 1 && args[0]->IsString()) + { + v8::String::Utf8Value string(args[0]); + eina_container_base* p = construct_container<efl::eina::js::eina_list>(*string); + if (!p) { + return eina::js::compatibility_throw + (args.GetIsolate(), v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Invalid type for container."))); + } + compatibility_set_pointer_internal_field + (args.This(), 0, dynamic_cast<void*>(p)); + return compatibility_return(); + } + } + return eina::js::compatibility_throw + (args.GetIsolate(), v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Wrong number of arguments for constructor call"))); +} + +compatibility_return_type new_eina_array_internal(compatibility_callback_info_type args) +{ + if(args.IsConstructCall()) + { + if(args.Length() == 0) + { + eina_container_base* p = new eina_array<int>; + compatibility_set_pointer_internal_field + (args.This(), 0, dynamic_cast<void*>(p)); + } + else + { + if(args[0]->IsExternal()) + { + eina_container_base* base = reinterpret_cast<eina_container_base*> + (v8::External::Cast(*args[0])->Value()); + compatibility_set_pointer_internal_field + (args.This(), 0, dynamic_cast<void*>(base)); + } + else + std::abort(); + } + } + else + std::abort(); + return compatibility_return(); +} + +compatibility_return_type new_eina_array(compatibility_callback_info_type args) +{ + if(args.IsConstructCall()) + { + if(args.Length() == 0) + { + eina_container_base* p = new eina_array<int>; + compatibility_set_pointer_internal_field + (args.This(), 0, dynamic_cast<void*>(p)); + return compatibility_return(); + } + else if (args.Length() == 1 && args[0]->IsString()) + { + v8::String::Utf8Value string(args[0]); + eina_container_base* p = construct_container<efl::eina::js::eina_array>(*string); + if (!p) { + return eina::js::compatibility_throw + (args.GetIsolate(), v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Invalid type for container."))); + } + compatibility_set_pointer_internal_field + (args.This(), 0, dynamic_cast<void*>(p)); + return compatibility_return(); + } + } + return eina::js::compatibility_throw + (args.GetIsolate(), v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Wrong number of arguments for constructor call"))); +} + +template <typename F> +struct function_params; + +template <typename R, typename... Sig> +struct function_params<R(*)(Sig...)> +{ + typedef std::tuple<Sig...> type; +}; + +template <typename F> +struct function_result; + +template <typename R, typename... Sig> +struct function_result<R(*)(Sig...)> +{ + typedef R type; +}; + +template <typename T> +struct is_persistent : std::false_type {}; + +template <typename...A> +struct is_persistent<v8::Persistent<A...> > : std::true_type {}; + +template <std::size_t I, typename Sig> +typename std::tuple_element<I, Sig>::type +get_element(v8::Isolate* isolate + , compatibility_callback_info_type args + , typename std::enable_if + <is_persistent<typename std::tuple_element<I, Sig>::type>::value>::type* = 0) +{ + return typename std::tuple_element<I, Sig>::type(isolate, args[I]); +} + +template <std::size_t I, typename Sig> +typename std::tuple_element<I, Sig>::type +get_element(v8::Isolate* /*isolate*/ + , compatibility_callback_info_type args + , typename std::enable_if + <!is_persistent<typename std::tuple_element<I, Sig>::type>::value>::type* = 0) +{ + return args[I]; +} + +template <typename Sig, typename R, typename T, typename F, std::size_t... N> +R call_impl(v8::Isolate* isolate + , compatibility_callback_info_type args + , T* self, F* f + , eina::index_sequence<N...>) +{ + assert(self != 0); + return (*f)(*self, isolate, js::get_element<N, Sig>(isolate, args)...); +} + +template <typename Sig, typename T, typename F, typename R> +compatibility_return_type call_generic_impl(compatibility_callback_info_type args, tag<R>) +{ + T* self = static_cast<T*> + (compatibility_get_pointer_internal_field<>(args.This(), 0)); + F* f = reinterpret_cast<F*>(v8::External::Cast(*args.Data())->Value()); + return compatibility_return + (js::get_value_from_c + (js::call_impl<Sig, R>(args.GetIsolate(), args, self, f + , eina::make_index_sequence<std::tuple_size<Sig>::value>()) + , args.GetIsolate(), "") + , args); +} + +template <typename Sig, typename T, typename F> +compatibility_return_type call_generic_impl(compatibility_callback_info_type args, tag<void>) +{ + T* self = static_cast<T*> + (compatibility_get_pointer_internal_field(args.This(), 0)); + F* f = reinterpret_cast<F*>(v8::External::Cast(*args.Data())->Value()); + js::call_impl<Sig, void>(args.GetIsolate(), args, self, f + , eina::make_index_sequence<std::tuple_size<Sig>::value>()); + return compatibility_return(); +} + +template <typename Sig, typename R, typename T, typename F> +compatibility_return_type call_generic(compatibility_callback_info_type args) +{ + return efl::eina::js::call_generic_impl<Sig, T, F>(args, tag<R>()); +} + +template <typename Sig, typename T, typename F, typename R> +compatibility_return_type call_function_impl(compatibility_callback_info_type args, tag<R>) +{ + T* self = static_cast<T*> + (compatibility_get_pointer_internal_field(args.This(), 0)); + F f = reinterpret_cast<F>(v8::External::Cast(*args.Data())->Value()); + return compatibility_return + (/*js::get_value_from_c*/ + (js::call_impl<Sig, R>(args.GetIsolate(), args, self, f + , eina::make_index_sequence<std::tuple_size<Sig>::value>()) + /*, args.GetIsolate(), ""*/) + , args); +} + +template <typename Sig, typename T, typename F> +compatibility_return_type call_function_impl(compatibility_callback_info_type args, tag<void>) +{ + T* self = static_cast<T*> + (compatibility_get_pointer_internal_field(args.This(), 0)); + F f = reinterpret_cast<F>(v8::External::Cast(*args.Data())->Value()); + js::call_impl<Sig, void>(args.GetIsolate(), args, self, f + , eina::make_index_sequence<std::tuple_size<Sig>::value>()); + return compatibility_return(); +} + +template <typename Sig, typename R, typename T, typename F> +compatibility_return_type call_function(compatibility_callback_info_type args) +{ + return efl::eina::js::call_function_impl<Sig, T, F>(args, tag<R>()); +} + +template <typename T, typename F> +void register_(v8::Isolate* isolate, const char* name, F f, v8::Handle<v8::ObjectTemplate> template_ + , typename std::enable_if<std::is_function<typename std::remove_pointer<F>::type>::value>::type* = 0) +{ + template_->Set(compatibility_new<v8::String>(isolate, name) + , compatibility_new<v8::FunctionTemplate> + (isolate, &efl::eina::js::call_function + <typename eina::_mpl::pop_front<typename function_params<F>::type, 2u>::type + , typename function_result<F>::type, T, F> + , compatibility_new<v8::External> + (isolate, reinterpret_cast<void*>(f)))); +} + +template <typename T, typename...Sig, typename F> +void register_(v8::Isolate* isolate, const char* name, F&& f, v8::Handle<v8::ObjectTemplate> template_ + , typename std::enable_if<!std::is_function<typename std::remove_pointer<F>::type>::value>::type* = 0) +{ + using result_type = decltype + (std::declval<F>() + (std::declval<T&>(), std::declval<v8::Isolate*>() + , std::declval<Sig>()...) + ); + template_->Set(compatibility_new<v8::String>(isolate, name) + , compatibility_new<v8::FunctionTemplate> + (isolate + , &efl::eina::js::call_generic<std::tuple<Sig...>, result_type, T, F> + , compatibility_new<v8::External> + (isolate, new F(std::forward<F>(f))))); +} + +v8::Local<v8::ObjectTemplate> register_template(v8::Isolate* isolate, v8::Handle<v8::FunctionTemplate> constructor) +{ + v8::Local<v8::ObjectTemplate> instance_t = constructor->InstanceTemplate(); + instance_t->SetInternalFieldCount(1); + + instance_t->SetIndexedPropertyHandler(& efl::eina::js::index_get, & efl::eina::js::index_set); + + v8::Local<v8::ObjectTemplate> prototype = constructor->PrototypeTemplate(); + prototype->SetAccessor(compatibility_new<v8::String>(isolate, "length"), &efl::eina::js::length); + + using namespace std::placeholders; + js::register_<js::eina_container_base> + (isolate, "push", &js::push, prototype); + js::register_<js::eina_container_base> + (isolate, "pop", &js::pop, prototype); + js::register_<js::eina_container_base> + (isolate, "concat", &js::concat, prototype); + js::register_<js::eina_container_base> + (isolate, "slice", &js::slice, prototype); + js::register_<js::eina_container_base> + (isolate, "toString", std::bind(&js::eina_container_base::to_string, _1, _2), prototype); + js::register_<js::eina_container_base, v8::Local<v8::Value> > + (isolate, "join", std::bind(&js::eina_container_base::join, _1, _2, _3), prototype); + js::register_<js::eina_container_base, v8::Local<v8::Value> > + (isolate, "indexOf", std::bind(&js::eina_container_base::index_of, _1, _2, _3), prototype); + js::register_<js::eina_container_base, v8::Local<v8::Value> > + (isolate, "lastIndexOf", std::bind(&js::eina_container_base::last_index_of, _1, _2, _3), prototype); + + return instance_t; +} + +void register_class(v8::Isolate* isolate, container_type type, const char* class_name + , compatibility_function_callback callback) +{ + v8::Handle<v8::FunctionTemplate> constructor + = compatibility_new<v8::FunctionTemplate>(isolate, callback); + constructor->SetClassName(compatibility_new<v8::String>(isolate, class_name)); + + v8::Local<v8::ObjectTemplate> instance_t = efl::eina::js::register_template(isolate, constructor); + + efl::eina::js::instance_persistents[type] = global_ref<v8::ObjectTemplate>{isolate, instance_t}; + efl::eina::js::instance_templates[type] = global_ref<v8::Function>{isolate, constructor->GetFunction()}; +} +void register_class(v8::Isolate* isolate, container_type, const char* class_name_ + , const char* constructor_name_ + , compatibility_function_callback callback + , v8::Handle<v8::Object> exports) +{ + v8::Handle<v8::FunctionTemplate> constructor + = compatibility_new<v8::FunctionTemplate>(isolate, callback); + auto class_name = compatibility_new<v8::String>(isolate, class_name_); + auto constructor_name = compatibility_new<v8::String>(isolate, constructor_name_); + constructor->SetClassName(class_name); + + v8::Local<v8::ObjectTemplate> instance_t = efl::eina::js::register_template(isolate, constructor); + (void)instance_t; + + exports->Set(constructor_name, constructor->GetFunction()); +} + +} + +EAPI v8::Handle<v8::Function> get_list_instance_template() +{ + return efl::eina::js::instance_templates[efl::eina::js::list_container_type].handle(); +} + +EAPI v8::Handle<v8::Function> get_array_instance_template() +{ + return efl::eina::js::instance_templates[efl::eina::js::array_container_type].handle(); +} + +} } } + +EAPI void eina_container_register(v8::Handle<v8::Object> exports, v8::Isolate* isolate) +{ + efl::eina::js::register_class(isolate, efl::eina::js::list_container_type + , "eina_list", &efl::eina::js::new_eina_list_internal); + efl::eina::js::register_class(isolate, efl::eina::js::list_container_type + , "eina_list", "List", &efl::eina::js::new_eina_list, exports); + efl::eina::js::register_class(isolate, efl::eina::js::array_container_type + , "eina_array", &efl::eina::js::new_eina_array_internal); + efl::eina::js::register_class(isolate, efl::eina::js::array_container_type + , "eina_array", "Array", &efl::eina::js::new_eina_array, exports); +} + diff --git a/src/bindings/js/eina_js/eina_js_container.hh b/src/bindings/js/eina_js/eina_js_container.hh new file mode 100644 index 0000000000..21343fd6da --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_container.hh @@ -0,0 +1,351 @@ +#ifndef EINA_JS_CONTAINER_HH +#define EINA_JS_CONTAINER_HH + +#include <algorithm> + +#include <eina_js_compatibility.hh> +#include <eina_js_get_value.hh> +#include <eina_js_get_value_from_c.hh> + +struct _Elm_Calendar_Mark; +struct Elm_Gen_Item; +struct _Eina_Rectangle; +struct _Evas_Textblock_Rectangle; +struct _Elm_Map_Overlay; + +namespace efl { namespace eina { namespace js { + +namespace detail { + +template <typename T> +eina_container_base* concat(T const& self, eina_container_base const& other) +{ + T const& rhs = static_cast<T const&>(other); + typedef typename T::container_type container_type; + container_type container(self._container.begin(), self._container.end()); + container.insert(container.end(), rhs._container.begin(), rhs._container.end()); + return new T(container.release_native_handle()); +} + +template <typename T> +eina_container_base* slice(T const& self, std::int64_t i, std::int64_t j) +{ + typedef typename T::container_type container_type; + container_type container(std::next(self._container.begin(), i), std::next(self._container.begin(), j)); + return new T(container.release_native_handle()); +} + +// T, W from the container instantiation +template<typename T, typename W, typename C> +int push(v8::Isolate* isolate, C& self, v8::Local<v8::Value> v) +{ + try + { + W value = container_wrap(get_value_from_javascript(v, isolate, "", value_tag<T>())); + self._container.push_back(value); + } + catch (std::logic_error const&) + { + return -1; + } + return self.size(); +} + +template<typename T, typename W, typename K, typename C> +v8::Local<v8::Value> pop(v8::Isolate* isolate, C& self) +{ + + if (self._container.empty()) + return v8::Undefined(isolate); + + auto value = eina::js::get_value_from_c( + eina::js::wrap_value<T>(eina::js::container_unwrap(self._container.back()), eina::js::value_tag<T>{}) + , isolate + , K::class_name()); + self._container.pop_back(); + return value; +} +template<typename T, typename W, typename C> +v8::Local<v8::Value> set(v8::Isolate* isolate, C& self, std::size_t index, v8::Local<v8::Value> v) + { + using notag_type = typename remove_tag<T>::type; + try + { + W value = container_wrap(get_value_from_javascript(v, isolate, "", value_tag<T>())); + + if (index >= self.size()) + { + std::size_t items_to_add = index - self.size() + 1; + for (int i = items_to_add; i; i--) + { + self._container.push_back(container_wrap(notag_type{})); + } + } + + auto v2 = std::next(self._container.begin(), index); + *v2 = value; + } + catch (std::logic_error const&) + { + return v8::Undefined(isolate); + } + + return v; + } + +} + +template <typename InputIterator, typename T> +inline InputIterator find_element(InputIterator first, InputIterator last, T const& value, typename std::enable_if<is_handable_by_value<T>::value>::type* = 0) +{ + return std::find(first, last, value); +} + +template <typename InputIterator, typename T> +inline InputIterator find_element(InputIterator first, InputIterator last, T const& value, typename std::enable_if<!is_handable_by_value<T>::value>::type* = 0) +{ + return std::find_if(first, last, [&](T const& e){ return &e == &value; }); +} + +template <typename InputIterator> +inline InputIterator find_element(InputIterator first, InputIterator last, char * value) +{ + return std::find_if(first, last, [=](char* e){ return strcmp(e, value) == 0; }); +} + +template <typename CharT, typename T> +inline void stream_element(std::basic_ostream<CharT>& s, T const& value, typename std::enable_if<is_handable_by_value<T>::value>::type* = 0) +{ + s << value; +} + +template <typename CharT, typename T> +inline void stream_element(std::basic_ostream<CharT>& s, T const& value, typename std::enable_if<!is_handable_by_value<T>::value>::type* = 0) +{ + s << &value; +} + +template <typename CharT> +inline void stream_element(std::basic_ostream<CharT>& s, Eina_Bool value) +{ + s << (value ? "true" : "false"); +} + +template <typename C, typename T, typename K> +struct eina_container_common; + + +template <typename C, typename V, typename T, typename K, typename Enable = void> +struct eina_container_type_specific + : eina_container_base +{ + v8::Local<v8::Value> get(v8::Isolate* isolate, std::size_t index) const + { + if(index >= this->size()) + return v8::Undefined(isolate); + return eina::js::get_value_from_c( + eina::js::wrap_value<T>(eina::js::container_unwrap(*std::next(container_get().begin(), index)), eina::js::value_tag<T>{}) + , isolate + , K::class_name()); + } + int index_of(v8::Isolate* isolate, v8::Local<v8::Value> v) const + { + try + { + V value = container_wrap(get_value_from_javascript( + v, isolate, K::class_name(), eina::js::value_tag<T>{}, false)); + typedef typename C::const_iterator iterator; + iterator first = container_get().cbegin() + , last = container_get().cend() + , found = find_element(first, last, value); + if(found == last) + return -1; + else + return std::distance(first, found); + } + catch (std::logic_error const&) + { + return -1; + } + } + int last_index_of(v8::Isolate* isolate, v8::Local<v8::Value> v) const + { + try + { + V value = container_wrap(get_value_from_javascript( + v, isolate, K::class_name(), eina::js::value_tag<T>{}, false)); + auto last = container_get().crend() + , found = find_element(container_get().crbegin(), last, value); + if(found == last) + return -1; + else + return std::distance(container_get().cbegin(), found.base()) -1; + } + catch (std::logic_error const&) + { + return -1; + } + } + void* get_container_native_handle() + { + void const* h = container_get().native_handle(); + return const_cast<void*>(h); + } + void const* get_container_native_handle() const + { + return container_get().native_handle(); + } + C& container_get() { return static_cast<eina_container_common<C, T, K>&>(*this)._container; } + C const& container_get() const { return static_cast<eina_container_common<C, T, K>const&>(*this)._container; } +}; + +template <typename C, typename T, typename K> +struct eina_container_common : eina_container_type_specific<C, typename C::value_type, T, K> +{ + eina_container_common() : _container() {} + eina_container_common(typename C::native_handle_type raw) : _container(raw) {} + + std::size_t size() const { return _container.size(); } + v8::Local<v8::String> to_string(v8::Isolate* isolate) const + { + return join(isolate, compatibility_new<v8::String>(isolate, ",")); + } + + v8::Local<v8::String> join(v8::Isolate* isolate, v8::Local<v8::Value> separator_js) const + { + std::string separator = ","; + typedef typename container_type::const_iterator iterator; + std::stringstream s; + + if (separator_js->IsString()) + { + v8::String::Utf8Value str(separator_js); + if (*str) + { + separator = *str; + } + else + { + eina::js::compatibility_throw( + isolate, v8::Exception::TypeError( + eina::js::compatibility_new<v8::String>(isolate, "Invalid separator."))); + return compatibility_new<v8::String>(isolate, ""); + } + } + else if (!separator_js->IsUndefined()) // Called join without arguments. + { + eina::js::compatibility_throw( + isolate, v8::Exception::TypeError( + eina::js::compatibility_new<v8::String>(isolate, "Separator must be a string."))); + return compatibility_new<v8::String>(isolate, ""); + } + + for(iterator first = _container.begin() + , last = _container.end() + , last_elem = std::next(last, -1); first != last; ++first) + { + stream_element(s, *first); + if(first != last_elem) + s << separator; + } + return compatibility_new<v8::String>(isolate, s.str().c_str()); + } + + // Default implementation of some methods + int push(v8::Isolate* isolate, v8::Local<v8::Value>) + { + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Push method was not implemented."))); + return -1; + } + v8::Local<v8::Value> pop(v8::Isolate* isolate) + { + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Pop method was not implemented."))); + return v8::Undefined(isolate); + } + v8::Local<v8::Value> set(v8::Isolate* isolate, std::size_t, v8::Local<v8::Value>) + { + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Indexed attribution was not implemented."))); + return v8::Undefined(isolate); + } + C _container; + typedef C container_type; +}; + + +// Specialization for problematic types +struct empty_container_base + : eina_container_base +{ + empty_container_base() {} + virtual ~empty_container_base() {} + + std::size_t size() const + { + return 0; + } + eina_container_base* concat(eina_container_base const& ) const + { + return new empty_container_base; + } + eina_container_base* slice(std::int64_t , std::int64_t ) const + { + return new empty_container_base; + } + int index_of(v8::Isolate*, v8::Local<v8::Value>) const + { + return -1; + } + int last_index_of(v8::Isolate*, v8::Local<v8::Value>) const + { + return -1; + } + v8::Local<v8::Value> get(v8::Isolate* isolate, std::size_t) const + { + return v8::Undefined(isolate); + } + v8::Local<v8::Value> set(v8::Isolate* isolate, std::size_t, v8::Local<v8::Value>) + { + return v8::Undefined(isolate); + } + int push(v8::Isolate*, v8::Local<v8::Value>) + { + return -1; + } + v8::Local<v8::Value> pop(v8::Isolate* isolate) + { + return v8::Undefined(isolate); + } + v8::Local<v8::String> to_string(v8::Isolate* isolate) const + { + return compatibility_new<v8::String>(isolate, ""); + } + v8::Local<v8::String> join(v8::Isolate* isolate, v8::Local<v8::Value>) const + { + return compatibility_new<v8::String>(isolate, ""); + } + container_type get_container_type() const + { + throw std::runtime_error("get_container_type of container with unmanagable type"); + return container_type_size; + } + void* get_container_native_handle() + { + return nullptr; + } + void const* get_container_native_handle() const + { + return nullptr; + } +}; + +} } } + +EAPI void eina_container_register(v8::Handle<v8::Object> exports, v8::Isolate* isolate); + +#endif diff --git a/src/bindings/js/eina_js/eina_js_error.cc b/src/bindings/js/eina_js/eina_js_error.cc new file mode 100644 index 0000000000..89d69a1895 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_error.cc @@ -0,0 +1,24 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eina_Js.hh> + +namespace efl { namespace eina {namespace js { + +EAPI +js::compatibility_return_type convert_error_to_javascript_exception(v8::Isolate *isolate) +{ + Eina_Error err = eina_error_get(); + if (!err) + return compatibility_return(); + + v8::Local<v8::Object> je = eina::js::compatibility_new<v8::Object>(isolate); + je->Set(compatibility_new<v8::String>(isolate, "code"), + compatibility_new<v8::String>(isolate, "Eina_Error")); + je->Set(compatibility_new<v8::String>(isolate, "value"), + compatibility_new<v8::String>(isolate, eina_error_msg_get(err))); + return compatibility_throw(isolate, je); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/eina_js/eina_js_error.hh b/src/bindings/js/eina_js/eina_js_error.hh new file mode 100644 index 0000000000..49cef35161 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_error.hh @@ -0,0 +1,25 @@ +#ifndef EINA_JS_ERROR_HH +#define EINA_JS_ERROR_HH + +#include <eina_js_compatibility.hh> + +namespace efl { namespace eina { namespace js { + +/** + * Converts the error value set through Eina's error tool to a JavaScript + * exception. + * + * The exception object will have a `code` string field with the `"Eina_Error"` + * string value and a `value` string field with the value extracted from + * `eina_error_msg_get`. + * + * It won't reset the error to NULL, so you can still access the error object, + * but if you keep calling this function without clearing the error, a new + * exception will be generated for each call after some error is reached. We, + * therefore, suggest you to call `eina_error_set(0)` afterwards. + */ +js::compatibility_return_type convert_error_to_javascript_exception(v8::Isolate *isolate); + +} } } // namespace efl::eina::js + +#endif /* EINA_JS_ERROR_HH */ diff --git a/src/bindings/js/eina_js/eina_js_get_value.hh b/src/bindings/js/eina_js/eina_js_get_value.hh new file mode 100644 index 0000000000..637b48a9c8 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_get_value.hh @@ -0,0 +1,449 @@ +#ifndef EFL_EINA_JS_GET_VALUE_HH +#define EFL_EINA_JS_GET_VALUE_HH + +#include <eina_js_compatibility.hh> + +#include <type_traits> +#include <cstdlib> +#include <iostream> +#include <typeinfo> + +namespace efl { namespace eina { namespace js { + +template <typename T> +inline int get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* + , value_tag<T> + , bool throw_js_exception = true + , typename std::enable_if<(std::is_integral<T>::value && !std::is_same<T, Eina_Bool>::value)>::type* = 0) +{ + if(v->IsInt32()) + return v->Int32Value(); + else if(v->IsUint32()) + return v->Uint32Value(); + else + { + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected Integral type"))); + + throw std::logic_error(""); + } + return 0; +} + +inline char* get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* + , value_tag<char*> + , bool throw_js_exception = true) +{ + if(v->IsNull()) + return nullptr; + else if(v->IsString()) + { + v8::String::Utf8Value str(v->ToString()); + char* string = strdup(*str); // TODO: leaks + return string; + } + else + { + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected String type"))); + + throw std::logic_error(""); + } + return 0; +} + +inline const char* get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* class_name + , value_tag<const char*> + , bool throw_js_exception = true) +{ + return get_value_from_javascript(v, isolate, class_name, value_tag<char*>(), throw_js_exception); +} + +inline Eo* get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* + , value_tag<Eo*> + , bool throw_js_exception = true) +{ + if(v->IsNull()) + return nullptr; + else if(v->IsObject()) + { + v8::Local<v8::Object> object = v->ToObject(); + if(object->InternalFieldCount() == 1) + { + v8::Local<v8::Value> r = object->GetInternalField(0); + if(v8::External* external = v8::External::Cast(*r)) + { + return static_cast<Eo*>(external->Value()); + } + } + } + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected Eolian object type"))); + throw std::logic_error(""); + return nullptr; +} + +inline Eo* get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* class_name + , value_tag<Eo* const> + , bool throw_js_exception = true) +{ + return get_value_from_javascript(v, isolate, class_name, value_tag<Eo*>(), throw_js_exception); +} + +template <typename T> +inline T get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* + , value_tag<struct_ptr_tag<T>> + , bool throw_js_exception = true) +{ + if(v->IsNull()) + return nullptr; + else if(v->IsObject()) + { + v8::Local<v8::Object> object = v->ToObject(); + if(object->InternalFieldCount() == 1) + { + return compatibility_get_pointer_internal_field<T>(object, 0); + } + } + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected Eolian struct type"))); + throw std::logic_error(""); + return nullptr; +} + +template <typename T> +inline T get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* class_name + , value_tag<struct_tag<T>> + , bool throw_js_exception = true) +{ + T* ptr = get_value_from_javascript(v, isolate, class_name, value_tag<struct_ptr_tag<T*>>(), throw_js_exception); + if (ptr) + return *ptr; + + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Conversion of null pointer to by-value struct."))); + throw std::logic_error(""); + return T{}; +} + +template <typename T> +inline T get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* + , value_tag<T> + , bool throw_js_exception = true + , typename std::enable_if<std::is_enum<T>::value>::type* = 0) +{ + if(v->IsInt32()) + return static_cast<T>(v->Int32Value()); + else if(v->IsUint32()) + return static_cast<T>(v->Uint32Value()); + else + { + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected enumeration type"))); + + throw std::logic_error(""); + } + return T(); +} + +inline Eina_Bool get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* + , value_tag<Eina_Bool> + , bool throw_js_exception = true) +{ + if(v->IsBoolean() || v->IsBooleanObject()) + { + return v->BooleanValue() ? EINA_TRUE : EINA_FALSE; + } + else + { + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected Boolean type"))); + + throw std::logic_error(""); + } + return 0; +} + +template <typename T> +inline double get_value_from_javascript + (v8::Local<v8::Value> v + , v8::Isolate* isolate + , const char* + , value_tag<T> + , bool throw_js_exception = true + , typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) +{ + if(v->IsNumber()) + { + return v->NumberValue(); + } + else + { + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected floating point type"))); + throw std::logic_error(""); + } + return 0.0; +} + +template <typename T> +inline T get_value_from_javascript + (v8::Local<v8::Value>, v8::Isolate* isolate, const char*, value_tag<T> + , bool throw_js_exception = true + , typename std::enable_if< + !std::is_floating_point<T>::value && + !std::is_integral<T>::value && + !std::is_enum<T>::value && + !js::is_struct_tag<T>::value && + !js::is_struct_ptr_tag<T>::value && + !js::is_complex_tag<T>::value && + !std::is_same<T, Eina_Accessor*>::value && + !std::is_same<T, Eina_Array*>::value && + !std::is_same<T, Eina_Iterator*>::value && + !std::is_same<T, Eina_Hash*>::value && + !std::is_same<T, Eina_List*>::value && + !std::is_same<T, const Eina_Accessor*>::value && + !std::is_same<T, const Eina_Array*>::value && + !std::is_same<T, const Eina_Iterator*>::value && + !std::is_same<T, const Eina_Hash*>::value && + !std::is_same<T, const Eina_List*>::value + >::type* = 0) +{ + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Not implemented yet"))); + throw std::logic_error(""); +} + +// TODO: Fix for const types +template <typename T, typename K> +inline Eina_Accessor* get_value_from_javascript( + v8::Local<v8::Value> v, + v8::Isolate* isolate, + const char*, + value_tag<complex_tag<Eina_Accessor *, T, K>>, + bool throw_js_exception = true) +{ + if(v->IsNull()) + return nullptr; + else if(v->IsObject()) + { + using wrapped_type = typename container_wrapper<T>::type; + v8::Local<v8::Object> object = v->ToObject(); + auto& acc = import_accessor<wrapped_type>(object); + return acc.native_handle(); + } + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected Eolian accessor type"))); + throw std::logic_error(""); +} + +template <typename...I> +inline const Eina_Accessor* get_value_from_javascript( + v8::Local<v8::Value> v, + v8::Isolate* isolate, + const char* class_name, + value_tag<complex_tag<const Eina_Accessor *, I...>>, + bool throw_js_exception = true) +{ + return get_value_from_javascript(v, isolate, class_name, value_tag<complex_tag<Eina_Accessor *, I...>>{}, throw_js_exception); +} + +template <typename...I> +inline Eina_Array* get_value_from_javascript( + v8::Local<v8::Value> v, + v8::Isolate* isolate, + const char*, + value_tag<complex_tag<Eina_Array *, I...>>, + bool throw_js_exception = true) +{ + if(v->IsNull()) + return nullptr; + else if(v->IsObject()) + { + v8::Local<v8::Object> object = v->ToObject(); + if(object->InternalFieldCount() == 1) + { + eina_container_base* cbase = compatibility_get_pointer_internal_field<eina_container_base*>(object, 0); + return static_cast<Eina_Array*>(cbase->get_container_native_handle()); + } + } + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected Eolian list type"))); + throw std::logic_error(""); + return nullptr; +} + +template <typename...I> +inline const Eina_Array* get_value_from_javascript( + v8::Local<v8::Value> v, + v8::Isolate* isolate, + const char* class_name, + value_tag<complex_tag<const Eina_Array *, I...>>, + bool throw_js_exception = true) +{ + return get_value_from_javascript(v, isolate, class_name, value_tag<complex_tag<Eina_Array *, I...>>{}, throw_js_exception); +} + +template <typename...I> +inline Eina_Iterator* get_value_from_javascript( + v8::Local<v8::Value>, + v8::Isolate* isolate, + const char*, + value_tag<complex_tag<Eina_Iterator *, I...>> tag, + bool throw_js_exception = true) +{ + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Not implemented yet"))); + throw std::logic_error(""); +} + +template <typename...I> +inline const Eina_Iterator* get_value_from_javascript( + v8::Local<v8::Value> v, + v8::Isolate* isolate, + const char* class_name, + value_tag<complex_tag<const Eina_Iterator *, I...>>, + bool throw_js_exception = true) +{ + return get_value_from_javascript(v, isolate, class_name, value_tag<complex_tag<Eina_Iterator *, I...>>{}, throw_js_exception); +} + +template <typename T, typename...U> +inline Eina_Hash* get_value_from_javascript( + v8::Local<v8::Value>, + v8::Isolate* isolate, + const char*, + value_tag<complex_tag<Eina_Hash *, T, U...>> tag, + bool throw_js_exception = true) +{ + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Not implemented yet"))); + throw std::logic_error(""); +} + +template <typename T, typename...U> +inline const Eina_Hash* get_value_from_javascript( + v8::Local<v8::Value> v, + v8::Isolate* isolate, + const char* class_name, + value_tag<complex_tag<const Eina_Hash *, T, U...>>, + bool throw_js_exception = true) +{ + return get_value_from_javascript(v, isolate, class_name, value_tag<complex_tag<Eina_Hash *, T, U...>>{}, throw_js_exception); +} + +template <typename...I> +inline Eina_List* get_value_from_javascript( + v8::Local<v8::Value> v, + v8::Isolate* isolate, + const char*, + value_tag<complex_tag<Eina_List *, I...>> /*tag*/, + bool throw_js_exception = true) +{ + if(v->IsNull()) + return nullptr; + else if(v->IsObject()) + { + v8::Local<v8::Object> object = v->ToObject(); + if(object->InternalFieldCount() == 1) + { + eina_container_base* cbase = compatibility_get_pointer_internal_field<eina_container_base*>(object, 0); + return static_cast<Eina_List*>(cbase->get_container_native_handle()); + } + } + if (throw_js_exception) + eina::js::compatibility_throw + (isolate, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(isolate, "Type expected is different. Expected Eolian list type"))); + throw std::logic_error(""); + return nullptr; +} + +template <typename...I> +inline const Eina_List* get_value_from_javascript( + v8::Local<v8::Value> v, + v8::Isolate* isolate, + const char* class_name, + value_tag<complex_tag<const Eina_List *, I...>>, + bool throw_js_exception = true) +{ + return get_value_from_javascript(v, isolate, class_name, value_tag<complex_tag<Eina_List *, I...>>{}, throw_js_exception); +} + +inline const void* get_value_from_javascript + (v8::Local<v8::Value>, + v8::Isolate*, + const char*, + value_tag<const void *>) +{ + return nullptr; +} + + +typedef void (*Evas_Smart_Cb)(void*, _Eo_Opaque*, void*); + +inline Evas_Smart_Cb get_value_from_javascript ( + v8::Local<v8::Value>, + v8::Isolate*, + const char*, + value_tag<Evas_Smart_Cb>) +{ + return nullptr; +} + +} } } + +#endif 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 new file mode 100644 index 0000000000..655b1b1974 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_get_value_from_c.hh @@ -0,0 +1,261 @@ +#ifndef EFL_EINA_JS_GET_VALUE_FROM_C_HH +#define EFL_EINA_JS_GET_VALUE_FROM_C_HH + +#include <eina_js_compatibility.hh> + +#include <type_traits> +#include <cstdlib> +#include <typeinfo> +#include <memory> + +namespace efl { namespace eina { namespace js { + +template <typename T> struct print_tag {}; + +template <typename T> +inline v8::Local<v8::Value> +get_value_from_c(T v, v8::Isolate* isolate, const char* + , typename std::enable_if<std::is_integral<typename std::remove_reference<T>::type>::value && !std::is_same<T, Eina_Bool>::value>::type* = 0) +{ + return eina::js::compatibility_new<v8::Integer>(isolate, v); +} + +template <typename T> +inline v8::Local<v8::Value> +get_value_from_c(T v, v8::Isolate* isolate, const char* + , typename std::enable_if<std::is_enum<typename std::remove_reference<T>::type>::value>::type* = 0) +{ + return eina::js::compatibility_new<v8::Integer>(isolate, v); +} + +template <typename T> +inline v8::Local<v8::Value> +get_value_from_c(T v, v8::Isolate* isolate, const char* + , typename std::enable_if<std::is_same<typename std::remove_reference<T>::type, Eina_Bool>::value>::type* = 0) +{ + return eina::js::compatibility_new<v8::Boolean>(isolate, v); +} + +template <typename T> +inline v8::Local<T> +get_value_from_c(v8::Local<T> v, v8::Isolate*, const char*) +{ + return v; +} + +template <typename T> +inline v8::Local<v8::Value> +get_value_from_c(T v, v8::Isolate* isolate, const char* + , typename std::enable_if<std::is_floating_point<typename std::remove_reference<T>::type>::value>::type* = 0) +{ + return eina::js::compatibility_new<v8::Number>(isolate, v); +} + +inline v8::Local<v8::Value> +get_value_from_c(const char* v, v8::Isolate* isolate, const char*) +{ + if (!v) + return v8::Null(isolate); + + return eina::js::compatibility_new<v8::String>(isolate, v); +} + +inline v8::Local<v8::Value> +get_value_from_c(char* v, v8::Isolate* isolate, const char* class_name) +{ + return js::get_value_from_c(const_cast<const char*>(v), isolate, class_name); +} + +inline v8::Local<v8::Value> +get_value_from_c(void*, v8::Isolate*, const char*) +{ + // TODO: create Extern? + std::cerr << "aborting because we don't know the type void*" << std::endl; + std::abort(); +} + +inline v8::Local<v8::Value> +get_value_from_c(const void*, v8::Isolate*, const char*) +{ + // TODO: create Extern? + std::cerr << "aborting because we don't know the type void*" << std::endl; + std::abort(); +} + +// For function pointer types +template <typename T> +inline v8::Local<v8::Value> +get_value_from_c(T, v8::Isolate*, const char* + , typename std::enable_if + <std::is_pointer<typename std::remove_reference<T>::type>::value + && std::is_function<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value + >::type* = 0) +{ + // TODO: create Extern? + std::cerr << "aborting because we don't know the type " << typeid(print_tag<T>).name() << std::endl; + std::abort(); +} + +// For all non-pointer types that are not handled +template <typename T> +inline v8::Local<v8::Value> +get_value_from_c(T, v8::Isolate*, const char* + , typename std::enable_if + <!std::is_pointer<typename std::remove_reference<T>::type>::value + && !std::is_integral<typename std::remove_reference<T>::type>::value + && !std::is_floating_point<typename std::remove_reference<T>::type>::value + && !std::is_enum<typename std::remove_reference<T>::type>::value + && !std::is_same<typename std::remove_reference<T>::type, Eina_Bool>::value + && !js::is_struct_tag<typename std::remove_reference<T>::type>::value + && !js::is_struct_ptr_tag<typename std::remove_reference<T>::type>::value + && !js::is_complex_tag<typename std::remove_reference<T>::type>::value + >::type* = 0) +{ + std::cerr << "aborting because we don't know the type " << typeid(print_tag<T>).name() << std::endl; + std::abort(); +} + +// For all non-handled pointer types (which are not function pointers): +// - we try to dereference it in the SFINAE +// - if it matches we call get_value_from_c for the dereferenced type +// - if it fails (probably because it is opaque) the void* or const void* +// overload will take place (implicit conversion) +template <typename T> +inline auto +get_value_from_c(T object, v8::Isolate* isolate, const char* class_name + , typename std::enable_if< + (std::is_pointer<typename std::remove_reference<T>::type>::value + && !std::is_function<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value + ) + && !(std::is_same<typename std::remove_reference<T>::type, char*>::value || + std::is_same<typename std::remove_reference<T>::type, const char*>::value || + std::is_same<typename std::remove_reference<T>::type, void*>::value || + std::is_same<typename std::remove_reference<T>::type, const void*>::value || + std::is_same<typename std::remove_reference<T>::type, Eo*>::value || + std::is_same<typename std::remove_reference<T>::type, const Eo*>::value + )>::type* = 0) -> decltype(get_value_from_c(*object, isolate, class_name)) +{ + std::cerr << "dereferencing " << typeid(print_tag<T>).name() << std::endl; + return get_value_from_c(*object, isolate, class_name); +} + +inline v8::Local<v8::Value> +get_value_from_c(Eo* v, v8::Isolate* isolate, const char* class_name) +{ + auto ctor = ::efl::eina::js::get_class_constructor(class_name); + return new_v8_external_instance(ctor, v, isolate); +} + +inline v8::Local<v8::Value> +get_value_from_c(const Eo* v, v8::Isolate* isolate, const char* class_name) +{ + // TODO: implement const objects? + auto ctor = ::efl::eina::js::get_class_constructor(class_name); + return new_v8_external_instance(ctor, const_cast<Eo*>(v), isolate); +} + +template <typename T> +inline v8::Local<v8::Value> +get_value_from_c(struct_ptr_tag<T> v, v8::Isolate* isolate, const char* class_name) +{ + // TODO: implement const structs? + auto ctor = ::efl::eina::js::get_class_constructor(class_name); + return new_v8_external_instance(ctor, const_cast<typename std::remove_const<T>::type>(v.value), isolate); +} + +template <typename T> +inline v8::Local<v8::Value> +get_value_from_c(struct_tag<T> v, v8::Isolate* isolate, const char* class_name) +{ + return get_value_from_c(struct_ptr_tag<T*>{new T(v.value)}, isolate, class_name); +} + +template <typename T, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<Eina_Accessor *, T, K> v, v8::Isolate* isolate, const char*) +{ + using wrapped_type = typename container_wrapper<T>::type; + auto a = new ::efl::eina::accessor<wrapped_type>{v.value}; + return export_accessor<T>(*a , isolate, K::class_name()); +} + +template <typename T, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<const Eina_Accessor *, T, K> v, v8::Isolate* isolate, const char* class_name) +{ + // TODO implement const accessor? + return get_value_from_c(efl::eina::js::complex_tag<Eina_Accessor*, T, K>{const_cast<Eina_Accessor*>(v.value)}, isolate, class_name); +} + +template <typename T, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<Eina_Array *, T, K> v, v8::Isolate* isolate, const char*) +{ + // TODO: use unique_ptr for eina_array to avoid leak ? + auto o = new ::efl::eina::js::range_eina_array<T, K>(v.value); + auto ctor = get_array_instance_template(); + return new_v8_external_instance(ctor, o, isolate); +} + +template <typename T, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<const Eina_Array *, T, K> v, v8::Isolate* isolate, const char* class_name) +{ + // TODO: implement const array? + return get_value_from_c(efl::eina::js::complex_tag<Eina_Array *, T, K>{const_cast<Eina_Array*>(v.value)}, isolate, class_name); +} + +template <typename T, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<Eina_Iterator *, T, K>, v8::Isolate*, const char*) +{ + std::cerr << "get_value_from_c for Eina_Iterator not implemented. Aborting..." << std::endl; + std::abort(); +} + +template <typename T, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<const Eina_Iterator *, T, K>, v8::Isolate*, const char*) +{ + std::cerr << "get_value_from_c for Eina_Iterator not implemented. Aborting..." << std::endl; + std::abort(); +} + +template <typename T, typename U, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<Eina_Hash *, T, U, K>, v8::Isolate*, const char*) +{ + std::cerr << "get_value_from_c for Eina_Hash not implemented. Aborting..." << std::endl; + std::abort(); +} + +template <typename T, typename U, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<const Eina_Hash *, T, U, K>, v8::Isolate*, const char*) +{ + std::cerr << "get_value_from_c for Eina_Hash not implemented. Aborting..." << std::endl; + std::abort(); +} + +template <typename T, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<Eina_List *, T, K> v, v8::Isolate* isolate, const char*) +{ + // TODO: ensure eina_list ownership ??? + auto o = new ::efl::eina::js::range_eina_list<T, K>(v.value); + auto ctor = get_list_instance_template(); + return new_v8_external_instance(ctor, o, isolate); +} + +template <typename T, typename K> +inline v8::Local<v8::Value> +get_value_from_c(efl::eina::js::complex_tag<const Eina_List *, T, K> v, v8::Isolate* isolate, const char* class_name) +{ + // TODO: implement const list? + return get_value_from_c(efl::eina::js::complex_tag<Eina_List *, T, K>{const_cast<Eina_List*>(v.value)}, isolate, class_name); +} + + +} } } + +#endif diff --git a/src/bindings/js/eina_js/eina_js_iterator.cc b/src/bindings/js/eina_js/eina_js_iterator.cc new file mode 100644 index 0000000000..d2480b8be2 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_iterator.cc @@ -0,0 +1,32 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eina.hh> +#include <Eina_Js.hh> + +namespace efl { namespace eina { namespace js { + +EAPI +void register_destroy_iterator(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + typedef void (*deleter_t)(void*); + + auto f = [](compatibility_callback_info_type info) -> compatibility_return_type + { + if (info.Length() != 1 || !info[0]->IsObject()) + return compatibility_return(); + + v8::Handle<v8::Object> o = info[0]->ToObject(); + + deleter_t deleter = compatibility_get_pointer_internal_field<deleter_t>(o, 1); + deleter(compatibility_get_pointer_internal_field<>(o, 0)); + return compatibility_return(); + }; + + global->Set(name, compatibility_new<v8::FunctionTemplate>(isolate, f)->GetFunction()); +} + +} } } // namespace efl { namespace js { diff --git a/src/bindings/js/eina_js/eina_js_iterator.hh b/src/bindings/js/eina_js/eina_js_iterator.hh new file mode 100644 index 0000000000..ed0066bf0b --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_iterator.hh @@ -0,0 +1,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 */ diff --git a/src/bindings/js/eina_js/eina_js_list.hh b/src/bindings/js/eina_js/eina_js_list.hh new file mode 100644 index 0000000000..6ab0521847 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_list.hh @@ -0,0 +1,132 @@ +#ifndef EINA_JS_LIST_HH +#define EINA_JS_LIST_HH + +#include <iostream> + +#include <eina_js_container.hh> +#include <eina_js_compatibility.hh> + +#include <iterator> + +namespace efl { namespace eina { namespace js { + +template <typename T, typename K, typename W> +struct eina_list : eina_container_common<efl::eina::list + <W + , typename std::conditional + <std::is_base_of<efl::eo::concrete, W>::value + , efl::eina::eo_clone_allocator + , efl::eina::malloc_clone_allocator + >::type>, T, K> +{ + typedef eina_container_common<efl::eina::list<W + , typename std::conditional + <std::is_base_of<efl::eo::concrete, W>::value + , efl::eina::eo_clone_allocator + , efl::eina::malloc_clone_allocator + >::type>, T, K> base_type; + using base_type::base_type; + typedef typename base_type::container_type container_type; + + eina_container_base* concat(eina_container_base const& other) const + { + return detail::concat(*this, other); + } + eina_container_base* slice(std::int64_t i, std::int64_t j) const + { + return detail::slice(*this, i, j); + } + v8::Local<v8::Value> set(v8::Isolate* isolate, std::size_t index, v8::Local<v8::Value> v) + { + return detail::set<T,W>(isolate, *this, index, v); + } + int push(v8::Isolate* isolate, v8::Local<v8::Value> v) + { + return detail::push<T,W>(isolate, *this, v); + } + v8::Local<v8::Value> pop(v8::Isolate* isolate) + { + return detail::pop<T,W,K>(isolate, *this); + } + js::container_type get_container_type() const { return list_container_type; } +}; + +template <typename T, typename K, typename W> +struct range_eina_list : eina_container_common<typename efl::eina::range_list<W>, T, K> +{ + typedef eina_container_common<efl::eina::range_list<W>, T, K> base_type; + using base_type::base_type; + typedef typename base_type::container_type container_type; + typedef typename std::conditional + <std::is_base_of<efl::eo::concrete, W>::value + , efl::eina::eo_clone_allocator + , efl::eina::malloc_clone_allocator + >::type clone_allocator_type; + + eina_container_base* concat(eina_container_base const& other) const + { + range_eina_list<T, K, W>const& rhs = static_cast<range_eina_list<T, K, W>const&>(other); + efl::eina::list<W, clone_allocator_type> + list(this->_container.begin(), this->_container.end()); + list.insert(list.end(), rhs._container.begin(), rhs._container.end()); + return new eina::js::eina_list<T, K, W>(list.release_native_handle()); + } + eina_container_base* slice(std::int64_t i, std::int64_t j) const + { + efl::eina::list<W, clone_allocator_type> + list(std::next(this->_container.begin(), i), std::next(this->_container.begin(), j)); + return new eina::js::eina_list<T, K, W>(list.release_native_handle()); + } + v8::Local<v8::Value> set(v8::Isolate* isolate, std::size_t, v8::Local<v8::Value>) + { + return v8::Undefined(isolate); + } + int push(v8::Isolate*, v8::Local<v8::Value>) + { + return this->size(); + } + v8::Local<v8::Value> pop(v8::Isolate* isolate) + { + return v8::Undefined(isolate); + } + js::container_type get_container_type() const { return list_container_type; } +}; + +// Problematic types. +template <> +struct eina_list<_Elm_Calendar_Mark*, js::nonclass_cls_name_getter, _Elm_Calendar_Mark> + : empty_container_base +{ eina_list(Eina_List const*){} }; +template <> +struct eina_list<Elm_Gen_Item*, js::nonclass_cls_name_getter, Elm_Gen_Item> + : empty_container_base +{ eina_list(Eina_List const*){} }; +template <> +struct eina_list<_Evas_Textblock_Rectangle*, js::nonclass_cls_name_getter, _Evas_Textblock_Rectangle> + : empty_container_base +{ eina_list(Eina_List const*){} }; +template <> +struct eina_list<_Elm_Map_Overlay*, js::nonclass_cls_name_getter, _Elm_Map_Overlay> + : empty_container_base +{ eina_list(Eina_List const*){} }; + +template <> +struct range_eina_list<_Elm_Calendar_Mark*, js::nonclass_cls_name_getter, _Elm_Calendar_Mark> + : empty_container_base +{ range_eina_list(Eina_List const*){} }; +template <> +struct range_eina_list<Elm_Gen_Item*, js::nonclass_cls_name_getter, Elm_Gen_Item> + : empty_container_base +{ range_eina_list(Eina_List const*){} }; +template <> +struct range_eina_list<_Evas_Textblock_Rectangle*, js::nonclass_cls_name_getter, _Evas_Textblock_Rectangle> + : empty_container_base +{ range_eina_list(Eina_List const*){} }; +template <> +struct range_eina_list<_Elm_Map_Overlay*, js::nonclass_cls_name_getter, _Elm_Map_Overlay> + : empty_container_base +{ range_eina_list(Eina_List const*){} }; + +} } } + +#endif diff --git a/src/bindings/js/eina_js/eina_js_log.cc b/src/bindings/js/eina_js/eina_js_log.cc new file mode 100644 index 0000000000..415a827d1f --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_log.cc @@ -0,0 +1,742 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string> +#include <map> +#include <Eina_Js.hh> + +namespace efl { namespace eina { namespace js { + +v8::Local<v8::String> to_v8_string(v8::Isolate *isolate, const char *fmt, + va_list args) +{ + using v8::String; +#if 0 + /* TODO: unfortunately, the elegant and exception-safe version isn't + compiling (yet!) */ + efl::eina::stringshare s(eina_stringshare_vprintf(fmt, args), + efl::eina::steal_stringshare_ref); + return compatibility_new<String>(isolate, s.data(), String::kNormalString, + s.size()); +#else + auto s = eina_stringshare_vprintf(fmt, args); + auto ret = compatibility_new<String>(isolate, s); + eina_stringshare_del(s); + return ret; +#endif +} + +static global_ref<v8::Value> js_eina_log_print_cb_data; +static std::map<int, std::string> js_eina_log_color_map; + +static void js_eina_log_print_cb(const Eina_Log_Domain *d, Eina_Log_Level level, + const char *file, const char *fnc, int line, + const char *fmt, void */*data*/, va_list args) +{ + using v8::String; + using v8::Integer; + using v8::Isolate; + + Isolate *const isolate = Isolate::GetCurrent(); + constexpr unsigned argc = 7; + + v8::Handle<v8::Value> argv[argc] = { + compatibility_new<String>(isolate, d->name ? d->name : ""), + compatibility_new<String>(isolate, d->color ? d->color : ""), + compatibility_new<Integer>(isolate, static_cast<int>(level)), + compatibility_new<String>(isolate, file), + compatibility_new<String>(isolate, fnc), + compatibility_new<Integer>(isolate, line), + to_v8_string(isolate, fmt, args) + }; + + auto o = js_eina_log_print_cb_data.handle(); + v8::Function::Cast(*o)->Call(o->ToObject(), argc, argv); +} + +static bool valid_level_conversion(int src, Eina_Log_Level &dst) +{ + if (src != EINA_LOG_LEVEL_CRITICAL && src != EINA_LOG_LEVEL_ERR + && src != EINA_LOG_LEVEL_WARN && src != EINA_LOG_LEVEL_INFO + && src != EINA_LOG_LEVEL_DBG) + return false; + + dst = static_cast<Eina_Log_Level>(src); + return true; +} + +EAPI +void register_log_print(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::String; + using v8::StackTrace; + using v8::FunctionTemplate; + + auto print = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 3 || !args[0]->IsNumber() || !args[1]->IsNumber() + || !args[2]->IsString()) + return compatibility_return(); + + Eina_Log_Level level; + if (!valid_level_conversion(args[1]->NumberValue(), level)) + return compatibility_return(); + + auto frame = compatibility_current_stack_trace<>(args.GetIsolate(), 1, + StackTrace::kDetailed)->GetFrame(0); + + eina_log_print(args[0]->NumberValue(), level, + *String::Utf8Value(frame->GetScriptNameOrSourceURL()), + *String::Utf8Value(frame->GetFunctionName()), + frame->GetLineNumber(), "%s", + *String::Utf8Value(args[2])); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, print) + ->GetFunction()); +} + +EAPI +void register_log_domain_register(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::Local; + using v8::String; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) + return compatibility_return(); + + // We duplicate the color string as eina takes a const char* but does take care of + // its lifetime, assuming a ever lasting string. + std::string color = *String::Utf8Value(args[1]); + int d = eina_log_domain_register(*String::Utf8Value(args[0]), + color.c_str()); + js_eina_log_color_map[d] = color; + + auto isolate = args.GetIsolate(); + return compatibility_return(value_cast<Local<Value>>(d, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_domain_unregister(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + int domain = args[0]->NumberValue(); + eina_log_domain_unregister(domain); + js_eina_log_color_map.erase(domain); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_domain_registered_level_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::Local; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + int l = eina_log_domain_registered_level_get(args[0]->NumberValue()); + auto isolate = args.GetIsolate(); + return compatibility_return(value_cast<Local<Value>>(l, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_domain_registered_level_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) + return compatibility_return(); + + eina_log_domain_registered_level_set(args[0]->NumberValue(), + args[1]->NumberValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_print_cb_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + js_eina_log_print_cb_data + = global_ref<v8::Value>(args.GetIsolate(), args[0]); + eina_log_print_cb_set(js_eina_log_print_cb, NULL); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_level_set(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + eina_log_level_set(args[0]->NumberValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_level_get(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + using v8::Integer; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + int l = eina_log_level_get(); + auto ret = compatibility_new<Integer>(args.GetIsolate(), l); + return compatibility_return(ret, args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_level_check(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + using v8::Boolean; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + bool b = eina_log_level_check(args[0]->NumberValue()); + auto ret = compatibility_new<Boolean>(args.GetIsolate(), b); + return compatibility_return(ret, args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_color_disable_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsBoolean()) + return compatibility_return(); + + eina_log_color_disable_set(args[0]->BooleanValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_color_disable_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::Boolean; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + bool b = eina_log_color_disable_get(); + auto ret = compatibility_new<Boolean>(args.GetIsolate(), b); + return compatibility_return(ret, args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_file_disable_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsBoolean()) + return compatibility_return(); + + eina_log_file_disable_set(args[0]->BooleanValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_file_disable_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::Boolean; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + bool b = eina_log_file_disable_get(); + auto ret = compatibility_new<Boolean>(args.GetIsolate(), b); + return compatibility_return(ret, args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_function_disable_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsBoolean()) + return compatibility_return(); + + eina_log_function_disable_set(args[0]->BooleanValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_function_disable_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::Boolean; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + bool b = eina_log_function_disable_get(); + auto ret = compatibility_new<Boolean>(args.GetIsolate(), b); + return compatibility_return(ret, args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_abort_on_critical_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsBoolean()) + return compatibility_return(); + + eina_log_abort_on_critical_set(args[0]->BooleanValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_abort_on_critical_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::Boolean; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + bool b = eina_log_abort_on_critical_get(); + auto ret = compatibility_new<Boolean>(args.GetIsolate(), b); + return compatibility_return(ret, args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_abort_on_critical_level_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + eina_log_abort_on_critical_level_set(args[0]->NumberValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_abort_on_critical_level_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + using v8::Integer; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + int l = eina_log_abort_on_critical_level_get(); + auto ret = compatibility_new<Integer>(args.GetIsolate(), l); + return compatibility_return(ret, args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_domain_level_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + using v8::String; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsNumber()) + return compatibility_return(); + + eina_log_domain_level_set(*String::Utf8Value(args[0]), + args[1]->NumberValue()); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_domain_level_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + using v8::String; + using v8::Integer; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsString()) + return compatibility_return(); + + int l = eina_log_domain_level_get(*String::Utf8Value(args[0])); + auto ret = compatibility_new<Integer>(args.GetIsolate(), l); + return compatibility_return(ret, args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_log_timing(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Value; + using v8::FunctionTemplate; + using v8::String; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 3 || !args[0]->IsNumber() || !args[1]->IsNumber() + || !args[2]->IsString()) { + return compatibility_return(); + } + + eina_log_timing(args[0]->NumberValue(), + static_cast<Eina_Log_State>(args[1]->NumberValue()), + *String::Utf8Value(args[2])); + return compatibility_return(); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +static void register_constant(v8::Isolate *isolate, v8::Handle<v8::Object> global, int value, const char* name) +{ + global->Set(compatibility_new<v8::String>(isolate, name), compatibility_new<v8::Integer>(isolate, value)); +} + +static void register_constant(v8::Isolate *isolate, v8::Handle<v8::Object> global, const char* value, const char* name) +{ + global->Set(compatibility_new<v8::String>(isolate, name), compatibility_new<v8::String>(isolate, value)); +} + +EAPI void register_log_constants(v8::Isolate *isolate, v8::Handle<v8::Object> global) +{ + register_constant(isolate, global, EINA_LOG_STATE_START, "LOG_STATE_START"); + register_constant(isolate, global, EINA_LOG_STATE_START, "LOG_STATE_STOP"); + + register_constant(isolate, global, EINA_LOG_LEVEL_CRITICAL, "LOG_LEVEL_CRITICAL"); + register_constant(isolate, global, EINA_LOG_LEVEL_ERR, "LOG_LEVEL_ERR"); + register_constant(isolate, global, EINA_LOG_LEVEL_WARN, "LOG_LEVEL_WARN"); + register_constant(isolate, global, EINA_LOG_LEVEL_INFO, "LOG_LEVEL_INFO"); + register_constant(isolate, global, EINA_LOG_LEVEL_DBG, "LOG_LEVEL_DBG"); + register_constant(isolate, global, EINA_LOG_LEVELS, "LOG_LEVELS"); + register_constant(isolate, global, EINA_LOG_LEVEL_UNKNOWN, "LOG_LEVEL_UNKNOWN"); + + register_constant(isolate, global, EINA_LOG_DOMAIN_GLOBAL, "LOG_DOMAIN_GLOBAL"); + + register_constant(isolate, global, EINA_COLOR_LIGHTRED, "COLOR_LIGHTRED"); + register_constant(isolate, global, EINA_COLOR_RED, "COLOR_RED"); + register_constant(isolate, global, EINA_COLOR_LIGHTBLUE, "COLOR_LIGHTBLUE"); + register_constant(isolate, global, EINA_COLOR_BLUE, "COLOR_BLUE"); + register_constant(isolate, global, EINA_COLOR_GREEN, "COLOR_GREEN"); + register_constant(isolate, global, EINA_COLOR_YELLOW, "COLOR_YELLOW"); + register_constant(isolate, global, EINA_COLOR_ORANGE, "COLOR_ORANGE"); + register_constant(isolate, global, EINA_COLOR_WHITE, "COLOR_WHITE"); + register_constant(isolate, global, EINA_COLOR_LIGHTCYAN, "COLOR_LIGHTCYAN"); + register_constant(isolate, global, EINA_COLOR_CYAN, "COLOR_CYAN"); + register_constant(isolate, global, EINA_COLOR_RESET, "COLOR_RESET"); + register_constant(isolate, global, EINA_COLOR_HIGH, "COLOR_HIGH"); +} + + +#define REGISTER_LOG_HELPER(isolate, global, level, name) \ +{ \ + using v8::String; \ + using v8::FunctionTemplate;\ + using v8::StackTrace;\ +\ + auto wrapper = [](compatibility_callback_info_type args)\ + -> compatibility_return_type {\ + if (args.Length() != 1 || !args[0]->IsString()) {\ + eina::js::compatibility_throw \ + (args.GetIsolate(), v8::Exception::TypeError(\ + eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Message must be a string."))); \ + return compatibility_return();\ + } \ +\ + auto frame = compatibility_current_stack_trace<>(args.GetIsolate(), 1,\ + StackTrace::kDetailed)->GetFrame(0);\ +\ + eina_log_print(EINA_LOG_DOMAIN_GLOBAL, level,\ + *String::Utf8Value(frame->GetScriptNameOrSourceURL()),\ + *String::Utf8Value(frame->GetFunctionName()),\ + frame->GetLineNumber(), "%s",\ + *String::Utf8Value(args[0]));\ +\ + return compatibility_return();\ + };\ +\ + global->Set(compatibility_new<String>(isolate, name),\ + compatibility_new<FunctionTemplate>(isolate, wrapper)->GetFunction());\ +} + +EAPI void register_log_helpers(v8::Isolate *isolate, v8::Handle<v8::Object> global) +{ + REGISTER_LOG_HELPER(isolate, global, EINA_LOG_LEVEL_CRITICAL, "logCritical"); + REGISTER_LOG_HELPER(isolate, global, EINA_LOG_LEVEL_ERR, "logError"); + REGISTER_LOG_HELPER(isolate, global, EINA_LOG_LEVEL_WARN, "logWarning"); + REGISTER_LOG_HELPER(isolate, global, EINA_LOG_LEVEL_INFO, "logInfo"); + REGISTER_LOG_HELPER(isolate, global, EINA_LOG_LEVEL_DBG, "logDebug"); +} + +} } } // namespace efl { namespace js { + +EAPI +void eina_log_register(v8::Handle<v8::Object> exports, v8::Isolate* isolate) +{ + using efl::eina::js::compatibility_new; + + efl::eina::js::register_log_domain_register(isolate, exports + , compatibility_new<v8::String>(isolate, "registerLogDomain")); + efl::eina::js::register_log_domain_unregister(isolate, exports + , compatibility_new<v8::String>(isolate, "unregisterLogDomain")); + efl::eina::js::register_log_domain_registered_level_set(isolate, exports + , compatibility_new<v8::String>(isolate, "setLogDomainRegisteredLevel")); + efl::eina::js::register_log_domain_registered_level_get(isolate, exports + , compatibility_new<v8::String>(isolate, "getLogDomainRegisteredLevel")); + + efl::eina::js::register_log_print(isolate, exports + , compatibility_new<v8::String>(isolate, "logPrint" +)); + efl::eina::js::register_log_print_cb_set(isolate, exports + , compatibility_new<v8::String>(isolate, "setLogPrintCb" +)); + + efl::eina::js::register_log_level_set(isolate, exports + , compatibility_new<v8::String>(isolate, "setLogLevel" +)); + efl::eina::js::register_log_level_get(isolate, exports + , compatibility_new<v8::String>(isolate, "getLogLevel" +)); + efl::eina::js::register_log_level_check(isolate, exports + , compatibility_new<v8::String>(isolate, "checkLogLevel" +)); + + efl::eina::js::register_log_color_disable_set(isolate, exports + , compatibility_new<v8::String>(isolate, "setLogColorDisable" +)); + efl::eina::js::register_log_color_disable_get(isolate, exports + , compatibility_new<v8::String>(isolate, "getLogColorDisable" +)); + + efl::eina::js::register_log_file_disable_set(isolate, exports + , compatibility_new<v8::String>(isolate, "setLogFileDisable" +)); + efl::eina::js::register_log_file_disable_get(isolate, exports + , compatibility_new<v8::String>(isolate, "getLogFileDisable" +)); + + efl::eina::js::register_log_function_disable_set(isolate, exports + , compatibility_new<v8::String>(isolate, "setLogFunctionDisable" +)); + efl::eina::js::register_log_function_disable_get(isolate, exports + , compatibility_new<v8::String>(isolate, "getLogFunctionDisable" +)); + + efl::eina::js::register_log_abort_on_critical_set(isolate, exports + , compatibility_new<v8::String>(isolate, "setLogAbortOnCritical" +)); + efl::eina::js::register_log_abort_on_critical_get(isolate, exports + , compatibility_new<v8::String>(isolate, "getLogAbortOnCritical" +)); + efl::eina::js::register_log_abort_on_critical_level_set(isolate, exports + , compatibility_new<v8::String>(isolate, "setLogAbortOnCriticalLevel" +)); + efl::eina::js::register_log_abort_on_critical_level_get(isolate, exports + , compatibility_new<v8::String>(isolate, "getLogAbortOnCriticalLevel" +)); + + efl::eina::js::register_log_domain_level_set(isolate, exports + , compatibility_new<v8::String>(isolate, "setLogDomainLevel" +)); + efl::eina::js::register_log_domain_level_get(isolate, exports + , compatibility_new<v8::String>(isolate, "getLogDomainLevel" +)); + + efl::eina::js::register_log_timing(isolate, exports + , compatibility_new<v8::String>(isolate, "logTiming")); + + efl::eina::js::register_log_constants(isolate, exports); + + efl::eina::js::register_log_helpers(isolate, exports); +} diff --git a/src/bindings/js/eina_js/eina_js_log.hh b/src/bindings/js/eina_js/eina_js_log.hh new file mode 100644 index 0000000000..bed5a1bf9d --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_log.hh @@ -0,0 +1,133 @@ +#ifndef EINA_JS_LOG_HH +#define EINA_JS_LOG_HH + +#include <type_traits> + +namespace efl { namespace eina { namespace js { + +using ::efl::eina::js::compatibility_new; +using ::efl::eina::js::compatibility_return_type; +using ::efl::eina::js::compatibility_callback_info_type; +using ::efl::eina::js::compatibility_return; +using ::efl::eina::js::compatibility_get_pointer_internal_field; +using ::efl::eina::js::compatibility_set_pointer_internal_field; + +void register_log_level_critical(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_level_err(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_level_warn(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_level_info(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_level_dbg(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_domain_global(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_print(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_domain_register(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_domain_unregister(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_domain_registered_level_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_domain_registered_level_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_print_cb_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_level_set(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_level_get(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_level_check(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_color_disable_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_color_disable_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_file_disable_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_file_disable_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_function_disable_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_function_disable_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_abort_on_critical_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_abort_on_critical_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_abort_on_critical_level_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_abort_on_critical_level_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_domain_level_set(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_domain_level_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_state_start(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_state_stop(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +void register_log_timing(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +} } } // namespace efl::js + +EAPI void eina_log_register(v8::Handle<v8::Object> exports, v8::Isolate* isolate); + +#endif /* EINA_JS_LOG_HH */ diff --git a/src/bindings/js/eina_js/eina_js_node.hh b/src/bindings/js/eina_js/eina_js_node.hh new file mode 100644 index 0000000000..cfa4169d82 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_node.hh @@ -0,0 +1,14 @@ + +#ifdef HAVE_NODE_NODE_H +#include <node/node.h> +#elif defined(HAVE_NODEJS_DEPS_NODE_NODE_H) +#include <nodejs/deps/node/node.h> +#elif defined(HAVE_NODEJS_DEPS_NODE_INCLUDE_NODE_H) +#include <nodejs/deps/node/include/node.h> +#elif defined(HAVE_NODEJS_SRC_NODE_H) +#include <nodejs/src/node.h> +#elif defined(HAVE_NODE_H) +#include <node.h> +#else +#error We must have at least one node header to include +#endif diff --git a/src/bindings/js/eina_js/eina_js_value.cc b/src/bindings/js/eina_js/eina_js_value.cc new file mode 100644 index 0000000000..5b5b822160 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_value.cc @@ -0,0 +1,132 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eina_Js.hh> + +namespace efl { namespace eina { namespace js { + +namespace { + +compatibility_return_type eina_value_set(compatibility_callback_info_type args) +{ + if (args.Length() != 1) + return compatibility_return(); + + void *ptr = js::compatibility_get_pointer_internal_field(args.Holder(), 0); + v8::Isolate *isolate = args.GetIsolate(); + try { + *static_cast<value*>(ptr) = value_cast<value>(args[0]); + } catch(const std::bad_cast &e) { + v8::Local<v8::Object> je = compatibility_new<v8::Object>(isolate); + je->Set(compatibility_new<v8::String>(isolate, "code"), + compatibility_new<v8::String>(isolate, "std::bad_cast")); + return compatibility_throw(isolate, je); + } catch(const ::efl::eina::system_error &e) { + v8::Local<v8::Object> je = compatibility_new<v8::Object>(isolate); + je->Set(compatibility_new<v8::String>(isolate, "code"), + compatibility_new<v8::String>(isolate, "std::error_code")); + je->Set(compatibility_new<v8::String>(isolate, "category"), + compatibility_new<v8::String>(isolate, e.code().category().name())); + je->Set(compatibility_new<v8::String>(isolate, "value"), + compatibility_new<v8::Integer>(isolate, e.code().value())); + return compatibility_throw(isolate, je); + } + return compatibility_return(); +} + +compatibility_return_type eina_value_get(compatibility_callback_info_type args) +{ + void *ptr = compatibility_get_pointer_internal_field(args.Holder(), 0); + auto &value = *static_cast<eina::value*>(ptr); + return compatibility_return + (value_cast<v8::Local<v8::Value>>(value, args.GetIsolate()), args); +} + +compatibility_return_type eina_value_constructor(compatibility_callback_info_type args) +{ + if (args.Length() != 1) + return compatibility_return(); + + v8::Isolate* isolate = args.GetIsolate(); + + try { + std::unique_ptr<value> + ptr(new value(value_cast<value>(args[0]))); + compatibility_set_pointer_internal_field(args.This(), 0, ptr.get()); + ptr.release(); + } catch(const std::bad_cast &e) { + v8::Local<v8::Object> je = compatibility_new<v8::Object>(isolate); + je->Set(compatibility_new<v8::String>(isolate, "code"), + compatibility_new<v8::String>(isolate, "std::bad_cast")); + return compatibility_throw(isolate,je); + } catch(const ::efl::eina::system_error &e) { + v8::Local<v8::Object> je = compatibility_new<v8::Object>(isolate); + je->Set(compatibility_new<v8::String>(isolate, "code"), + compatibility_new<v8::String>(isolate, "std::error_code")); + je->Set(compatibility_new<v8::String>(isolate, "category"), + compatibility_new<v8::String>(isolate, e.code().category().name())); + je->Set(compatibility_new<v8::String>(isolate, "value"), + compatibility_new<v8::Integer>(isolate, e.code().value())); + return compatibility_throw(isolate, je); + } + // makeweak + // { + // typedef global_ref<v8::Object> persistent_t; + // typedef v8::WeakCallbackData<v8::Object, persistent_t> cb_type; + + // auto on_gc = [](const cb_type &data) { + // typedef ::efl::eina::value value_type; + // typedef value_type *ptr_type; + + // auto o = data.GetValue(); + // delete static_cast<ptr_type> + // (compatibility_get_pointer_internal_field(o, 0)); + // compatibility_set_pointer_internal_field<void*>(o, 0, nullptr); + + // delete data.GetParameter(); + // }; + + // auto persistent = new persistent_t(isolate, args.This()); + // persistent->SetWeak<v8::Object>(persistent, on_gc); + // } +} + +} + +EAPI +void register_value(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Isolate; + using v8::Local; + using v8::Value; + using v8::Integer; + using v8::String; + using v8::Object; + using v8::FunctionTemplate; + using v8::FunctionCallbackInfo; + + v8::Local<v8::FunctionTemplate> constructor = compatibility_new<v8::FunctionTemplate>(isolate, &eina_value_constructor); + + v8::Local<v8::ObjectTemplate> instance = constructor->InstanceTemplate(); + instance->SetInternalFieldCount(1); + + auto prototype = constructor->PrototypeTemplate(); + + prototype->Set(compatibility_new<v8::String>(isolate, "set") + , compatibility_new<FunctionTemplate>(isolate, &eina_value_set)); + prototype->Set(compatibility_new<v8::String>(isolate, "get") + , compatibility_new<FunctionTemplate>(isolate, &eina_value_get)); + + global->Set(name, constructor->GetFunction()); +} + +} } } // namespace efl { namespace js { + +EAPI +void eina_value_register(v8::Handle<v8::Object> global, v8::Isolate* isolate) +{ + efl::eina::js::register_value(isolate, global + , efl::eina::js::compatibility_new<v8::String>(isolate, "value")); +} diff --git a/src/bindings/js/eina_js/eina_js_value.hh b/src/bindings/js/eina_js/eina_js_value.hh new file mode 100644 index 0000000000..e6ebd30ca7 --- /dev/null +++ b/src/bindings/js/eina_js/eina_js_value.hh @@ -0,0 +1,142 @@ +#ifndef EINA_JS_VALUE_HH +#define EINA_JS_VALUE_HH + +#include <type_traits> + +#include <eina_js_compatibility.hh> + +namespace efl { namespace eina { namespace js { + +namespace detail { + +template<class T, class = void> +struct is_representable_as_v8_integer: std::false_type {}; + +template<class T> +struct is_representable_as_v8_integer +<T, + typename std::enable_if<std::is_integral<T>::value + /* v8::Integer only stores 32-bit signed and unsigned + numbers. */ + && (sizeof(T) <= sizeof(int32_t))>::type> +: std::true_type {}; + +template<class T> +typename std::enable_if<is_representable_as_v8_integer<T>::value + && std::is_signed<T>::value, + v8::Local<v8::Value>>::type +to_v8_number(const T &v, v8::Isolate *isolate) +{ + return compatibility_new<v8::Integer>(isolate, v); +} + +template<class T> +typename std::enable_if<is_representable_as_v8_integer<T>::value + && std::is_unsigned<T>::value, + v8::Local<v8::Value>>::type +to_v8_number(const T &v, v8::Isolate *isolate) +{ + return compatibility_new<v8::Integer>(isolate, v); +} + +template<class T> +typename std::enable_if<(std::is_integral<T>::value + && !is_representable_as_v8_integer<T>::value) + || std::is_floating_point<T>::value, + v8::Local<v8::Value>>::type +to_v8_number(const T &v, v8::Isolate *isolate) +{ + return compatibility_new<v8::Number>(isolate, v); +} + +template<class T> +typename std::enable_if<std::is_same<T, ::efl::eina::stringshare>::value + || std::is_same<T, std::string>::value, + v8::Local<v8::Value>>::type +to_v8_string(const T &v, v8::Isolate *isolate) +{ + return compatibility_new<v8::String>(isolate, v.c_str()); +} + +} // namespace detail + +template<class T> +typename std::enable_if<std::is_same<T, v8::Local<v8::Value>>::value, T>::type +value_cast(const ::efl::eina::value &v, v8::Isolate *isolate) +{ + using detail::to_v8_number; + using detail::to_v8_string; + using ::efl::eina::get; + + const auto &t = v.type_info(); + if (t == EINA_VALUE_TYPE_UINT64) { + return to_v8_number(get<uint64_t>(v), isolate); + } else if (t == EINA_VALUE_TYPE_UCHAR) { + return to_v8_number(get<unsigned char>(v), isolate); + } else if (t == EINA_VALUE_TYPE_USHORT) { + return to_v8_number(get<unsigned short>(v), isolate); + } else if (t == EINA_VALUE_TYPE_UINT) { + return to_v8_number(get<unsigned int>(v), isolate); + } else if (t == EINA_VALUE_TYPE_ULONG) { + return to_v8_number(get<unsigned long>(v), isolate); + } else if (t == EINA_VALUE_TYPE_CHAR) { + return to_v8_number(get<char>(v), isolate); + } else if (t == EINA_VALUE_TYPE_SHORT) { + return to_v8_number(get<short>(v), isolate); + } else if (t == EINA_VALUE_TYPE_INT) { + return to_v8_number(get<int>(v), isolate); + } else if (t == EINA_VALUE_TYPE_LONG) { + return to_v8_number(get<long>(v), isolate); + } else if (t == EINA_VALUE_TYPE_FLOAT) { + return to_v8_number(get<float>(v), isolate); + } else if (t == EINA_VALUE_TYPE_DOUBLE) { + return to_v8_number(get<double>(v), isolate); + } else if (t == EINA_VALUE_TYPE_STRINGSHARE) { + return to_v8_string(get<::efl::eina::stringshare>(v), isolate); + } else if (t == EINA_VALUE_TYPE_STRING) { + return to_v8_string(get<std::string>(v), isolate); + } + + throw std::bad_cast{}; +} + +template<class T> +typename std::enable_if<std::is_same<T, ::efl::eina::value>::value, T>::type +value_cast(const v8::Handle<v8::Value> &v) +{ + using ::efl::eina::value; + + if (v->IsBoolean()) { + return value(int{v->BooleanValue()}); + } else if (v->IsInt32()) { + return value(v->Int32Value()); + } else if (v->IsUint32()) { + return value(v->Uint32Value()); + } else if (v->IsNumber()) { + return value(v->NumberValue()); + } else if (v->IsString()) { + v8::String::Utf8Value data(v); + return value(std::string(*data, data.length())); + } + + throw std::bad_cast{}; +} + +/* + # JS binding + + - There is the `value()` constructor, which accepts a primitive value as input + argument and might throw. + - The returned object has a `get()` method, which can be used to get the + wrapped value as a JavaScript value. + - The returned object has a `set()` method, which can be used to change the + wrapped value. + */ +void register_value(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name); + +} } } // namespace efl::js + +EAPI void eina_value_register(v8::Handle<v8::Object> global, v8::Isolate* isolate); + +#endif /* EINA_JS_VALUE_HH */ diff --git a/src/bindings/js/eio_js/Eio_Js.hh b/src/bindings/js/eio_js/Eio_Js.hh new file mode 100644 index 0000000000..e379229870 --- /dev/null +++ b/src/bindings/js/eio_js/Eio_Js.hh @@ -0,0 +1,44 @@ +#ifndef EIO_JS_INIT_HH +#define EIO_JS_INIT_HH + +#include <Eio.h> +#include <Ecore.h> + +#include <Eina.hh> + +#include <Eina_Js.hh> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EIO_JS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EIO_JS_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +namespace efl { namespace eio { namespace js { + +EAPI +void register_eio(v8::Isolate* isolate, v8::Handle<v8::Object> exports); + +} } } // namespace efl { namespace eio { namespace js { + +#endif /* EIO_JS_INIT_HH */ diff --git a/src/bindings/js/eio_js/eio_js.cc b/src/bindings/js/eio_js/eio_js.cc new file mode 100644 index 0000000000..8441247e63 --- /dev/null +++ b/src/bindings/js/eio_js/eio_js.cc @@ -0,0 +1,1756 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eio_Js.hh> + +namespace efl { namespace eio { namespace js { + +using ::efl::eina::js::compatibility_new; +using ::efl::eina::js::compatibility_return_type; +using ::efl::eina::js::compatibility_callback_info_type; +using ::efl::eina::js::compatibility_return; +using ::efl::eina::js::compatibility_get_pointer_internal_field; +using ::efl::eina::js::compatibility_set_pointer_internal_field; + +namespace { + +Eio_File* extract_eio_file(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field<Eio_File*>(object, 0); +} + +v8::Local<v8::Object> wrap_eio_file(Eio_File *file, v8::Isolate *isolate) +{ + using v8::String; + using v8::Boolean; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto cancel = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + + auto ret = eio_file_cancel(extract_eio_file(info.This())); + return compatibility_return(compatibility_new<Boolean>(isolate, ret), + info); + }; + + auto check = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + + auto ret = eio_file_check(extract_eio_file(info.This())); + return compatibility_return(compatibility_new<Boolean>(isolate, ret), + info); + }; + + ret->Set(compatibility_new<String>(isolate, "cancel"), + compatibility_new<FunctionTemplate>(isolate, cancel) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "check"), + compatibility_new<FunctionTemplate>(isolate, check) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, file); + + return ret; +} + +static Eina_File* extract_eina_file(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field<Eina_File*>(object, 0); +} + +static v8::Local<v8::Object> wrap_eina_file(Eina_File *file, + v8::Isolate *isolate) +{ + using v8::String; + using v8::ObjectTemplate; + using v8::Object; + using v8::FunctionTemplate; + using v8::WeakCallbackData; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + /* TODO: + + Eina_File only handle files open in read-only mode. Althought there + aren't many useful functions exposed to a JavaScript binding, the exposed + `file->fd` can be used to expose a few read operations found in + `<cstdio>`. + */ + + auto close = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto o = info.This(); + + auto file = extract_eina_file(o); + if (!file) + return compatibility_return(); + + eina_file_close(file); + compatibility_set_pointer_internal_field<void*>(o, 0, nullptr); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "close"), + compatibility_new<FunctionTemplate>(isolate, close) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, file); + + auto on_gc = [ret]() { + auto file = extract_eina_file(ret); + + if (file) { + eina_file_close(file); + compatibility_set_pointer_internal_field<void*>(ret, 0, nullptr); + } + }; + + efl::eina::js::make_weak(isolate, ret, on_gc); + + return ret; +} + +static Eio_Monitor* extract_monitor(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field<Eio_Monitor*>(object, 0); +} + +static v8::Local<v8::Object> wrap_monitor(Eio_Monitor *monitor, + v8::Isolate *isolate) +{ + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + eio_monitor_del(extract_monitor(info.This())); + return compatibility_return(); + }; + + auto path_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto ret = eio_monitor_path_get(extract_monitor(info.This())); + return compatibility_return(compatibility_new<String>(info.GetIsolate(), + ret), + info); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "path_get"), + compatibility_new<FunctionTemplate>(isolate, path_get) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, monitor); + + return ret; +} + +static Ecore_Event_Handler *extract_event_handler(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field<Ecore_Event_Handler*> + (object, 0); +} + +static v8::Local<v8::Object> wrap_event_handler(Ecore_Event_Handler *handler, + v8::Isolate *isolate) +{ + using v8::String; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + using v8::Value; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto p = ecore_event_handler_del(extract_event_handler(info.This())); + + auto per = static_cast<efl::eina::js::global_ref<Value>*>(p); + per->dispose(); + delete per; + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, handler); + + return ret; +} + +static +v8::Local<v8::Object> wrap_eina_file_direct_info(const Eina_File_Direct_Info* + info, + v8::Isolate *isolate) +{ + using v8::Object; + using v8::String; + using v8::Integer; + + auto wrapped_info = compatibility_new<Object>(isolate); + + wrapped_info->Set(compatibility_new<String>(isolate, "path_length"), + compatibility_new<Integer>(isolate, info->path_length)); + wrapped_info->Set(compatibility_new<String>(isolate, "mame_length"), + compatibility_new<Integer>(isolate, info->name_length)); + wrapped_info->Set(compatibility_new<String>(isolate, "name_start"), + compatibility_new<Integer>(isolate, info->name_start)); + wrapped_info->Set(compatibility_new<String>(isolate, "type"), + compatibility_new<Integer>(isolate, info->type)); + wrapped_info->Set(compatibility_new<String>(isolate, "path"), + compatibility_new<String>(isolate, info->path)); + + return wrapped_info; +} + +EAPI +void register_init(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto init = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = eio_init(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, init) + ->GetFunction()); +} + +EAPI +void register_shutdown(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto shutdown = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = eio_shutdown(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, shutdown) + ->GetFunction()); +} + +EAPI +void register_op_file_copy(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, EIO_FILE_COPY)); +} + +EAPI +void register_op_file_move(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, EIO_FILE_MOVE)); +} + +EAPI +void register_op_dir_copy(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, EIO_DIR_COPY)); +} + +EAPI +void register_op_dir_move(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, EIO_DIR_MOVE)); +} + +EAPI +void register_op_unlink(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, EIO_UNLINK)); +} + +EAPI +void register_op_file_getpwnam(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, EIO_FILE_GETPWNAM)); +} + +EAPI +void register_op_file_getgrnam(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, EIO_FILE_GETGRNAM)); +} + +EAPI +void register_file_open(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::Value; + using v8::String; + using v8::FunctionTemplate; + using v8::Function; + using v8::Handle; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 4 || !args[0]->IsString() || !args[1]->IsBoolean() + || !args[2]->IsFunction() || !args[3]->IsFunction()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[2]); + cb_data[0] = persistent_t(isolate, args[2]); + cb_data[1] = persistent_t(isolate, args[3]); + + auto open_cb = [](void *data, Eio_File *handler, Eina_File *file) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + wrap_eina_file(file, isolate) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] persistent; + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 1); + }; + + auto ret = eio_file_open(*String::Utf8Value(args[0]), + args[1]->BooleanValue(), open_cb, error_cb, + cb_data.release()); + + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_monitor_file_created(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, EIO_MONITOR_FILE_CREATED)); +} + +EAPI +void register_monitor_file_deleted(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, EIO_MONITOR_FILE_DELETED)); +} + +EAPI +void register_monitor_file_modified(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, EIO_MONITOR_FILE_MODIFIED)); +} + +EAPI +void register_monitor_file_closed(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, EIO_MONITOR_FILE_CLOSED)); +} + +EAPI +void register_monitor_directory_created(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + EIO_MONITOR_DIRECTORY_CREATED)); +} + +EAPI +void register_monitor_directory_deleted(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + EIO_MONITOR_DIRECTORY_DELETED)); +} + +EAPI +void register_monitor_directory_modified(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + EIO_MONITOR_DIRECTORY_MODIFIED)); +} + +EAPI +void register_monitor_directory_closed(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + EIO_MONITOR_DIRECTORY_CLOSED)); +} + +EAPI +void register_monitor_self_rename(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, EIO_MONITOR_SELF_RENAME)); +} + +EAPI +void register_monitor_self_deleted(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, EIO_MONITOR_SELF_DELETED)); +} + +EAPI +void register_monitor_error(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, EIO_MONITOR_ERROR)); +} + +EAPI +void register_monitor_add(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsString()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = eio_monitor_add(*String::Utf8Value(args[0])); + return compatibility_return(wrap_monitor(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +template<int &wanted_event> +static +void register_monitor_event_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::String; + using v8::Value; + using v8::Object; + using v8::Function; + using v8::Handle; + using v8::Local; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + + auto p = new efl::eina::js::global_ref<Value>(isolate, args[0]); + + auto cb = [](void *d, int type, void *event) -> Eina_Bool { + auto p = reinterpret_cast<efl::eina::js::global_ref<Value>*>(d); + auto e = reinterpret_cast<Eio_Monitor_Event*>(event); + + auto isolate = v8::Isolate::GetCurrent(); + + auto o = p->handle(); + auto wrapped_event = compatibility_new<Object>(isolate); + + wrapped_event->Set(compatibility_new<String>(isolate, "monitor"), + wrap_monitor(e->monitor, isolate)); + wrapped_event->Set(compatibility_new<String>(isolate, "filename"), + compatibility_new<String>(isolate, e->filename)); + + Handle<Value> args[2]{ + compatibility_new<Integer>(isolate, type), + wrapped_event + }; + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 2, args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + + return bret ? EINA_TRUE : EINA_FALSE; + }; + + auto ret = ecore_event_handler_add(wanted_event, cb, p); + return compatibility_return(wrap_event_handler(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void +register_event_monitor_file_created_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_FILE_CREATED> + (isolate, global, name); +} + +EAPI +void +register_event_monitor_file_deleted_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_FILE_DELETED> + (isolate, global, name); +} + +EAPI +void +register_event_monitor_file_modified_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_FILE_MODIFIED> + (isolate, global, name); +} + +EAPI +void +register_event_monitor_file_closed_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_FILE_CLOSED> + (isolate, global, name); +} + +EAPI +void register_event_monitor_directory_created_handler_add +(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_DIRECTORY_CREATED> + (isolate, global, name); +} + +EAPI +void register_event_monitor_directory_deleted_handler_add +(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_DIRECTORY_DELETED> + (isolate, global, name); +} + +EAPI +void register_event_monitor_directory_modified_handler_add +(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_DIRECTORY_MODIFIED> + (isolate, global, name); +} + +EAPI +void register_event_monitor_directory_closed_handler_add +(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_DIRECTORY_CLOSED> + (isolate, global, name); +} + +EAPI +void +register_event_monitor_self_rename_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_SELF_RENAME> + (isolate, global, name); +} + +EAPI +void +register_event_monitor_self_deleted_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_SELF_DELETED> + (isolate, global, name); +} + +EAPI +void +register_event_monitor_error_handler_add(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + return register_monitor_event_handler_add<EIO_MONITOR_ERROR> + (isolate, global, name); +} + +EAPI +void register_file_ls(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 5 || !args[0]->IsString() || !args[1]->IsFunction() + || !args[2]->IsFunction() || !args[3]->IsFunction() + || !args[4]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[4]); + cb_data[0] = persistent_t(isolate, args[1]); + cb_data[1] = persistent_t(isolate, args[2]); + cb_data[2] = persistent_t(isolate, args[3]); + cb_data[3] = persistent_t(isolate, args[4]); + + auto filter_cb = [](void *data, Eio_File *handler, const char *file) + -> Eina_Bool { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<String>(isolate, file) + }; + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 2, args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + return bret ? EINA_TRUE : EINA_FALSE; + }; + auto main_cb = [](void *data, Eio_File *handler, const char *file) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<String>(isolate, file) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + }; + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 2; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] (persistent - 2); + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 3; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 3); + }; + + auto ret = eio_file_ls(*String::Utf8Value(args[0]), filter_cb, main_cb, + done_cb, error_cb, cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_file_chmod(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 4 || !args[0]->IsString() || !args[1]->IsNumber() + || !args[2]->IsFunction() || !args[3]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[2]); + cb_data[0] = persistent_t(isolate, args[2]); + cb_data[1] = persistent_t(isolate, args[3]); + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] persistent; + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 1); + }; + + auto ret = eio_file_chmod(*String::Utf8Value(args[0]), + args[1]->IntegerValue(), done_cb, error_cb, + cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_file_chown(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 5 || !args[0]->IsString() || !args[1]->IsString() + || !args[2]->IsString() || !args[3]->IsFunction() + || !args[4]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[2]); + cb_data[0] = persistent_t(isolate, args[3]); + cb_data[1] = persistent_t(isolate, args[4]); + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] persistent; + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 1); + }; + + auto ret = eio_file_chown(*String::Utf8Value(args[0]), + *String::Utf8Value(args[1]), + *String::Utf8Value(args[2]), done_cb, + error_cb, + cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_file_unlink(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 3 || !args[0]->IsString() || !args[1]->IsFunction() + || !args[2]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[2]); + cb_data[0] = persistent_t(isolate, args[1]); + cb_data[1] = persistent_t(isolate, args[2]); + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] persistent; + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 1); + }; + + auto ret = eio_file_unlink(*String::Utf8Value(args[0]), done_cb, + error_cb, cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_file_mkdir(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 4 || !args[0]->IsString() || !args[1]->IsNumber() + || !args[2]->IsString() || !args[3]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[2]); + cb_data[0] = persistent_t(isolate, args[2]); + cb_data[1] = persistent_t(isolate, args[3]); + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] persistent; + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 1); + }; + + auto ret = eio_file_mkdir(*String::Utf8Value(args[0]), + args[1]->IntegerValue(), done_cb, error_cb, + cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_file_move(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::Number; + using v8::Object; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 5 || !args[0]->IsString() || !args[1]->IsString() + || !args[2]->IsFunction() || !args[3]->IsFunction() + || !args[4]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[3]); + cb_data[0] = persistent_t(isolate, args[2]); + cb_data[1] = persistent_t(isolate, args[3]); + cb_data[2] = persistent_t(isolate, args[4]); + auto progress_cb = [](void *data, Eio_File *handler, + const Eio_Progress *info) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + auto wrapped_info = compatibility_new<Object>(isolate); + + wrapped_info->Set(compatibility_new<String>(isolate, "op"), + compatibility_new<Integer>(isolate, info->op)); + wrapped_info->Set(compatibility_new<String>(isolate, "current"), + compatibility_new<Integer>(isolate, + info->current)); + wrapped_info->Set(compatibility_new<String>(isolate, "max"), + compatibility_new<Integer>(isolate, info->max)); + wrapped_info->Set(compatibility_new<String>(isolate, "percent"), + compatibility_new<Number>(isolate, + info->percent)); + wrapped_info->Set(compatibility_new<String>(isolate, "source"), + compatibility_new<String>(isolate, info->source)); + wrapped_info->Set(compatibility_new<String>(isolate, "dest"), + compatibility_new<String>(isolate, info->dest)); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + wrapped_info + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + }; + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] (persistent - 1); + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 2; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 2); + }; + + auto ret = eio_file_move(*String::Utf8Value(args[0]), + *String::Utf8Value(args[1]), + progress_cb, done_cb, error_cb, + cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_file_copy(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::Number; + using v8::Object; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 5 || !args[0]->IsString() || !args[1]->IsString() + || !args[2]->IsFunction() || !args[3]->IsFunction() + || !args[4]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[3]); + cb_data[0] = persistent_t(isolate, args[2]); + cb_data[1] = persistent_t(isolate, args[3]); + cb_data[2] = persistent_t(isolate, args[4]); + auto progress_cb = [](void *data, Eio_File *handler, + const Eio_Progress *info) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + auto wrapped_info = compatibility_new<Object>(isolate); + + wrapped_info->Set(compatibility_new<String>(isolate, "op"), + compatibility_new<Integer>(isolate, info->op)); + wrapped_info->Set(compatibility_new<String>(isolate, "current"), + compatibility_new<Integer>(isolate, + info->current)); + wrapped_info->Set(compatibility_new<String>(isolate, "max"), + compatibility_new<Integer>(isolate, info->max)); + wrapped_info->Set(compatibility_new<String>(isolate, "percent"), + compatibility_new<Number>(isolate, + info->percent)); + wrapped_info->Set(compatibility_new<String>(isolate, "source"), + compatibility_new<String>(isolate, info->source)); + wrapped_info->Set(compatibility_new<String>(isolate, "dest"), + compatibility_new<String>(isolate, info->dest)); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + wrapped_info + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + }; + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] (persistent - 1); + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 2; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 2); + }; + + auto ret = eio_file_copy(*String::Utf8Value(args[0]), + *String::Utf8Value(args[1]), + progress_cb, done_cb, error_cb, + cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_dir_move(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::Number; + using v8::Object; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 6 || !args[0]->IsString() || !args[1]->IsString() + || !args[2]->IsFunction() || !args[3]->IsFunction() + || !args[4]->IsFunction() || !args[5]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[4]); + cb_data[0] = persistent_t(isolate, args[2]); + cb_data[1] = persistent_t(isolate, args[3]); + cb_data[2] = persistent_t(isolate, args[4]); + cb_data[3] = persistent_t(isolate, args[5]); + auto filter_cb = [](void *data, Eio_File *handler, + const Eina_File_Direct_Info *info) -> Eina_Bool { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + wrap_eina_file_direct_info(info, isolate) + }; + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 2, args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + return bret ? EINA_TRUE : EINA_FALSE; + }; + auto progress_cb = [](void *data, Eio_File *handler, + const Eio_Progress *info) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + auto wrapped_info = compatibility_new<Object>(isolate); + + wrapped_info->Set(compatibility_new<String>(isolate, "op"), + compatibility_new<Integer>(isolate, info->op)); + wrapped_info->Set(compatibility_new<String>(isolate, "current"), + compatibility_new<Integer>(isolate, + info->current)); + wrapped_info->Set(compatibility_new<String>(isolate, "max"), + compatibility_new<Integer>(isolate, info->max)); + wrapped_info->Set(compatibility_new<String>(isolate, "percent"), + compatibility_new<Number>(isolate, + info->percent)); + wrapped_info->Set(compatibility_new<String>(isolate, "source"), + compatibility_new<String>(isolate, info->source)); + wrapped_info->Set(compatibility_new<String>(isolate, "dest"), + compatibility_new<String>(isolate, info->dest)); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + wrapped_info + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + }; + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 2; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] (persistent - 2); + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 3; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 3); + }; + + auto ret = eio_dir_move(*String::Utf8Value(args[0]), + *String::Utf8Value(args[1]), filter_cb, + progress_cb, done_cb, error_cb, + cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_dir_copy(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::Number; + using v8::Object; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 6 || !args[0]->IsString() || !args[1]->IsString() + || !args[2]->IsFunction() || !args[3]->IsFunction() + || !args[4]->IsFunction() || !args[5]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[4]); + cb_data[0] = persistent_t(isolate, args[2]); + cb_data[1] = persistent_t(isolate, args[3]); + cb_data[2] = persistent_t(isolate, args[4]); + cb_data[3] = persistent_t(isolate, args[5]); + auto filter_cb = [](void *data, Eio_File *handler, + const Eina_File_Direct_Info *info) -> Eina_Bool { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + wrap_eina_file_direct_info(info, isolate) + }; + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 2, args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + return bret ? EINA_TRUE : EINA_FALSE; + }; + auto progress_cb = [](void *data, Eio_File *handler, + const Eio_Progress *info) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + auto wrapped_info = compatibility_new<Object>(isolate); + + wrapped_info->Set(compatibility_new<String>(isolate, "op"), + compatibility_new<Integer>(isolate, info->op)); + wrapped_info->Set(compatibility_new<String>(isolate, "current"), + compatibility_new<Integer>(isolate, + info->current)); + wrapped_info->Set(compatibility_new<String>(isolate, "max"), + compatibility_new<Integer>(isolate, info->max)); + wrapped_info->Set(compatibility_new<String>(isolate, "percent"), + compatibility_new<Number>(isolate, + info->percent)); + wrapped_info->Set(compatibility_new<String>(isolate, "source"), + compatibility_new<String>(isolate, info->source)); + wrapped_info->Set(compatibility_new<String>(isolate, "dest"), + compatibility_new<String>(isolate, info->dest)); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + wrapped_info + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + }; + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 2; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] (persistent - 2); + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 3; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 3); + }; + + auto ret = eio_dir_copy(*String::Utf8Value(args[0]), + *String::Utf8Value(args[1]), filter_cb, + progress_cb, done_cb, error_cb, + cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +EAPI +void register_dir_unlink(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::Integer; + using v8::Number; + using v8::Object; + using v8::FunctionTemplate; + using v8::Handle; + using v8::Value; + using v8::Function; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 5 || !args[0]->IsString() || !args[1]->IsFunction() + || !args[2]->IsFunction() || !args[3]->IsFunction() + || !args[4]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + + auto cb_data = unique_ptr<persistent_t[]>(new persistent_t[4]); + cb_data[0] = persistent_t(isolate, args[1]); + cb_data[1] = persistent_t(isolate, args[2]); + cb_data[2] = persistent_t(isolate, args[3]); + cb_data[3] = persistent_t(isolate, args[4]); + auto filter_cb = [](void *data, Eio_File *handler, + const Eina_File_Direct_Info *info) -> Eina_Bool { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + wrap_eina_file_direct_info(info, isolate) + }; + + auto ret = Function::Cast(*o)->Call(o->ToObject(), 2, args); + auto bret = ret->IsBoolean() && ret->BooleanValue(); + return bret ? EINA_TRUE : EINA_FALSE; + }; + auto progress_cb = [](void *data, Eio_File *handler, + const Eio_Progress *info) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 1; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + auto wrapped_info = compatibility_new<Object>(isolate); + + wrapped_info->Set(compatibility_new<String>(isolate, "op"), + compatibility_new<Integer>(isolate, info->op)); + wrapped_info->Set(compatibility_new<String>(isolate, "current"), + compatibility_new<Integer>(isolate, + info->current)); + wrapped_info->Set(compatibility_new<String>(isolate, "max"), + compatibility_new<Integer>(isolate, info->max)); + wrapped_info->Set(compatibility_new<String>(isolate, "percent"), + compatibility_new<Number>(isolate, + info->percent)); + wrapped_info->Set(compatibility_new<String>(isolate, "source"), + compatibility_new<String>(isolate, info->source)); + wrapped_info->Set(compatibility_new<String>(isolate, "dest"), + compatibility_new<String>(isolate, info->dest)); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + wrapped_info + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + }; + auto done_cb = [](void *data, Eio_File *handler) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 2; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args = wrap_eio_file(handler, isolate); + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete[] (persistent - 2); + }; + auto error_cb = [](void *data, Eio_File *handler, int error) { + auto persistent = reinterpret_cast<persistent_t*>(data) + 3; + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_eio_file(handler, isolate), + compatibility_new<Integer>(isolate, error) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete[] (persistent - 3); + }; + + auto ret = eio_dir_unlink(*String::Utf8Value(args[0]), filter_cb, + progress_cb, done_cb, error_cb, + cb_data.release()); + return compatibility_return(wrap_eio_file(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +} + +EAPI +void register_eio(v8::Isolate* isolate, v8::Handle<v8::Object> exports) +{ + using v8::String; + register_init(isolate, exports, + compatibility_new<String>(isolate, "eio_init")); + register_shutdown(isolate, exports, + compatibility_new<String>(isolate, "eio_shutdown")); + register_op_file_copy(isolate, exports, + compatibility_new<String>(isolate, "EIO_FILE_COPY")); + register_op_file_move(isolate, exports, + compatibility_new<String>(isolate, "EIO_FILE_MOVE")); + register_op_dir_copy(isolate, exports, + compatibility_new<String>(isolate, "EIO_DIR_COPY")); + register_op_dir_move(isolate, exports, + compatibility_new<String>(isolate, "EIO_DIR_MOVE")); + register_op_unlink(isolate, exports, + compatibility_new<String>(isolate, "EIO_LINK")); + register_op_file_getpwnam(isolate, exports, + compatibility_new<String>(isolate, + "EIO_FILE_GETPWNAM")); + register_op_file_getgrnam(isolate, exports, + compatibility_new<String>(isolate, + "EIO_FILE_GETGRNAM")); + register_file_open(isolate, exports, + compatibility_new<String>(isolate, "eio_file_open")); + register_monitor_file_created(isolate, exports, + compatibility_new<String>(isolate, + "EIO_MONITOR_FILE" + "_CREATED")); + register_monitor_file_deleted(isolate, exports, + compatibility_new<String>(isolate, + "EIO_MONITOR_FILE" + "_DELETED")); + register_monitor_file_modified(isolate, exports, + compatibility_new<String>(isolate, + "EIO_MONITOR_FILE" + "_MODIFIED")); + register_monitor_file_closed(isolate, exports, + compatibility_new<String>(isolate, + "EIO_MONITOR_FILE" + "_CLOSED")); + register_monitor_directory_created(isolate, exports, + compatibility_new<String> + (isolate, + "EIO_MONITOR_DIRECTORY_CREATED")); + register_monitor_directory_deleted(isolate, exports, + compatibility_new<String> + (isolate, + "EIO_MONITOR_DIRECTORY_DELETED")); + register_monitor_directory_modified(isolate, exports, + compatibility_new<String> + (isolate, + "EIO_MONITOR_DIRECTORY_MODIFIED")); + register_monitor_directory_closed(isolate, exports, + compatibility_new<String> + (isolate, "EIO_MONITOR_DIRECTORY_CLOSED")); + register_monitor_self_rename(isolate, exports, + compatibility_new<String> + (isolate, "EIO_MONITOR_SELF_RENAME")); + register_monitor_self_deleted(isolate, exports, + compatibility_new<String> + (isolate, "EIO_MONITOR_SELF_DELETED")); + register_monitor_error(isolate, exports, + compatibility_new<String>(isolate, + "EIO_MONITOR_ERROR")); + register_monitor_add(isolate, exports, + compatibility_new<String>(isolate, "eio_monitor_add")); + register_event_monitor_file_created_handler_add + (isolate, exports, + compatibility_new<String>(isolate, + "eio_event_monitor_file_created_handler_add")); + register_event_monitor_file_deleted_handler_add + (isolate, exports, + compatibility_new<String>(isolate, + "eio_event_monitor_file_deleted_handler_add")); + register_event_monitor_file_modified_handler_add + (isolate, exports, + compatibility_new<String> + (isolate, "eio_event_monitor_file_modified_handler_add")); + register_event_monitor_file_closed_handler_add + (isolate, exports, + compatibility_new<String>(isolate, + "eio_event_monitor_file_closed_handler_add")); + register_event_monitor_directory_created_handler_add + (isolate, exports, + compatibility_new<String> + (isolate, "eio_event_monitor_directory_created_handler_add")); + register_event_monitor_directory_deleted_handler_add + (isolate, exports, + compatibility_new<String> + (isolate, "eio_event_monitor_directory_deleted_handler_add")); + register_event_monitor_directory_modified_handler_add + (isolate, exports, + compatibility_new<String> + (isolate, "eio_event_monitor_directory_modified_handler_add")); + register_event_monitor_directory_closed_handler_add + (isolate, exports, + compatibility_new<String> + (isolate, "eio_event_monitor_directory_closed_handler_add")); + register_event_monitor_self_rename_handler_add + (isolate, exports, + compatibility_new<String>(isolate, + "eio_event_monitor_self_rename_handler_add")); + register_event_monitor_self_deleted_handler_add + (isolate, exports, + compatibility_new<String>(isolate, + "eio_event_monitor_self_deleted_handler_add")); + register_event_monitor_error_handler_add + (isolate, exports, + compatibility_new<String>(isolate, + "eio_event_monitor_error_handler_add")); + register_file_ls(isolate, exports, + compatibility_new<String>(isolate, "eio_file_ls")); + register_file_chmod(isolate, exports, + compatibility_new<String>(isolate, "eio_file_chmod")); + register_file_chown(isolate, exports, + compatibility_new<String>(isolate, "eio_file_chown")); + register_file_unlink(isolate, exports, + compatibility_new<String>(isolate, "eio_file_unlink")); + register_file_mkdir(isolate, exports, + compatibility_new<String>(isolate, "eio_file_mkdir")); + register_file_move(isolate, exports, + compatibility_new<String>(isolate, "eio_file_move")); + register_file_copy(isolate, exports, + compatibility_new<String>(isolate, "eio_file_copy")); + register_dir_move(isolate, exports, + compatibility_new<String>(isolate, "eio_dir_move")); + register_dir_copy(isolate, exports, + compatibility_new<String>(isolate, "eio_dir_copy")); + register_dir_unlink(isolate, exports, + compatibility_new<String>(isolate, "eio_dir_unlink")); +} + +} } } // namespace efl { namespace eio { namespace js { diff --git a/src/bindings/js/eldbus_js/Eldbus_Js.hh b/src/bindings/js/eldbus_js/Eldbus_Js.hh new file mode 100644 index 0000000000..00da9ca924 --- /dev/null +++ b/src/bindings/js/eldbus_js/Eldbus_Js.hh @@ -0,0 +1,48 @@ + +#ifndef EFL_ELDBUS_JS_HH +#define EFL_ELDBUS_JS_HH + +#include <Eina.hh> +#include <Eina_Js.hh> + +#include <Eldbus.h> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EINA_JS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +namespace efl { namespace eldbus { namespace js { + +EAPI void register_eldbus_connection(v8::Isolate* isolate, v8::Handle<v8::Object> exports); +EAPI void register_eldbus_core(v8::Isolate* isolate, v8::Handle<v8::Object> exports); +EAPI void register_eldbus_message(v8::Isolate* isolate, v8::Handle<v8::Object> exports); +EAPI void register_eldbus_object_mapper(v8::Isolate* isolate, v8::Handle<v8::Object> exports); +EAPI void register_eldbus(v8::Isolate* isolate, v8::Handle<v8::Object> exports); + +} } } + +#include <eldbus_js_util.hh> + +#endif diff --git a/src/bindings/js/eldbus_js/eldbus_js_connection.cc b/src/bindings/js/eldbus_js/eldbus_js_connection.cc new file mode 100644 index 0000000000..c02dc8c600 --- /dev/null +++ b/src/bindings/js/eldbus_js/eldbus_js_connection.cc @@ -0,0 +1,543 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eldbus_Js.hh> + +namespace efl { namespace eldbus { namespace js { + +namespace { + +v8::Local<v8::Object> wrap_event_callback(Eldbus_Connection *conn, + Eldbus_Connection_Event_Type type, + Eldbus_Connection_Event_Cb cb, + void *cb_data, v8::Isolate *isolate) +{ + using v8::String; + using v8::Integer; + using v8::Value; + using v8::Object; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(3); + auto ret = obj_tpl->NewInstance(); + + ret->Set(compatibility_new<String>(isolate, "_type"), + compatibility_new<Integer>(isolate, type)); + + compatibility_set_pointer_internal_field(ret, 0, conn); + compatibility_set_pointer_internal_field(ret, 1, (void*)(cb)); + compatibility_set_pointer_internal_field(ret, 2, cb_data); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + auto o = info.This(); + auto isolate = info.GetIsolate(); + + auto conn + = (compatibility_get_pointer_internal_field<Eldbus_Connection*> + (o, 0)); + auto cb + = (compatibility_get_pointer_internal_field + <Eldbus_Connection_Event_Cb>(o, 1)); + auto cb_data + = (compatibility_get_pointer_internal_field + <efl::eina::js::global_ref<Value>*>(o, 2)); + auto type + = (static_cast<Eldbus_Connection_Event_Type> + (o->Get(compatibility_new<String>(isolate, "_type")) + ->IntegerValue())); + + eldbus_connection_event_callback_del(conn, type, cb, cb_data); + + delete cb_data; + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + return ret; +} + +Eldbus_Connection* extract_eldbus_connection(v8::Local<v8::Object> o) +{ + return compatibility_get_pointer_internal_field<Eldbus_Connection*>(o, 0); +} + +void register_timeout_infinite(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, + ELDBUS_TIMEOUT_INFINITE)); +} + +void register_connection_type_unknown(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ELDBUS_CONNECTION_TYPE_UNKNOWN)); +} + +void register_connection_type_session(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ELDBUS_CONNECTION_TYPE_SESSION)); +} + +void register_connection_type_system(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ELDBUS_CONNECTION_TYPE_SYSTEM)); +} + +void register_connection_type_starter(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ELDBUS_CONNECTION_TYPE_STARTER)); +} + +void register_connection_type_address(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ELDBUS_CONNECTION_TYPE_ADDRESS)); +} + +void register_connection_type_last(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ELDBUS_CONNECTION_TYPE_LAST)); +} + +void register_connection_event_del(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, + ELDBUS_CONNECTION_EVENT_DEL)); +} + +void register_connection_event_disconnected(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer> + (isolate, ELDBUS_CONNECTION_EVENT_DISCONNECTED)); +} + +void register_connection_event_last(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, compatibility_new<Integer>(isolate, + ELDBUS_CONNECTION_EVENT_LAST)); +} + +void register_connection_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + Eldbus_Connection_Type type; + + switch (args[0]->IntegerValue()) { + case ELDBUS_CONNECTION_TYPE_UNKNOWN: + type = ELDBUS_CONNECTION_TYPE_UNKNOWN; + break; + case ELDBUS_CONNECTION_TYPE_SESSION: + type = ELDBUS_CONNECTION_TYPE_SESSION; + break; + case ELDBUS_CONNECTION_TYPE_SYSTEM: + type = ELDBUS_CONNECTION_TYPE_SYSTEM; + break; + case ELDBUS_CONNECTION_TYPE_STARTER: + type = ELDBUS_CONNECTION_TYPE_STARTER; + break; + case ELDBUS_CONNECTION_TYPE_ADDRESS: + type = ELDBUS_CONNECTION_TYPE_ADDRESS; + break; + case ELDBUS_CONNECTION_TYPE_LAST: + type = ELDBUS_CONNECTION_TYPE_LAST; + break; + default: + return compatibility_return(); + } + auto ret = eldbus_connection_get(type); + return compatibility_return(wrap_eldbus_connection(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_private_connection_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsNumber()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + Eldbus_Connection_Type type; + + switch (args[0]->IntegerValue()) { + case ELDBUS_CONNECTION_TYPE_UNKNOWN: + type = ELDBUS_CONNECTION_TYPE_UNKNOWN; + break; + case ELDBUS_CONNECTION_TYPE_SESSION: + type = ELDBUS_CONNECTION_TYPE_SESSION; + break; + case ELDBUS_CONNECTION_TYPE_SYSTEM: + type = ELDBUS_CONNECTION_TYPE_SYSTEM; + break; + case ELDBUS_CONNECTION_TYPE_STARTER: + type = ELDBUS_CONNECTION_TYPE_STARTER; + break; + case ELDBUS_CONNECTION_TYPE_ADDRESS: + type = ELDBUS_CONNECTION_TYPE_ADDRESS; + break; + case ELDBUS_CONNECTION_TYPE_LAST: + type = ELDBUS_CONNECTION_TYPE_LAST; + break; + default: + return compatibility_return(); + } + auto ret = eldbus_private_connection_get(type); + return compatibility_return(wrap_eldbus_connection(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_address_connection_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) + +{ + using v8::String; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsString()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + + auto ret = eldbus_address_connection_get(*String::Utf8Value(args[0])); + return compatibility_return(wrap_eldbus_connection(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_private_address_connection_get(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) + +{ + using v8::String; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsString()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + + String::Utf8Value address(args[0]); + + auto ret = eldbus_private_address_connection_get(*address); + return compatibility_return(wrap_eldbus_connection(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +} + +v8::Local<v8::Object> wrap_eldbus_connection(Eldbus_Connection *conn, + v8::Isolate *isolate) +{ + using v8::String; + using v8::Boolean; + using v8::Value; + using v8::Handle; + using v8::ObjectTemplate; + using v8::Function; + using v8::FunctionTemplate; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto event_callback_add = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 2 || !info[0]->IsNumber() + || !info[1]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = info.GetIsolate(); + auto conn = extract_eldbus_connection(info.This()); + Eldbus_Connection_Event_Type type; + + switch (info[0]->IntegerValue()) { + case ELDBUS_CONNECTION_EVENT_DEL: + type = ELDBUS_CONNECTION_EVENT_DEL; + break; + case ELDBUS_CONNECTION_EVENT_DISCONNECTED: + type = ELDBUS_CONNECTION_EVENT_DISCONNECTED; + break; + case ELDBUS_CONNECTION_EVENT_LAST: + type = ELDBUS_CONNECTION_EVENT_LAST; + break; + default: + return compatibility_return(); + } + + unique_ptr<persistent_t> cb_data{new persistent_t{isolate, info[1]}}; + + auto cb = [](void *data, Eldbus_Connection *conn, + void */*event_info*/) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args{wrap_eldbus_connection(conn, isolate)}; + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + }; + + eldbus_connection_event_callback_add(conn, type, cb, cb_data.get()); + auto ret = wrap_event_callback(conn, type, cb, cb_data.release(), + isolate); + return compatibility_return(ret, info); + }; + + auto send = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 3 || !info[0]->IsObject() || !info[1]->IsFunction() + || !info[2]->IsNumber()) { + return compatibility_return(); + } + + auto isolate = info.GetIsolate(); + auto conn = extract_eldbus_connection(info.This()); + auto msg + = (compatibility_get_pointer_internal_field<Eldbus_Message*> + (info[0]->ToObject(), 0)); + + unique_ptr<persistent_t> cb_data{new persistent_t{isolate, info[1]}}; + + auto cb = [](void *data, const Eldbus_Message *msg, + Eldbus_Pending *pending) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_const_eldbus_msg(msg, isolate), + wrap_eldbus_pending(pending, persistent, isolate) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete persistent; + }; + + auto ret = eldbus_connection_send(conn, msg, cb, cb_data.get(), + info[2]->NumberValue()); + return compatibility_return(wrap_eldbus_pending(ret, cb_data.release(), + isolate), + info); + }; + + auto unique_name_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto conn = extract_eldbus_connection(info.This()); + + auto ret = eldbus_connection_unique_name_get(conn); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto object_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 2 || !info[0]->IsString() || !info[1]->IsString()) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto conn = extract_eldbus_connection(info.This()); + + auto ret = eldbus_object_get(conn, *String::Utf8Value(info[0]), + *String::Utf8Value(info[1])); + return compatibility_return(wrap_eldbus_object(ret, isolate), info); + }; + + auto signal_handler_add = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 5 || !info[0]->IsString() || !info[1]->IsString() + || !info[2]->IsString() || !info[3]->IsString() + || !info[4]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = info.GetIsolate(); + auto conn = extract_eldbus_connection(info.This()); + + unique_ptr<persistent_t> cb_data{new persistent_t{isolate, info[4]}}; + + auto cb = [](void *data, const Eldbus_Message *msg) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args{wrap_const_eldbus_msg(msg, isolate)}; + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + }; + + auto ret = eldbus_signal_handler_add(conn, *String::Utf8Value(info[0]), + *String::Utf8Value(info[1]), + *String::Utf8Value(info[2]), + *String::Utf8Value(info[3]), + cb, cb_data.get()); + auto wrapped_ret = wrap_eldbus_signal_handler(ret, cb_data.release(), + isolate); + return compatibility_return(wrapped_ret, info); + }; + + ret->Set(compatibility_new<String>(isolate, "event_callback_add"), + compatibility_new<FunctionTemplate>(isolate, event_callback_add) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "send"), + compatibility_new<FunctionTemplate>(isolate, send)->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "unique_name_get"), + compatibility_new<FunctionTemplate>(isolate, unique_name_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "object_get"), + compatibility_new<FunctionTemplate>(isolate, object_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "signal_handler_add"), + compatibility_new<FunctionTemplate>(isolate, signal_handler_add) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, conn); + + return ret; +} + +EAPI +void register_eldbus_connection(v8::Isolate* isolate, v8::Handle<v8::Object> exports) +{ + using v8::String; + register_timeout_infinite(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_TIMEOUT_INFINITE")); + register_connection_type_unknown(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_CONNECTION_TYPE_UNKNOWN")); + register_connection_type_session(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_CONNECTION_TYPE_SESSION")); + register_connection_type_system(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_CONNECTION_TYPE_SYSTEM")); + register_connection_type_starter(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_CONNECTION_TYPE_STARTER")); + register_connection_type_address(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_CONNECTION_TYPE_ADDRESS")); + register_connection_type_last(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_CONNECTION_TYPE_LAST")); + register_connection_event_del(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_CONNECTION_EVENT_DEL")); + register_connection_event_disconnected(isolate, exports, + compatibility_new<String> + (isolate, + "ELDBUS_CONNECTION_EVENT" + "_DISCONNECTED")); + register_connection_event_last(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_CONNECTION_EVENT_LAST")); + + register_connection_get(isolate, exports, + compatibility_new<String> + (isolate, "connection_get")); + + register_private_connection_get(isolate, exports, + compatibility_new<String> + (isolate, "private_connection_get")); + + register_address_connection_get(isolate, exports, + compatibility_new<String> + (isolate, "address_connection_get")); + + register_private_address_connection_get(isolate, exports, + compatibility_new<String> + (isolate, "private_address_connection_get")); +} + +} } } // namespace efl { namespace eldbus { namespace js { diff --git a/src/bindings/js/eldbus_js/eldbus_js_core.cc b/src/bindings/js/eldbus_js/eldbus_js_core.cc new file mode 100644 index 0000000000..e9a8c3344d --- /dev/null +++ b/src/bindings/js/eldbus_js/eldbus_js_core.cc @@ -0,0 +1,183 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eldbus_Js.hh> + +namespace efl { namespace eldbus { namespace js { + +namespace { + +void register_init(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto init = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = eldbus_init(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, init) + ->GetFunction()); +} + +void register_shutdown(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto shutdown = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = eldbus_shutdown(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, shutdown) + ->GetFunction()); +} + +void register_fdo_bus(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + global->Set(name, compatibility_new<String>(isolate, ELDBUS_FDO_BUS)); +} + +void register_fdo_path(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + global->Set(name, compatibility_new<String>(isolate, ELDBUS_FDO_PATH)); +} + +void register_fdo_interface(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + global->Set(name, compatibility_new<String>(isolate, ELDBUS_FDO_INTERFACE)); +} + +void register_fdo_interface_properties(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + global->Set(name, + compatibility_new<String>(isolate, + ELDBUS_FDO_INTERFACE_PROPERTIES)); +} + +void register_fdo_interface_object_manager(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + global->Set(name, + compatibility_new<String>(isolate, + ELDBUS_FDO_INTERFACE_OBJECT_MANAGER)); +} + +void register_fdo_interface_introspectable(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + global->Set(name, + compatibility_new<String>(isolate, + ELDBUS_FDO_INTERFACE_INTROSPECTABLE)); +} + +void register_fdo_inteface_peer(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + global->Set(name, + compatibility_new<String>(isolate, ELDBUS_FDO_INTEFACE_PEER)); +} + +void register_error_pending_canceled(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + global->Set(name, + compatibility_new<String>(isolate, + ELDBUS_ERROR_PENDING_CANCELED)); +} + +void register_error_pending_timeout(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + global->Set(name, + compatibility_new<String>(isolate, + ELDBUS_ERROR_PENDING_TIMEOUT)); +} + +} + +EAPI +void register_eldbus_core(v8::Isolate* isolate, v8::Handle<v8::Object> exports) +{ + using v8::String; + register_init(isolate, exports, + compatibility_new<String>(isolate, "eldbus_init")); + register_shutdown(isolate, exports, + compatibility_new<String>(isolate, "eldbus_shutdown")); + register_fdo_bus(isolate, exports, + compatibility_new<String>(isolate, "ELDBUS_FDO_BUS")); + register_fdo_path(isolate, exports, + compatibility_new<String>(isolate, "ELDBUS_FDO_PATH")); + register_fdo_interface(isolate, exports, + compatibility_new<String>(isolate, + "ELDBUS_FDO_INTERFACE")); + register_fdo_interface_properties(isolate, exports, + compatibility_new<String> + (isolate, + "ELDBUS_FDO_INTERFACE_PROPERTIES")); + register_fdo_interface_object_manager(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_FDO_INTERFACE_OBJECT_MANAGER")); + + register_fdo_interface_introspectable + (isolate, exports, + compatibility_new<String>(isolate, + "ELDBUS_FDO_INTERFACE_INTROSPECTABLE")); + register_fdo_inteface_peer(isolate, exports, + compatibility_new<String> + (isolate, "ELDBUS_FDO_INTEFACE_PEER")); + register_error_pending_canceled + (isolate, exports, + compatibility_new<String>(isolate, "ELDBUS_ERROR_PENDING_CANCELED")); + register_error_pending_timeout + (isolate, exports, + compatibility_new<String>(isolate, "ELDBUS_ERROR_PENDING_TIMEOUT")); +} + +EAPI void register_eldbus(v8::Isolate* isolate, v8::Handle<v8::Object> exports) +{ + register_eldbus_connection(isolate, exports); + register_eldbus_core(isolate, exports); + register_eldbus_message(isolate, exports); + register_eldbus_object_mapper(isolate, exports); +} + +} } } // namespace efl { namespace eldbus { namespace js { diff --git a/src/bindings/js/eldbus_js/eldbus_js_message.cc b/src/bindings/js/eldbus_js/eldbus_js_message.cc new file mode 100644 index 0000000000..f9cfa40b76 --- /dev/null +++ b/src/bindings/js/eldbus_js/eldbus_js_message.cc @@ -0,0 +1,103 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eldbus_Js.hh> + +namespace efl { namespace eldbus { namespace js { + +namespace { + +void register_message_method_call_new(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 4 || !args[0]->IsString() || !args[1]->IsString() + || !args[2]->IsString() || !args[3]->IsString()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + auto ret = eldbus_message_method_call_new(*String::Utf8Value(args[0]), + *String::Utf8Value(args[1]), + *String::Utf8Value(args[2]), + *String::Utf8Value(args[3])); + return compatibility_return(wrap_eldbus_msg(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_message_error_new(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 3 || !args[0]->IsObject() || !args[1]->IsString() + || !args[2]->IsString()) { + return compatibility_return(); + } + + auto isolate = args.GetIsolate(); + auto ret = eldbus_message_error_new(extract_eldbus_msg(args[0] + ->ToObject()), + *String::Utf8Value(args[1]), + *String::Utf8Value(args[2])); + return compatibility_return(wrap_eldbus_msg(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +void register_message_method_return_new(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::String; + using v8::FunctionTemplate; + + auto f = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsObject()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto eldbus_msg = extract_eldbus_msg(args[0]->ToObject()); + auto ret = eldbus_message_method_return_new(eldbus_msg); + return compatibility_return(wrap_eldbus_msg(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, f)->GetFunction()); +} + +} + +EAPI +void register_eldbus_message(v8::Isolate* isolate, v8::Handle<v8::Object> exports) +{ + register_message_method_call_new + (isolate, exports, compatibility_new<v8::String> + (isolate, "message_method_call_new")); + + register_message_error_new + (isolate, exports, compatibility_new<v8::String> + (isolate, "message_error_new")); + + register_message_method_return_new + (isolate, exports, compatibility_new<v8::String> + (isolate, "message_method_return_new")); +} + +} } } // namespace efl { namespace eldbus { namespace js { diff --git a/src/bindings/js/eldbus_js/eldbus_js_object_mapper.cc b/src/bindings/js/eldbus_js/eldbus_js_object_mapper.cc new file mode 100644 index 0000000000..955ce80948 --- /dev/null +++ b/src/bindings/js/eldbus_js/eldbus_js_object_mapper.cc @@ -0,0 +1,100 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eldbus_Js.hh> + +namespace efl { namespace eldbus { namespace js { + +namespace { + +void register_object_event_iface_added(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ELDBUS_OBJECT_EVENT_IFACE_ADDED)); +} + +void register_object_event_iface_removed(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, + ELDBUS_OBJECT_EVENT_IFACE_REMOVED)); +} + +void register_object_event_property_changed(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer> + (isolate, ELDBUS_OBJECT_EVENT_PROPERTY_CHANGED)); +} + +void register_object_event_property_removed(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer> + (isolate, ELDBUS_OBJECT_EVENT_PROPERTY_REMOVED)); +} + +void register_object_event_del(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ELDBUS_OBJECT_EVENT_DEL)); +} + +void register_object_event_last(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + global->Set(name, + compatibility_new<Integer>(isolate, ELDBUS_OBJECT_EVENT_LAST)); +} + +} + +EAPI +void register_eldbus_object_mapper(v8::Isolate* isolate, v8::Handle<v8::Object> exports) +{ + register_object_event_iface_added + (isolate, exports, compatibility_new<v8::String> + (isolate, "object_event_iface_added")); + + register_object_event_iface_removed + (isolate, exports, compatibility_new<v8::String> + (isolate, "object_event_iface_removed")); + + register_object_event_property_changed + (isolate, exports, compatibility_new<v8::String> + (isolate, "object_event_property_changed")); + + register_object_event_property_removed + (isolate, exports, compatibility_new<v8::String> + (isolate, "object_event_property_removed")); + + register_object_event_del + (isolate, exports, compatibility_new<v8::String> + (isolate, "object_event_del")); + + register_object_event_last + (isolate, exports, compatibility_new<v8::String> + (isolate, "object_event_last")); +} + + +} } } // namespace efl { namespace eldbus { namespace js { diff --git a/src/bindings/js/eldbus_js/eldbus_js_util.hh b/src/bindings/js/eldbus_js/eldbus_js_util.hh new file mode 100644 index 0000000000..c5af5752be --- /dev/null +++ b/src/bindings/js/eldbus_js/eldbus_js_util.hh @@ -0,0 +1,836 @@ +#ifndef ELDBUS_JS_UTIL_HH +#define ELDBUS_JS_UTIL_HH + +namespace efl { namespace eldbus { namespace js { + +using eina::js::compatibility_get_pointer_internal_field; +using eina::js::compatibility_set_pointer_internal_field; +using eina::js::compatibility_new; +using eina::js::compatibility_callback_info_type; +using eina::js::compatibility_return_type; +using eina::js::compatibility_return; + +v8::Local<v8::Object> wrap_eldbus_connection(Eldbus_Connection *conn, + v8::Isolate *isolate); + +inline +const Eldbus_Message *extract_const_eldbus_msg(v8::Local<v8::Object> o) +{ + return compatibility_get_pointer_internal_field<Eldbus_Message*>(o, 0); +} + +inline +v8::Local<v8::Object> wrap_const_eldbus_msg(const Eldbus_Message *msg, + v8::Isolate *isolate) +{ + using v8::String; + using v8::Object; + using v8::Boolean; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto path_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto msg = extract_const_eldbus_msg(info.This()); + + auto ret = eldbus_message_path_get(msg); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto interface_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto msg = extract_const_eldbus_msg(info.This()); + + auto ret = eldbus_message_interface_get(msg); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto member_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto msg = extract_const_eldbus_msg(info.This()); + + auto ret = eldbus_message_member_get(msg); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto destination_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto msg = extract_const_eldbus_msg(info.This()); + + auto ret = eldbus_message_destination_get(msg); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto sender_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto msg = extract_const_eldbus_msg(info.This()); + + auto ret = eldbus_message_sender_get(msg); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto signature_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto msg = extract_const_eldbus_msg(info.This()); + + auto ret = eldbus_message_signature_get(msg); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto error_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto msg = extract_const_eldbus_msg(info.This()); + const char *name = NULL; + const char *text = NULL; + auto ret = compatibility_new<Object>(isolate); + + auto bret = eldbus_message_error_get(msg, &name, &text); + ret->Set(compatibility_new<String>(isolate, "ok"), + compatibility_new<Boolean>(isolate, bret)); + + if (bret) { + ret->Set(compatibility_new<String>(isolate, "name"), + compatibility_new<String>(isolate, name)); + ret->Set(compatibility_new<String>(isolate, "text"), + compatibility_new<String>(isolate, text)); + } + + return compatibility_return(ret, info); + }; + + ret->Set(compatibility_new<String>(isolate, "path_get"), + compatibility_new<FunctionTemplate>(isolate, path_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "interface_get"), + compatibility_new<FunctionTemplate>(isolate, interface_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "member_get"), + compatibility_new<FunctionTemplate>(isolate, member_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "destination_get"), + compatibility_new<FunctionTemplate>(isolate, destination_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "sender_get"), + compatibility_new<FunctionTemplate>(isolate, sender_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "signature_get"), + compatibility_new<FunctionTemplate>(isolate, signature_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "error_get"), + compatibility_new<FunctionTemplate>(isolate, error_get) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, + const_cast<Eldbus_Message*>(msg)); + + return ret; +} + +inline Eldbus_Message *extract_eldbus_msg(v8::Local<v8::Object> o) +{ + return compatibility_get_pointer_internal_field<Eldbus_Message*>(o, 0); +} + +inline +v8::Local<v8::Object> wrap_eldbus_msg(Eldbus_Message *msg, v8::Isolate *isolate) +{ + using v8::String; + using v8::FunctionTemplate; + + auto ret = wrap_const_eldbus_msg(msg, isolate); + + auto ref = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto msg = extract_eldbus_msg(info.This()); + + eldbus_message_ref(msg); + + return compatibility_return(); + }; + + auto unref = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto msg = extract_eldbus_msg(info.This()); + + eldbus_message_unref(msg); + + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "ref"), + compatibility_new<FunctionTemplate>(isolate, ref)->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "unref"), + compatibility_new<FunctionTemplate>(isolate, unref) + ->GetFunction()); + + return ret; +} + +inline +v8::Local<v8::Object> wrap_eldbus_pending(Eldbus_Pending *pending, + efl::eina::js::global_ref<v8::Value>* + persistent, + v8::Isolate *isolate) +{ + using v8::String; + using v8::Object; + using v8::Boolean; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + typedef decltype(persistent) persistent_ptr_t; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(2); + auto ret = obj_tpl->NewInstance(); + + auto cancel = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto o = info.This(); + auto pending + = compatibility_get_pointer_internal_field<Eldbus_Pending*>(o, 0); + auto persistent + = compatibility_get_pointer_internal_field<persistent_ptr_t>(o, 1); + + eldbus_pending_cancel(pending); + delete persistent; + return compatibility_return(); + }; + + auto destination_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto pending + = compatibility_get_pointer_internal_field<Eldbus_Pending*>(o, 0); + + auto ret = eldbus_pending_destination_get(pending); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto path_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto pending + = compatibility_get_pointer_internal_field<Eldbus_Pending*>(o, 0); + + auto ret = eldbus_pending_path_get(pending); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto interface_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto pending + = compatibility_get_pointer_internal_field<Eldbus_Pending*>(o, 0); + + auto ret = eldbus_pending_interface_get(pending); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto method_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto pending + = compatibility_get_pointer_internal_field<Eldbus_Pending*>(o, 0); + + auto ret = eldbus_pending_method_get(pending); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + ret->Set(compatibility_new<String>(isolate, "cancel"), + compatibility_new<FunctionTemplate>(isolate, cancel) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "destination_get"), + compatibility_new<FunctionTemplate>(isolate, destination_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "path_get"), + compatibility_new<FunctionTemplate>(isolate, path_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "interface_get"), + compatibility_new<FunctionTemplate>(isolate, interface_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "method_get"), + compatibility_new<FunctionTemplate>(isolate, method_get) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, pending); + compatibility_set_pointer_internal_field(ret, 1, persistent); + + return ret; +} + +inline +v8::Local<v8::Object> +wrap_eldbus_signal_handler(Eldbus_Signal_Handler *handler, + efl::eina::js::global_ref<v8::Value> *persistent, + v8::Isolate *isolate) +{ + using v8::String; + using v8::Object; + using v8::Boolean; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + typedef decltype(persistent) persistent_ptr_t; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(2); + auto ret = obj_tpl->NewInstance(); + + auto ref = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto o = info.This(); + auto handler + = (compatibility_get_pointer_internal_field<Eldbus_Signal_Handler*> + (o, 0)); + + eldbus_signal_handler_ref(handler); + return compatibility_return(); + }; + + auto unref = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto o = info.This(); + auto handler + = (compatibility_get_pointer_internal_field<Eldbus_Signal_Handler*> + (o, 0)); + + eldbus_signal_handler_unref(handler); + return compatibility_return(); + }; + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto o = info.This(); + auto handler + = (compatibility_get_pointer_internal_field<Eldbus_Signal_Handler*> + (o, 0)); + auto persistent + = compatibility_get_pointer_internal_field<persistent_ptr_t>(o, 1); + + eldbus_signal_handler_del(handler); + delete persistent; + return compatibility_return(); + }; + + auto sender_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto handler + = (compatibility_get_pointer_internal_field<Eldbus_Signal_Handler*> + (o, 0)); + + auto ret = eldbus_signal_handler_sender_get(handler); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto path_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto handler + = (compatibility_get_pointer_internal_field<Eldbus_Signal_Handler*> + (o, 0)); + + auto ret = eldbus_signal_handler_path_get(handler); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto interface_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto handler + = (compatibility_get_pointer_internal_field<Eldbus_Signal_Handler*> + (o, 0)); + + auto ret = eldbus_signal_handler_interface_get(handler); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto member_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto handler + = (compatibility_get_pointer_internal_field<Eldbus_Signal_Handler*> + (o, 0)); + + auto ret = eldbus_signal_handler_member_get(handler); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto match_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto handler + = (compatibility_get_pointer_internal_field<Eldbus_Signal_Handler*> + (o, 0)); + + auto ret = eldbus_signal_handler_match_get(handler); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto connection_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto o = info.This(); + auto handler + = (compatibility_get_pointer_internal_field<Eldbus_Signal_Handler*> + (o, 0)); + + auto ret = eldbus_signal_handler_connection_get(handler); + return compatibility_return(wrap_eldbus_connection(ret, isolate), info); + }; + + ret->Set(compatibility_new<String>(isolate, "ref"), + compatibility_new<FunctionTemplate>(isolate, ref)->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "unref"), + compatibility_new<FunctionTemplate>(isolate, unref) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "sender_get"), + compatibility_new<FunctionTemplate>(isolate, sender_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "path_get"), + compatibility_new<FunctionTemplate>(isolate, path_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "interface_get"), + compatibility_new<FunctionTemplate>(isolate, interface_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "member_get"), + compatibility_new<FunctionTemplate>(isolate, member_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "match_get"), + compatibility_new<FunctionTemplate>(isolate, match_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "connection_get"), + compatibility_new<FunctionTemplate>(isolate, connection_get) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, handler); + compatibility_set_pointer_internal_field(ret, 1, persistent); + + return ret; +} + +static +v8::Local<v8::Object> wrap_object_event_callback(Eldbus_Object *obj, + Eldbus_Object_Event_Type type, + Eldbus_Object_Event_Cb cb, + void *cb_data, + v8::Isolate *isolate) +{ + using v8::String; + using v8::Integer; + using v8::Value; + using v8::Object; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(3); + auto ret = obj_tpl->NewInstance(); + + ret->Set(compatibility_new<String>(isolate, "_type"), + compatibility_new<Integer>(isolate, type)); + + compatibility_set_pointer_internal_field(ret, 0, obj); + compatibility_set_pointer_internal_field(ret, 1, (void*)(cb)); + compatibility_set_pointer_internal_field(ret, 2, cb_data); + + auto del = [](compatibility_callback_info_type info) + -> compatibility_return_type { + auto o = info.This(); + auto isolate = info.GetIsolate(); + + auto obj + = (compatibility_get_pointer_internal_field<Eldbus_Object*> + (o, 0)); + auto cb + = (compatibility_get_pointer_internal_field + <Eldbus_Object_Event_Cb>(o, 1)); + auto cb_data + = (compatibility_get_pointer_internal_field + <efl::eina::js::global_ref<Value>*>(o, 2)); + auto type + = (static_cast<Eldbus_Object_Event_Type> + (o->Get(compatibility_new<String>(isolate, "_type")) + ->IntegerValue())); + + eldbus_object_event_callback_del(obj, type, cb, cb_data); + + delete cb_data; + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "del"), + compatibility_new<FunctionTemplate>(isolate, del)->GetFunction()); + + return ret; +} + +inline +Eldbus_Object *extract_eldbus_object(v8::Local<v8::Object> o) +{ + return compatibility_get_pointer_internal_field<Eldbus_Object*>(o, 0); +} + +inline +v8::Local<v8::Object> wrap_eldbus_object(Eldbus_Object *object, + v8::Isolate *isolate) +{ + using v8::String; + using v8::Value; + using v8::Handle; + using v8::Function; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto ref = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto object = extract_eldbus_object(info.This()); + + eldbus_object_ref(object); + return compatibility_return(); + }; + + auto unref = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto object = extract_eldbus_object(info.This()); + + eldbus_object_unref(object); + return compatibility_return(); + }; + + auto event_callback_add = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 2 || !info[0]->IsNumber() + || !info[1]->IsFunction()) { + return compatibility_return(); + } + + Eldbus_Object_Event_Type type; + + switch (info[0]->IntegerValue()) { + case ELDBUS_OBJECT_EVENT_IFACE_ADDED: + type = ELDBUS_OBJECT_EVENT_IFACE_ADDED; + break; + case ELDBUS_OBJECT_EVENT_IFACE_REMOVED: + type = ELDBUS_OBJECT_EVENT_IFACE_REMOVED; + break; + case ELDBUS_OBJECT_EVENT_PROPERTY_CHANGED: + type = ELDBUS_OBJECT_EVENT_PROPERTY_CHANGED; + break; + case ELDBUS_OBJECT_EVENT_PROPERTY_REMOVED: + type = ELDBUS_OBJECT_EVENT_PROPERTY_REMOVED; + break; + case ELDBUS_OBJECT_EVENT_DEL: + type = ELDBUS_OBJECT_EVENT_DEL; + break; + case ELDBUS_OBJECT_EVENT_LAST: + type = ELDBUS_OBJECT_EVENT_LAST; + break; + default: + return compatibility_return(); + } + + auto isolate = info.GetIsolate(); + + unique_ptr<persistent_t> cb_data{new persistent_t{isolate, info[1]}}; + + auto cb = [](void *data, Eldbus_Object *obj, void */*event_info*/) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args{wrap_eldbus_object(obj, isolate)}; + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + }; + + auto object = extract_eldbus_object(info.This()); + + eldbus_object_event_callback_add(object, type, cb, cb_data.get()); + auto ret = wrap_object_event_callback(object, type, cb, + cb_data.release(), isolate); + return compatibility_return(ret, info); + }; + + auto connection_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto object = extract_eldbus_object(info.This()); + + auto conn = eldbus_object_connection_get(object); + return compatibility_return(wrap_eldbus_connection(conn, isolate), + info); + }; + + auto bus_name_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto object = extract_eldbus_object(info.This()); + + auto ret = eldbus_object_bus_name_get(object); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto path_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto object = extract_eldbus_object(info.This()); + + auto ret = eldbus_object_path_get(object); + return compatibility_return(compatibility_new<String>(isolate, ret), + info); + }; + + auto send = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 3 || !info[0]->IsObject() || !info[1]->IsFunction() + || !info[2]->IsNumber()) { + return compatibility_return(); + } + + auto isolate = info.GetIsolate(); + auto obj = extract_eldbus_object(info.This()); + auto msg + = (compatibility_get_pointer_internal_field<Eldbus_Message*> + (info[0]->ToObject(), 0)); + + unique_ptr<persistent_t> cb_data{new persistent_t{isolate, info[1]}}; + + auto cb = [](void *data, const Eldbus_Message *msg, + Eldbus_Pending *pending) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_const_eldbus_msg(msg, isolate), + wrap_eldbus_pending(pending, persistent, isolate) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + + delete persistent; + }; + + auto ret = eldbus_object_send(obj, msg, cb, cb_data.get(), + info[2]->NumberValue()); + return compatibility_return(wrap_eldbus_pending(ret, cb_data.release(), + isolate), + info); + }; + + auto signal_handler_add = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 3 || !info[0]->IsString() || !info[1]->IsString() + || !info[2]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = info.GetIsolate(); + auto object = extract_eldbus_object(info.This()); + String::Utf8Value interface(info[0]); + String::Utf8Value member(info[1]); + + unique_ptr<persistent_t> cb_data{new persistent_t{isolate, info[2]}}; + + auto cb = [](void *data, const Eldbus_Message *msg) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args{wrap_const_eldbus_msg(msg, isolate)}; + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + }; + + auto ret = eldbus_object_signal_handler_add(object, *interface, *member, + cb, cb_data.get()); + return + compatibility_return(wrap_eldbus_signal_handler(ret, + cb_data.release(), + isolate), + info); + }; + + auto method_call_new = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 2 || !info[0]->IsString() + || !info[1]->IsString()) { + return compatibility_return(); + } + + auto isolate = info.GetIsolate(); + auto object = extract_eldbus_object(info.This()); + auto ret = eldbus_object_method_call_new(object, + *String::Utf8Value(info[0]), + *String::Utf8Value(info[1])); + return compatibility_return(wrap_eldbus_msg(ret, isolate), info); + }; + + ret->Set(compatibility_new<String>(isolate, "ref"), + compatibility_new<FunctionTemplate>(isolate, ref)->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "unref"), + compatibility_new<FunctionTemplate>(isolate, unref) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "event_callback_add"), + compatibility_new<FunctionTemplate>(isolate, event_callback_add) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "connection_get"), + compatibility_new<FunctionTemplate>(isolate, connection_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "bus_name_get"), + compatibility_new<FunctionTemplate>(isolate, bus_name_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "path_get"), + compatibility_new<FunctionTemplate>(isolate, path_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "send"), + compatibility_new<FunctionTemplate>(isolate, send)->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "signal_handler_add"), + compatibility_new<FunctionTemplate>(isolate, signal_handler_add) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "method_call_new"), + compatibility_new<FunctionTemplate>(isolate, method_call_new) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, object); + + return ret; +} + +} } } // namespace efl { namespace eldbus { namespace js { + +#endif /* ELDBUS_JS_UTIL_HH */ diff --git a/src/bindings/js/eo_js/Eo_Js.hh b/src/bindings/js/eo_js/Eo_Js.hh new file mode 100644 index 0000000000..ab08b9886e --- /dev/null +++ b/src/bindings/js/eo_js/Eo_Js.hh @@ -0,0 +1,15 @@ +#ifndef EFL_EO_JS_HH +#define EFL_EO_JS_HH + +#include <Eina_Js.hh> + +#include <eo_js_direction.hh> +#include <eo_js_constructor.hh> +#include <eo_js_call_function.hh> +#include <eo_js_event.hh> +#include <eo_js_namespace.hh> +#include <eo_js_struct.hh> +#include <eo_js_construct_from_eo.hh> + +#endif + diff --git a/src/bindings/js/eo_js/eo_js_call_function.hh b/src/bindings/js/eo_js/eo_js_call_function.hh new file mode 100644 index 0000000000..26bf03f862 --- /dev/null +++ b/src/bindings/js/eo_js/eo_js_call_function.hh @@ -0,0 +1,288 @@ +#ifndef EFL_EO_JS_CALL_FUNCTION_HH +#define EFL_EO_JS_CALL_FUNCTION_HH + +#include <eina_tuple.hh> +#include <eina_tuple_c.hh> +#include <eina_function.hh> + +#include <cstdlib> +#include <functional> +#include <iostream> +#include <cassert> +#include <vector> + +namespace efl { namespace eo { namespace js { + +inline eina::js::compatibility_return_type call_function(eina::js::compatibility_callback_info_type args) +{ + void* data = v8::External::Cast(*args.Data())->Value(); + std::function<eina::js::compatibility_return_type(eina::js::compatibility_callback_info_type)>* + f = static_cast<std::function<eina::js::compatibility_return_type(eina::js::compatibility_callback_info_type)>*>(data); + return (*f)(args); +} + +template <typename In, std::size_t I> +struct is_in : eina::_mpl::tuple_contains<std::integral_constant<std::size_t, I>, In> +{}; + +template <typename In, std::size_t I> +struct arg_index : std::integral_constant<std::size_t, + std::conditional<is_in<In, I>::value, std::integral_constant<std::size_t, 1>, std::integral_constant<std::size_t, 0>>::type::value + + arg_index<In, I - 1>::value> +{}; + +template <typename In> +struct arg_index<In, 0> : std::integral_constant<std::size_t, 0> +{}; + +template <typename In, typename Out, typename Ownership, typename F, typename Return, typename Parameters> +struct method_caller +{ + typedef typename eina::_mpl::function_params<F>::type parameters_t; + + template <std::size_t I> + struct is_out : eina::_mpl::tuple_contains<std::integral_constant<std::size_t, I>, Out> + {}; + + template <std::size_t I> + struct is_inout : std::integral_constant<bool, + eina::_mpl::tuple_contains<std::integral_constant<std::size_t, I>, Out>::value && + eina::_mpl::tuple_contains<std::integral_constant<std::size_t, I>, In>::value> + {}; + + template <std::size_t I, typename Outs> + static + typename std::tuple_element<I, parameters_t>::type + get_value(eina::js::compatibility_callback_info_type args, Outs& /*outs*/, v8::Isolate* isolate, char const* class_name + , std::false_type) + { + using Param = typename std::tuple_element<I, Parameters>::type; + const auto js_index = arg_index<In, I>::value; + + return eina::js::get_value_from_javascript + (args[js_index], isolate, class_name, eina::js::value_tag<Param>()); + } + + template <std::size_t I, typename Outs> + static + typename std::add_pointer< + typename std::tuple_element + <eina::_mpl::tuple_find<std::integral_constant<std::size_t, I>, Out>::value + , Outs>::type>::type + get_value(eina::js::compatibility_callback_info_type, Outs& outs, v8::Isolate*, char const* + , std::true_type) + { + return &std::get<eina::_mpl::tuple_find<std::integral_constant<std::size_t, I>, Out>::value> + (outs); + } + + template <typename OutParameter, std::size_t I, typename R> + eina::js::compatibility_return_type + create_return_unique_value(eina::js::compatibility_callback_info_type args + , R const& r) const + { + return eina::js::compatibility_return( + eina::js::get_value_from_c( + eina::js::wrap_value<OutParameter>(r, eina::js::value_tag<OutParameter>{}), + args.GetIsolate(), + class_names[I]), + args); + } + + template <typename OutParameters, typename Outs> + eina::js::compatibility_return_type + create_return_value(eina::js::compatibility_callback_info_type args + , Outs const& outs + , typename std::enable_if<std::tuple_size<Outs>::value == 1>::type* = 0) const + { + using OutParameter = typename std::tuple_element<0, OutParameters>::type; + return create_return_unique_value<OutParameter, std::tuple_element<0, Out>::type::value>(args, std::get<0u>(outs)); + } + + template <typename OutParameters, typename Outs> + eina::js::compatibility_return_type + create_return_value(eina::js::compatibility_callback_info_type + , Outs const& + , typename std::enable_if<std::tuple_size<Outs>::value == 0>::type* = 0) const + { + // nothing + return eina::js::compatibility_return(); + } + + template <typename OutParameters, typename Outs> + eina::js::compatibility_return_type + create_return_value(eina::js::compatibility_callback_info_type args + , Outs const& outs + , typename std::enable_if<(std::tuple_size<Outs>::value > 1)>::type* = 0) const + { + v8::Isolate* isolate = args.GetIsolate(); + int const length = std::tuple_size<Outs>::value; + v8::Local<v8::Array> ret = eina::js::compatibility_new<v8::Array>(isolate, length); + set_return<OutParameters, 0u>(isolate, ret, outs, eina::make_index_sequence<std::tuple_size<Outs>::value>()); + return eina::js::compatibility_return(ret, args); + } + + template <typename OutParameters, typename R, typename Outs> + eina::js::compatibility_return_type + create_return_value(eina::js::compatibility_callback_info_type args + , R const& r + , Outs const& + , typename std::enable_if<std::tuple_size<Outs>::value == 0>::type* = 0) const + { + return create_return_unique_value<Return, std::tuple_size<Ownership>::value>(args, r); + } + + template <typename OutParameters, std::size_t Offset, typename Outs, std::size_t...S> + void set_return(v8::Isolate* isolate, v8::Local<v8::Array> r + , Outs const& outs, eina::index_sequence<S...>) const + { + std::initializer_list<int> l + = {(r->Set(S+Offset, eina::js::get_value_from_c( + eina::js::wrap_value<typename std::tuple_element<S, OutParameters>::type>(std::get<S>(outs), eina::js::value_tag<typename std::tuple_element<S, OutParameters>::type>{}), + isolate, + class_names[std::tuple_element<S, Out>::type::value])),0)...}; + static_cast<void>(l); + } + + template <typename OutParameters, typename R, typename Outs> + eina::js::compatibility_return_type + create_return_value(eina::js::compatibility_callback_info_type args + , R const& r + , Outs const& outs + , typename std::enable_if<std::tuple_size<Outs>::value != 0>::type* = 0) const + { + v8::Isolate* isolate = args.GetIsolate(); + int const length = std::tuple_size<Outs>::value + 1; + v8::Local<v8::Array> ret = eina::js::compatibility_new<v8::Array>(isolate, length); + ret->Set(0, eina::js::get_value_from_c( + eina::js::wrap_value<Return>(r, eina::js::value_tag<Return>{}), + isolate, + class_names[std::tuple_size<Ownership>::value])); + set_return<OutParameters, 1u>(isolate, ret, outs, eina::make_index_sequence<std::tuple_size<Outs>::value>()); + return eina::js::compatibility_return(ret, args); + } + + template <std::size_t I, typename Outs> + static void + init_inout(eina::js::compatibility_callback_info_type args + , Outs& outs + , v8::Isolate* isolate + , char const* class_name + , std::true_type) + { + using Param = typename std::remove_pointer<typename std::tuple_element<I, Parameters>::type>::type; + + const auto js_index = arg_index<In, I>::value; + + *get_value<I>(args, outs, args.GetIsolate(), class_name, std::true_type()) = + eina::js::get_value_from_javascript(args[js_index], isolate, class_name, eina::js::value_tag<Param>());; + } + + template <std::size_t I, typename Outs> + static void + init_inout(eina::js::compatibility_callback_info_type + , Outs& + , v8::Isolate* + , char const* + , std::false_type) + { + } + + template <typename OutParameters, std::size_t... I> + eina::js::compatibility_return_type + aux(eina::js::compatibility_callback_info_type args, eina::index_sequence<I...> + , std::true_type) const + { + typename eina::_mpl::tuple_transform<Out, out_transform<parameters_t> >::type outs {}; + static_cast<void>(outs); + + std::initializer_list<int> l = + {(init_inout<I>(args, outs, args.GetIsolate(), class_names[I], typename is_inout<I>::type()), 0)...}; + static_cast<void>(l); + + function(get_value<I>(args, outs, args.GetIsolate(), class_names[I], typename is_out<I>::type())...); + return create_return_value<OutParameters>(args, outs); + } + + template <typename OutParameters, std::size_t... I> + eina::js::compatibility_return_type + aux(eina::js::compatibility_callback_info_type args, eina::index_sequence<I...> + , std::false_type) const + { + typename eina::_mpl::tuple_transform<Out, out_transform<parameters_t> >::type outs {}; + static_cast<void>(outs); + + std::initializer_list<int> l = + {(init_inout<I>(args, outs, args.GetIsolate(), class_names[I], typename is_inout<I>::type()), 0)...}; + static_cast<void>(l); + + typename eina::_mpl::function_return<F>::type r = + function(get_value<I>(args, outs, args.GetIsolate(), class_names[I], typename is_out<I>::type())...); + return create_return_value<OutParameters>(args, r, outs); + } + + template <typename P> + struct out_transform + { + template <typename T> + struct apply + { + typedef typename std::remove_pointer<typename std::tuple_element<T::value, P>::type>::type type; + }; + }; + + eina::js::compatibility_return_type operator()(eina::js::compatibility_callback_info_type args) + { + using OutParameters = typename eina::_mpl::tuple_transform<Out, out_transform<Parameters> >::type; + + int input_parameters = std::tuple_size<In>::value; + if(input_parameters <= args.Length()) + { + v8::Local<v8::Object> self = args.This(); + v8::Local<v8::Value> external = self->GetInternalField(0); + Eo* eo = static_cast<Eo*>(v8::External::Cast(*external)->Value()); + try + { + eo_do + (eo, + aux<OutParameters>( + args, + eina::make_index_sequence<std::tuple_size<parameters_t>::value>(), + std::is_same<void, Return>()) + ); + } + catch(std::logic_error const&) + { + return eina::js::compatibility_return(); + } + } + else + { + return eina::js::compatibility_throw + (v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(nullptr, "Expected more arguments for this call"))); + } + } + + template <typename A> + method_caller(F f, A&& c) + : function(f) + , class_names(std::forward<A>(c)) + {} + + F function; + /// Hold the names of the type of each argument, with the return's type name at the end + std::array<const char*, std::tuple_size<Ownership>::value + 1> class_names; +}; + +template <typename In, typename Out, typename Ownership, typename Return, typename Parameters, std::size_t N, typename F> +v8::Handle<v8::Value> call_function_data(v8::Isolate* isolate, std::array<const char*, N> class_names, F f) +{ + return eina::js::compatibility_new<v8::External> + (isolate, new std::function<eina::js::compatibility_return_type(eina::js::compatibility_callback_info_type const&)> + (method_caller<In, Out, Ownership, F, Return, Parameters>{f, class_names})); +} + +} } } + +#endif diff --git a/src/bindings/js/eo_js/eo_js_construct_from_eo.hh b/src/bindings/js/eo_js/eo_js_construct_from_eo.hh new file mode 100644 index 0000000000..287aaa748c --- /dev/null +++ b/src/bindings/js/eo_js/eo_js_construct_from_eo.hh @@ -0,0 +1,39 @@ +#ifndef EFL_EO_JS_CONSTRUCT_FROM_EO_HH +#define EFL_EO_JS_CONSTRUCT_FROM_EO_HH + +#include <eina_tuple.hh> +#include <eina_tuple_c.hh> +#include <eina_function.hh> +#include <Eo.h> + +#include <cstdlib> +#include <functional> +#include <iostream> +#include <cassert> +#include <vector> + +namespace efl { namespace eo { namespace js { + +inline eina::js::compatibility_return_type construct_from_eo(eina::js::compatibility_callback_info_type args) +{ + if(args.IsConstructCall()) + { + Eo* eo = static_cast<Eo*>(v8::External::Cast(*args[0])->Value()); + args.This()->SetInternalField(0, args[0]); + efl::eina::js::make_weak(args.GetIsolate(), args.This(), [eo] { eo_unref(eo); }); + return eina::js::compatibility_return(); + } + else + { + std::size_t argc = args.Length(); + std::vector<v8::Local<v8::Value> > argv (argc ? argc : 1 ); + for(int i = 0; i != args.Length(); ++i) + argv[i] = args[i]; + args.Callee()->NewInstance(argc, &argv[0]); + return eina::js::compatibility_return(); + } +} + +} } } + +#endif diff --git a/src/bindings/js/eo_js/eo_js_constructor.hh b/src/bindings/js/eo_js/eo_js_constructor.hh new file mode 100644 index 0000000000..09cc9dce71 --- /dev/null +++ b/src/bindings/js/eo_js/eo_js_constructor.hh @@ -0,0 +1,136 @@ +#ifndef EFL_EO_JS_CONSTRUCTOR_HH +#define EFL_EO_JS_CONSTRUCTOR_HH + +#include <Eina.hh> + +#include <eina_tuple.hh> +#include <eina_function.hh> +#include <Eo.h> + +#include <cstdlib> +#include <functional> +#include <iostream> +#include <cassert> +#include <vector> + +namespace efl { namespace eo { namespace js { + +inline eina::js::compatibility_return_type constructor(eina::js::compatibility_callback_info_type args) +{ + if(args.IsConstructCall()) + { + void* data = v8::External::Cast(*args.Data())->Value(); + std::function<eina::js::compatibility_return_type(eina::js::compatibility_callback_info_type)>* + f = static_cast<std::function<eina::js::compatibility_return_type(eina::js::compatibility_callback_info_type)>*> + (data); + return (*f)(args); + } + else + { + std::size_t argc = args.Length(); + std::vector<v8::Local<v8::Value> > argv (argc ? argc : 1 ); + for(int i = 0; i != args.Length(); ++i) + argv[i] = args[i]; + args.Callee()->NewInstance(argc, &argv[0]); + return eina::js::compatibility_return(); + } +} + +template <typename...F> +struct constructor_caller +{ + struct call + { + template <typename T> + void operator()(T function) const + { + int const parameters + = std::tuple_size<typename eina::_mpl::function_params<T>::type>::value; + if(*current + parameters <= args->Length()) + { + aux(function, eina::make_index_sequence<parameters>()); + *current += parameters; + } + else + { + eina::js::compatibility_throw + (v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(args->GetIsolate(), "Expected more arguments for this call"))); + throw std::logic_error(""); + } + } + + template <typename U, std::size_t I> + static + typename std::tuple_element<I, typename eina::_mpl::function_params<U>::type>::type + get_value(v8::Local<v8::Value> v, v8::Isolate* isolate) + { + typename std::tuple_element<I, typename eina::_mpl::function_params<U>::type>::type + tmp = + eina::js::get_value_from_javascript + (v, isolate, "" + , eina::js::value_tag<typename std::tuple_element + <I, typename eina::_mpl::function_params<U>::type>::type>()); + return tmp; + } + + template <typename T, std::size_t... I> + void aux(T function, eina::index_sequence<I...>) const + { + function(get_value<T, I>((*args)[I + *current], args->GetIsolate())...); + } + + int* current; + eina::js::compatibility_callback_info_pointer args; + }; + + eina::js::compatibility_return_type operator()(eina::js::compatibility_callback_info_type args) const + { + int current_index = 1; + if(args.Length() != 0) + { + try + { + Eo* parent = eina::js::get_value_from_javascript + (args[0], args.GetIsolate(), "", eina::js::value_tag<Eo*>()); + Eo* eo = eo_add + (klass + , parent + , eina::_mpl::for_each(constructors, call{¤t_index, &args}) + ); + assert(eo != 0); + v8::Local<v8::Object> self = args.This(); + self->SetInternalField(0, eina::js::compatibility_new<v8::External>(args.GetIsolate(), eo)); + efl::eina::js::make_weak(args.GetIsolate(), self + , [eo] + { + eo_unref(eo); + }); + } + catch(std::logic_error const&) {} + } + else + { + eina::js::compatibility_throw + (v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Expected at least one argument for this call"))); + } + return eina::js::compatibility_return(); + } + + Eo_Class const* klass; + std::tuple<F...> constructors; +}; + +template <typename... F> +v8::Handle<v8::Value> constructor_data(v8::Isolate* isolate, Eo_Class const* klass, F... f) +{ + return eina::js::compatibility_new<v8::External> + (isolate + , new std::function<eina::js::compatibility_return_type(eina::js::compatibility_callback_info_type)> + (constructor_caller<F...>{klass, std::tuple<F...>{f...}})); +} + +} } } + +#endif diff --git a/src/bindings/js/eo_js/eo_js_direction.hh b/src/bindings/js/eo_js/eo_js_direction.hh new file mode 100644 index 0000000000..96cd07608c --- /dev/null +++ b/src/bindings/js/eo_js/eo_js_direction.hh @@ -0,0 +1,12 @@ +#ifndef EFL_EO_JS_EO_JS_DIRECTION_HH +#define EFL_EO_JS_EO_JS_DIRECTION_HH + +namespace efl { namespace eo { namespace js { + +struct input {}; +struct output {}; +struct input_output {}; + +} } } + +#endif diff --git a/src/bindings/js/eo_js/eo_js_event.hh b/src/bindings/js/eo_js/eo_js_event.hh new file mode 100644 index 0000000000..ab2dd34fee --- /dev/null +++ b/src/bindings/js/eo_js/eo_js_event.hh @@ -0,0 +1,126 @@ +#ifndef EFL_EO_JS_EVENT_HH +#define EFL_EO_JS_EVENT_HH + +#include <eina_tuple.hh> +#include <eina_tuple_c.hh> +#include <eina_function.hh> +#include <Eo.h> + +#include <cstdlib> +#include <functional> +#include <iostream> +#include <cassert> +#include <vector> + +namespace efl { namespace eo { namespace js { + +struct event_information +{ + eina::js::global_ref<v8::Function>* constructor; + Eo_Event_Description const* event; + Eo_Event_Cb event_callback; + const char* class_name; +}; + +typedef std::map<std::string, event_information*> event_information_map; + +struct event_callback_information +{ + event_information* event_info; + eina::js::global_ref<v8::Function> function; +}; + +template <typename T> +v8::Local<v8::Value> get_event_info(void* event_info, v8::Isolate* isolate, const char* class_name) +{ + using no_tag_type = typename eina::js::remove_tag<T>::type; + return eina::js::get_value_from_c( + eina::js::wrap_value<T>(*static_cast<no_tag_type*>(event_info), eina::js::value_tag<T>{}), + isolate, + class_name); +} + +// FIXME: This shouldn't be necessary. Reveiew Eolian standards. +template <> +inline v8::Local<v8::Value> get_event_info<const char*>(void* event_info, v8::Isolate* isolate, const char*) +{ + return eina::js::get_value_from_c(static_cast<const char*>(event_info), isolate, ""); +} + +template <> +inline v8::Local<v8::Value> get_event_info<void>(void*, v8::Isolate* isolate, const char*) +{ + return v8::Undefined(isolate); +} + +template <typename T> +inline Eina_Bool event_callback(void* data, Eo* obj, Eo_Event_Description const* + , void* event_info) +{ + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + event_callback_information* event = static_cast<event_callback_information*>(data); + v8::Handle<v8::Value> a[] = {eina::js::compatibility_new<v8::External>(isolate, obj)}; + v8::Local<v8::Object> self = (event->event_info->constructor->handle())->NewInstance(1, a); + + v8::Local<v8::Value> call_args[] = { + self, + get_event_info<T>(event_info, isolate, event->event_info->class_name) + }; + event->function.handle()->Call(eina::js::compatibility_global(), 2, call_args); + + return EO_CALLBACK_CONTINUE; +} + +inline eina::js::compatibility_return_type on_event(eina::js::compatibility_callback_info_type args) +{ + if (args.Length() >= 2) + { + v8::Local<v8::Value> ev_name = args[0]; + v8::Local<v8::Value> f = args[1]; + if (ev_name->IsString() && f->IsFunction()) + { + v8::Local<v8::Value> data = args.Data(); + auto ev_map = + static_cast<event_information_map*> + (v8::External::Cast(*data)->Value()); + + v8::String::Utf8Value str(ev_name->ToString()); + auto found = ev_map->find(*str); + if (found == ev_map->end()) + return eina::js::compatibility_return(); + + auto event = found->second; + + v8::Local<v8::Object> self = args.This(); + v8::Local<v8::Value> external = self->GetInternalField(0); + Eo* eo = static_cast<Eo*>(v8::External::Cast(*external)->Value()); + + auto isolate = args.GetIsolate(); + + event_callback_information* i = new event_callback_information + {event, {isolate, eina::js::compatibility_cast<v8::Function>(f)}}; + eo_do(eo, eo_event_callback_priority_add + (event->event, EO_CALLBACK_PRIORITY_DEFAULT, event->event_callback, i)); + } + else + { + eina::js::compatibility_throw + (v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Invalid argument type"))); + throw std::logic_error(""); + } + } + else + { + eina::js::compatibility_throw + (v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(args.GetIsolate(), "Expected more arguments for this call"))); + throw std::logic_error(""); + } + return eina::js::compatibility_return(); +} + +} } } + +#endif diff --git a/src/bindings/js/eo_js/eo_js_namespace.hh b/src/bindings/js/eo_js/eo_js_namespace.hh new file mode 100644 index 0000000000..4fe9d9b797 --- /dev/null +++ b/src/bindings/js/eo_js/eo_js_namespace.hh @@ -0,0 +1,24 @@ +#ifndef EFL_EO_JS_NAMESPACE_HH +#define EFL_EO_JS_NAMESPACE_HH + +namespace efl { namespace eo { namespace js { + +inline +v8::Local<v8::Object> get_namespace(std::vector<const char*> const& nss, v8::Isolate* isolate, v8::Local<v8::Object> to_export) +{ + for (auto ns : nss) + { + v8::Local<v8::Value> ns_obj = to_export->Get(::efl::eina::js::compatibility_new<v8::String>(isolate, ns)); + if (ns_obj->IsUndefined() || ns_obj->IsNull()) + { + ns_obj = ::efl::eina::js::compatibility_new<v8::Object>(isolate); + to_export->Set(::efl::eina::js::compatibility_new<v8::String>(isolate, ns), ns_obj); + } + to_export = ns_obj->ToObject(); + } + return to_export; +} + +} } } + +#endif diff --git a/src/bindings/js/eo_js/eo_js_struct.hh b/src/bindings/js/eo_js/eo_js_struct.hh new file mode 100644 index 0000000000..731f9d093c --- /dev/null +++ b/src/bindings/js/eo_js/eo_js_struct.hh @@ -0,0 +1,106 @@ +#ifndef EFL_EO_JS_STRUCT_HH +#define EFL_EO_JS_STRUCT_HH + +#include <eina_tuple.hh> +#include <eina_tuple_c.hh> +#include <eina_function.hh> +#include <Eo.h> + +#include <cstdlib> +#include <functional> +#include <iostream> +#include <cassert> +#include <vector> + +namespace efl { namespace eo { namespace js { + +template <typename S, typename M, M S::*MPtr, typename K> +eina::js::compatibility_accessor_getter_return_type +get_struct_member(v8::Local<v8::String>, eina::js::compatibility_accessor_getter_callback_info_type info) +{ + v8::Local<v8::Object> self_obj = eina::js::compatibility_cast<v8::Object>(info.This()); + auto sct = static_cast<S*>(eina::js::compatibility_get_pointer_internal_field(self_obj, 0)); + return eina::js::compatibility_return(eina::js::get_value_from_c(sct->*MPtr, info.GetIsolate(), K::class_name()), info); +} + +template <typename S, typename GenTag, typename M, M S::*MPtr, typename K> +eina::js::compatibility_accessor_setter_return_type +set_struct_member(v8::Local<v8::String>, v8::Local<v8::Value> value, eina::js::compatibility_accessor_setter_callback_info_type info) +{ + v8::Local<v8::Object> self_obj = eina::js::compatibility_cast<v8::Object>(info.This()); + auto sct = static_cast<S*>(eina::js::compatibility_get_pointer_internal_field(self_obj, 0)); + sct->*MPtr = eina::js::get_value_from_javascript(value, info.GetIsolate(), K::class_name(), eina::js::value_tag<GenTag>()); +} + +template <typename S> +eina::js::compatibility_return_type new_struct(eina::js::compatibility_callback_info_type args) +{ + if (!args.IsConstructCall()) + return eina::js::compatibility_throw + (nullptr, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(nullptr, "Not constructor call"))); + + if(args.Length() == 0) + { + S* p = new S{}; + eina::js::compatibility_set_pointer_internal_field(args.This(), 0, static_cast<void*>(p)); + } + else + { + if (!args[0]->IsExternal()) + return eina::js::compatibility_throw + (nullptr, v8::Exception::TypeError + (eina::js::compatibility_new<v8::String>(nullptr, "Invalid argument type for constructor call"))); + + S* p = reinterpret_cast<S*>(v8::External::Cast(*args[0])->Value()); + eina::js::compatibility_set_pointer_internal_field(args.This(), 0, static_cast<void*>(p)); + } + + return eina::js::compatibility_return(); +} + +template <typename S, typename F> +inline void register_struct_persistent(v8::Isolate* isolate, const char* name, const char* full_name, F&& fields_func) +{ + v8::Handle<v8::FunctionTemplate> constructor = eina::js::compatibility_new<v8::FunctionTemplate>(isolate, &efl::eo::js::new_struct<S>); + constructor->SetClassName(eina::js::compatibility_new<v8::String>(isolate, name)); + + v8::Local<v8::ObjectTemplate> instance_t = constructor->InstanceTemplate(); + instance_t->SetInternalFieldCount(1); + v8::Local<v8::ObjectTemplate> prototype = constructor->PrototypeTemplate(); + + fields_func(isolate, prototype); + + static efl::eina::js::global_ref<v8::ObjectTemplate> instance_persistent{isolate, instance_t}; + static efl::eina::js::global_ref<v8::Function> instance_template{isolate, constructor->GetFunction()}; + (void)instance_persistent; + + eina::js::register_class_constructor(full_name, instance_template.handle()); +} + +template <typename S, typename F> +void register_struct_exports(v8::Isolate* isolate, const char* name, v8::Handle<v8::Object> exports, F&& fields_func) +{ + v8::Handle<v8::FunctionTemplate> constructor = eina::js::compatibility_new<v8::FunctionTemplate>(isolate, &efl::eo::js::new_struct<S>); + constructor->SetClassName(eina::js::compatibility_new<v8::String>(isolate, name)); + + v8::Local<v8::ObjectTemplate> instance_t = constructor->InstanceTemplate(); + instance_t->SetInternalFieldCount(1); + v8::Local<v8::ObjectTemplate> prototype = constructor->PrototypeTemplate(); + + fields_func(isolate, prototype); + + exports->Set(eina::js::compatibility_new<v8::String>(isolate, name), constructor->GetFunction()); +} + + +template <typename S, typename F> +void register_struct(v8::Isolate* isolate, const char* name, const char* full_name, v8::Handle<v8::Object> exports, F&& fields_func) +{ + register_struct_persistent<S>(isolate, name, full_name, std::forward<F>(fields_func)); + register_struct_exports<S>(isolate, name, exports, std::forward<F>(fields_func)); +} + +} } } + +#endif diff --git a/src/bindings/js/ethumb_js/Ethumb_Js.hh b/src/bindings/js/ethumb_js/Ethumb_Js.hh new file mode 100644 index 0000000000..39459708ae --- /dev/null +++ b/src/bindings/js/ethumb_js/Ethumb_Js.hh @@ -0,0 +1,48 @@ +#ifndef ETHUMB_JS_INIT_HH +#define ETHUMB_JS_INIT_HH + +#include <Eina.hh> + +#include <Eina_Js.hh> +#include <Ethumb_Client.h> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ETHUMB_JS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ETHUMB_JS_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +namespace efl { namespace ethumb { namespace js { + +using ::efl::eina::js::compatibility_new; +using ::efl::eina::js::compatibility_return_type; +using ::efl::eina::js::compatibility_callback_info_type; +using ::efl::eina::js::compatibility_return; +using ::efl::eina::js::compatibility_get_pointer_internal_field; +using ::efl::eina::js::compatibility_set_pointer_internal_field; + +EAPI void register_ethumb(v8::Isolate *isolate, v8::Handle<v8::Object> exports); + +} } } // namespace efl { namespace ethumb { namespace js { + +#endif /* ETHUMB_JS_INIT_HH */ diff --git a/src/bindings/js/ethumb_js/ethumb_js_client.cc b/src/bindings/js/ethumb_js/ethumb_js_client.cc new file mode 100644 index 0000000000..50aaee39a4 --- /dev/null +++ b/src/bindings/js/ethumb_js/ethumb_js_client.cc @@ -0,0 +1,571 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Ethumb_Js.hh> + +namespace efl { namespace ethumb { namespace js { + +namespace { + +Ethumb_Exists* extract_ethumb_exists(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field<Ethumb_Exists*>(object, 0); +} + +efl::eina::js::global_ref<v8::Value>* +extract_ethumb_exists_cb(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field + <efl::eina::js::global_ref<v8::Value>*>(object, 1); +} + +v8::Local<v8::Object> wrap_ethumb_exists(Ethumb_Exists *exists, + efl::eina::js::global_ref<v8::Value>* + cb, + v8::Isolate *isolate) +{ + using v8::String; + using v8::Boolean; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(2); + auto ret = obj_tpl->NewInstance(); + + auto cancel = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto exists = extract_ethumb_exists(info.This()); + auto cb = extract_ethumb_exists_cb(info.This()); + + if (ethumb_client_thumb_exists_check(exists)) + return compatibility_return(); + + delete cb; + + ethumb_client_thumb_exists_cancel(exists); + return compatibility_return(); + }; + + auto check = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + auto exists = extract_ethumb_exists(info.This()); + + auto ret = ethumb_client_thumb_exists_check(exists); + + return compatibility_return(compatibility_new<Boolean>(isolate, ret), + info); + }; + + ret->Set(compatibility_new<String>(isolate, "cancel"), + compatibility_new<FunctionTemplate>(isolate, cancel) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "check"), + compatibility_new<FunctionTemplate>(isolate, check) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, exists); + compatibility_set_pointer_internal_field(ret, 1, cb); + + return ret; +} + +// ==================================================== + +Ethumb_Client_Async* extract_ethumb_client_async(v8::Local<v8::Object> o) +{ + return compatibility_get_pointer_internal_field<Ethumb_Client_Async*>(o, 0); +} + +efl::eina::js::global_ref<v8::Value>* +extract_ethumb_client_async_cb(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field + <efl::eina::js::global_ref<v8::Value>*>(object, 1); +} + +Ethumb_Client* extract_ethumb_client_async_client(v8::Local<v8::Object> o) +{ + return compatibility_get_pointer_internal_field<Ethumb_Client*>(o, 0); +} + +v8::Local<v8::Object> +wrap_ethumb_client_async(Ethumb_Client_Async *request, + efl::eina::js::global_ref<v8::Value>* cb, + Ethumb_Client *client, + v8::Isolate *isolate) +{ + using v8::String; + using v8::Boolean; + using v8::ObjectTemplate; + using v8::FunctionTemplate; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(3); + auto ret = obj_tpl->NewInstance(); + + auto cancel = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto request = extract_ethumb_client_async(info.This()); + auto cb = extract_ethumb_client_async_cb(info.This()); + auto client = extract_ethumb_client_async_client(info.This()); + + delete cb; + + ethumb_client_thumb_async_cancel(client, request); + return compatibility_return(); + }; + + ret->Set(compatibility_new<String>(isolate, "cancel"), + compatibility_new<FunctionTemplate>(isolate, cancel) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, request); + compatibility_set_pointer_internal_field(ret, 1, cb); + compatibility_set_pointer_internal_field(ret, 2, client); + + return ret; +} + +Ethumb_Client* extract_ethumb_client(v8::Local<v8::Object> object) +{ + return compatibility_get_pointer_internal_field<Ethumb_Client*>(object, 0); +} + +v8::Local<v8::Object> wrap_ethumb_client(Ethumb_Client *client, + v8::Isolate *isolate) +{ + using v8::Integer; + using v8::String; + using v8::Boolean; + using v8::Value; + using v8::Object; + using v8::ObjectTemplate; + using v8::Handle; + using v8::Function; + using v8::FunctionTemplate; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto obj_tpl = compatibility_new<ObjectTemplate>(isolate); + obj_tpl->SetInternalFieldCount(1); + auto ret = obj_tpl->NewInstance(); + + auto disconnect = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ethumb_client_disconnect(extract_ethumb_client(info.This())); + return compatibility_return(); + }; + + auto on_server_die_callback_set = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 1 || !info[0]->IsFunction()) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + + unique_ptr<persistent_t> cb_data{new persistent_t(isolate, info[0])}; + + auto client = extract_ethumb_client(info.This()); + auto server_die_cb = [](void *data, Ethumb_Client *client) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args{wrap_ethumb_client(client, isolate)}; + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + }; + auto free_data = [](void *data) { + auto persistent = reinterpret_cast<persistent_t*>(data); + delete persistent; + }; + + ethumb_client_on_server_die_callback_set(client, server_die_cb, + cb_data.release(), free_data); + return compatibility_return(); + }; + + auto file_set = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 2 || !info[0]->IsString() || !info[1]->IsString()) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + + auto ret = ethumb_client_file_set(extract_ethumb_client(info.This()), + *String::Utf8Value(info[0]), + *String::Utf8Value(info[1])); + return compatibility_return(compatibility_new<Boolean>(isolate, ret), + info); + }; + + auto file_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + + auto ret = compatibility_new<Object>(isolate); + const char *path; + const char *key; + + ethumb_client_file_get(extract_ethumb_client(info.This()), &path, &key); + + ret->Set(compatibility_new<String>(isolate, "path"), + compatibility_new<String>(isolate, path)); + ret->Set(compatibility_new<String>(isolate, "key"), + compatibility_new<String>(isolate, key)); + + return compatibility_return(ret, info); + }; + + auto file_free = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 0) + return compatibility_return(); + + ethumb_client_file_free(extract_ethumb_client(info.This())); + + return compatibility_return(); + }; + + auto thumb_exists = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 1 || !info[0]->IsFunction()) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + + unique_ptr<persistent_t> cb_data{new persistent_t(isolate, info[0])}; + + auto client = extract_ethumb_client(info.This()); + auto exists_cb = [](void *data, Ethumb_Client *client, + Ethumb_Exists *thread, Eina_Bool exists) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[3] = { + wrap_ethumb_client(client, isolate), + wrap_ethumb_exists(thread, NULL, isolate), + compatibility_new<Boolean>(isolate, exists) + }; + + Function::Cast(*o)->Call(o->ToObject(), 3, args); + + delete persistent; + }; + + auto ret = ethumb_client_thumb_exists(client, exists_cb, + cb_data.get()); + return compatibility_return(wrap_ethumb_exists(ret, cb_data.release(), + isolate), + info); + }; + + auto generate = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 1 || !info[0]->IsFunction()) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + + unique_ptr<persistent_t> cb_data{new persistent_t(isolate, info[0])}; + + auto client = extract_ethumb_client(info.This()); + auto generated_cb = [](void *data, Ethumb_Client *client, int id, + const char *file, const char *key, + const char *thumb_path, const char *thumb_key, + Eina_Bool success) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[7] = { + wrap_ethumb_client(client, isolate), + compatibility_new<Integer>(isolate, id), + compatibility_new<String>(isolate, file), + compatibility_new<String>(isolate, key), + compatibility_new<String>(isolate, thumb_path), + compatibility_new<String>(isolate, thumb_key), + compatibility_new<Boolean>(isolate, success) + }; + + Function::Cast(*o)->Call(o->ToObject(), 7, args); + }; + auto free_data = [](void *data) { + auto persistent = reinterpret_cast<persistent_t*>(data); + delete persistent; + }; + + auto ret = ethumb_client_generate(client, generated_cb, + cb_data.release(), free_data); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + info); + }; + + auto generate_cancel = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 2 || !info[0]->IsNumber() + || !info[1]->IsFunction()) { + return compatibility_return(); + } + + auto isolate = info.GetIsolate(); + + unique_ptr<persistent_t> cb_data{new persistent_t(isolate, info[1])}; + + auto client = extract_ethumb_client(info.This()); + auto cancel_cb = [](void *data, Eina_Bool success) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args{compatibility_new<Boolean>(isolate, success)}; + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + }; + auto free_data = [](void *data) { + auto persistent = reinterpret_cast<persistent_t*>(data); + delete persistent; + }; + + ethumb_client_generate_cancel(client, info[0]->IntegerValue(), + cancel_cb, cb_data.release(), free_data); + return compatibility_return(); + }; + + auto generate_cancel_all = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 1 || !info[0]->IsFunction()) + return compatibility_return(); + + auto client = extract_ethumb_client(info.This()); + + ethumb_client_generate_cancel_all(client); + return compatibility_return(); + }; + + auto thumb_async_get = [](compatibility_callback_info_type info) + -> compatibility_return_type { + if (info.Length() != 1 || !info[0]->IsFunction()) + return compatibility_return(); + + auto isolate = info.GetIsolate(); + + unique_ptr<persistent_t> cb_data{new persistent_t(isolate, info[0])}; + + auto client = extract_ethumb_client(info.This()); + auto done_cb = [](Ethumb_Client *client, const char *thumb_path, + const char *thumb_key, void *data) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[3] = { + wrap_ethumb_client(client, isolate), + compatibility_new<String>(isolate, thumb_path), + compatibility_new<String>(isolate, thumb_key) + }; + + Function::Cast(*o)->Call(o->ToObject(), 3, args); + + delete persistent; + }; + auto error_cb = [](Ethumb_Client *client, void *data) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args{wrap_ethumb_client(client, isolate)}; + + Function::Cast(*o)->Call(o->ToObject(), 1, &args); + + delete persistent; + }; + + auto ret = ethumb_client_thumb_async_get(client, done_cb, error_cb, + cb_data.get()); + auto wrapped_ret = wrap_ethumb_client_async(ret, cb_data.release(), + client, isolate); + return compatibility_return(wrapped_ret, info); + }; + + ret->Set(compatibility_new<String>(isolate, "disconnect"), + compatibility_new<FunctionTemplate>(isolate, disconnect) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "on_server_die_callback_set"), + compatibility_new<FunctionTemplate>(isolate, + on_server_die_callback_set) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "file_set"), + compatibility_new<FunctionTemplate>(isolate, file_set) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "file_get"), + compatibility_new<FunctionTemplate>(isolate, file_get) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "file_free"), + compatibility_new<FunctionTemplate>(isolate, file_free) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "thumb_exists"), + compatibility_new<FunctionTemplate>(isolate, thumb_exists) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "generate"), + compatibility_new<FunctionTemplate>(isolate, generate) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "generate_cancel"), + compatibility_new<FunctionTemplate>(isolate, generate_cancel) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "generate_cancel_all"), + compatibility_new<FunctionTemplate>(isolate, generate_cancel_all) + ->GetFunction()); + ret->Set(compatibility_new<String>(isolate, "thumb_async_get"), + compatibility_new<FunctionTemplate>(isolate, thumb_async_get) + ->GetFunction()); + + compatibility_set_pointer_internal_field(ret, 0, client); + + return ret; +} + +EAPI +void register_client_init(v8::Isolate *isolate, v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto init = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ethumb_client_init(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, init) + ->GetFunction()); +} + +EAPI +void register_client_shutdown(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::FunctionTemplate; + + auto shutdown = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 0) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + auto ret = ethumb_client_shutdown(); + return compatibility_return(compatibility_new<Integer>(isolate, ret), + args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, shutdown) + ->GetFunction()); +} + +EAPI +void register_client_connect(v8::Isolate *isolate, + v8::Handle<v8::Object> global, + v8::Handle<v8::String> name) +{ + using v8::Integer; + using v8::Boolean; + using v8::Value; + using v8::FunctionTemplate; + using v8::Function; + using v8::Handle; + using std::unique_ptr; + + typedef efl::eina::js::global_ref<Value> persistent_t; + + auto shutdown = [](compatibility_callback_info_type args) + -> compatibility_return_type { + if (args.Length() != 1 || !args[0]->IsFunction()) + return compatibility_return(); + + auto isolate = args.GetIsolate(); + + unique_ptr<persistent_t> cb_data{new persistent_t(isolate, args[0])}; + + auto connect_cb = [](void *data, Ethumb_Client *client, + Eina_Bool success) { + auto persistent = reinterpret_cast<persistent_t*>(data); + auto o = persistent->handle(); + + auto isolate = v8::Isolate::GetCurrent(); + + Handle<Value> args[2] = { + wrap_ethumb_client(client, isolate), + compatibility_new<Boolean>(isolate, success) + }; + + Function::Cast(*o)->Call(o->ToObject(), 2, args); + }; + auto free_data = [](void *data) { + auto persistent = reinterpret_cast<persistent_t*>(data); + delete persistent; + }; + + auto ret = ethumb_client_connect(connect_cb, cb_data.release(), + free_data); + return compatibility_return(wrap_ethumb_client(ret, isolate), args); + }; + + global->Set(name, + compatibility_new<FunctionTemplate>(isolate, shutdown) + ->GetFunction()); +} + +} + +EAPI +void register_ethumb(v8::Isolate *isolate, v8::Handle<v8::Object> exports) +{ + using v8::String; + register_client_init(isolate, exports, + compatibility_new<String>(isolate, + "ethumb_client_init")); + register_client_shutdown(isolate, exports, + compatibility_new<String>(isolate, + "ethumb_client_shutdown")); + register_client_connect(isolate, exports, + compatibility_new<String>(isolate, + "ethumb_client_connect")); +} + +} } } // namespace efl { namespace ethumb { namespace js { diff --git a/src/lib/ecore/ecore.c b/src/lib/ecore/ecore.c index e5a4c4c88f..88d7c356ca 100644 --- a/src/lib/ecore/ecore.c +++ b/src/lib/ecore/ecore.c @@ -909,7 +909,6 @@ _ecore_memory_statistic(EINA_UNUSED void *data) #endif #ifdef HAVE_MALLOC_INFO if (frame) fputs("\n", _ecore_memory_statistic_file); - fprintf(_ecore_memory_statistic_file, "=== Frame %i ===\n\n", frame++); malloc_info(0, _ecore_memory_statistic_file); #endif diff --git a/src/lib/ecore/ecore_main.c b/src/lib/ecore/ecore_main.c index ebd66eb2e1..f7e6a8a874 100644 --- a/src/lib/ecore/ecore_main.c +++ b/src/lib/ecore/ecore_main.c @@ -61,7 +61,7 @@ #include "Ecore.h" #include "ecore_private.h" -#ifdef HAVE_SYS_EPOLL_H +#if defined(HAVE_SYS_EPOLL_H) && !defined(HAVE_LIBUV) # define HAVE_EPOLL 1 # include <sys/epoll.h> #else @@ -157,6 +157,51 @@ timerfd_settime(int fd EINA_UNUSED, # include <glib.h> #endif +#ifdef HAVE_LIBUV +#ifdef HAVE_NODE_UV_H +#include <node/uv.h> +#elif defined(HAVE_NODEJS_DEPS_UV_UV_H) +#include <nodejs/deps/uv/uv.h> +#elif defined(HAVE_NODEJS_DEPS_UV_INCLUDE_UV_H) +#include <nodejs/deps/uv/include/uv.h> +#elif defined(HAVE_NODEJS_SRC_UV_H) +#include <nodejs/src/uv.h> +#elif defined(HAVE_UV_H) +#include <uv.h> +#else +#error No uv.h header found? +#endif + +#include <dlfcn.h> + +static uv_prepare_t _ecore_main_uv_prepare; +static uv_check_t _ecore_main_uv_check; +static uv_timer_t _ecore_main_uv_handle_timers; +static Eina_Bool _ecore_main_uv_idling; + +static int (*_dl_uv_loop_alive)(uv_loop_t*) = 0; +static int (*_dl_uv_run)(uv_loop_t*, uv_run_mode mode) = 0; +static int (*_dl_uv_stop)(uv_loop_t*) = 0; +static uv_loop_t* (*_dl_uv_default_loop)() = 0; +static int (*_dl_uv_poll_init_socket)(uv_loop_t* loop, uv_poll_t* handle, uv_os_sock_t fd) = 0; +static int (*_dl_uv_poll_init)(uv_loop_t* loop, uv_poll_t* handle, int fd) = 0; +static int (*_dl_uv_poll_start)(uv_poll_t* handle, int events, uv_poll_cb cb) = 0; +static int (*_dl_uv_poll_stop)(uv_poll_t* handle) = 0; +static int (*_dl_uv_timer_init)(uv_loop_t*, uv_timer_t* handle); +static int (*_dl_uv_timer_start)(uv_timer_t* handle, + uv_timer_cb cb, + uint64_t timeout, + uint64_t repeat); +static int (*_dl_uv_timer_stop)(uv_timer_t* handle); +static int (*_dl_uv_prepare_init)(uv_loop_t*, uv_prepare_t* prepare); +static int (*_dl_uv_prepare_start)(uv_prepare_t* prepare, uv_prepare_cb cb); +static int (*_dl_uv_prepare_stop)(uv_prepare_t* prepare); +static int (*_dl_uv_check_init)(uv_loop_t*, uv_check_t* prepare); +static int (*_dl_uv_check_start)(uv_check_t* prepare, uv_check_cb cb); +static int (*_dl_uv_check_stop)(uv_check_t* prepare); +static int (*_dl_uv_close)(uv_handle_t* handle, uv_close_cb close_cb); +#endif + #define NS_PER_SEC (1000.0 * 1000.0 * 1000.0) struct _Ecore_Fd_Handler @@ -181,6 +226,9 @@ struct _Ecore_Fd_Handler #if defined(USE_G_MAIN_LOOP) GPollFD gfd; #endif +#ifdef HAVE_LIBUV + uv_poll_t uv_handle; +#endif }; GENERIC_ALLOC_SIZE_DECLARE(Ecore_Fd_Handler); @@ -198,7 +246,7 @@ struct _Ecore_Win32_Handler GENERIC_ALLOC_SIZE_DECLARE(Ecore_Win32_Handler); #endif -#ifndef USE_G_MAIN_LOOP +#if !defined(USE_G_MAIN_LOOP) && !defined(HAVE_LIBUV) static int _ecore_main_select(double timeout); #endif static void _ecore_main_prepare_handlers(void); @@ -310,9 +358,13 @@ _ecore_try_add_to_call_list(Ecore_Fd_Handler *fdh) { /* check if this fdh is already in the list */ if (fdh->next_ready) - return; + { + DBG("next_ready"); + return; + } if (fdh->read_active || fdh->write_active || fdh->error_active) { + DBG("added"); /* * make sure next_ready is non-null by pointing to ourselves * use that to indicate this fdh is in the ready list @@ -344,6 +396,7 @@ _ecore_epoll_add(int efd, int events, void *ptr) { + struct epoll_event ev; memset(&ev, 0, sizeof (ev)); @@ -375,97 +428,197 @@ _gfd_events_from_fdh(Ecore_Fd_Handler *fdh) } #endif +#ifdef HAVE_LIBUV +static void +_ecore_main_uv_poll_cb(uv_poll_t* handle, int status, int events) +{ + DBG("_ecore_main_uv_poll_cb %p status %d events %d", (void*)handle->data, status, events); + Ecore_Fd_Handler* fdh = handle->data; + + if(_ecore_main_uv_idling) + { + DBG("not IDLE anymore"); + _ecore_main_uv_idling = EINA_FALSE; + _ecore_idle_exiter_call(); + _ecore_animator_run_reset(); + } + + if (status) + fdh->error_active = EINA_TRUE; + if (events & UV_READABLE) + fdh->read_active = EINA_TRUE; + if (events & UV_WRITABLE) + fdh->write_active = EINA_TRUE; + + _ecore_try_add_to_call_list(fdh); + + _ecore_main_fd_handlers_call(); + if (fd_handlers_with_buffer) + _ecore_main_fd_handlers_buf_call(); + _ecore_signal_received_process(); + _ecore_event_call(); + _ecore_main_fd_handlers_cleanup(); + _ecore_timer_expired_timers_call(_ecore_time_loop_time); + _ecore_timer_cleanup(); +} + +static int +_ecore_main_uv_events_from_fdh(Ecore_Fd_Handler *fdh) +{ + int events = 0; + if (fdh->flags & ECORE_FD_READ) events |= UV_READABLE; + if (fdh->flags & ECORE_FD_WRITE) events |= UV_WRITABLE; + DBG("events is %d", (int)events); + return events; +} +#endif + static inline int _ecore_main_fdh_poll_add(Ecore_Fd_Handler *fdh) { + DBG("_ecore_main_fdh_poll_add"); int r = 0; - if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0) +#ifdef HAVE_LIBUV + if(!_dl_uv_run) +#endif { - r = _ecore_epoll_add(_ecore_get_epoll_fd(), fdh->fd, - _ecore_poll_events_from_fdh(fdh), fdh); + if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0) + { + r = _ecore_epoll_add(_ecore_get_epoll_fd(), fdh->fd, + _ecore_poll_events_from_fdh(fdh), fdh); + } } -#ifdef USE_G_MAIN_LOOP +#ifdef HAVE_LIBUV else +#endif { +#ifdef HAVE_LIBUV + if(!fdh->file) + { + DBG("_ecore_main_fdh_poll_add libuv socket %p", fdh); + fdh->uv_handle.data = fdh; + DBG("_ecore_main_fdh_poll_add2 %p", fdh); + _dl_uv_poll_init_socket(_dl_uv_default_loop(), &fdh->uv_handle, fdh->fd); + DBG("_ecore_main_fdh_poll_add3 %p", fdh->uv_handle.data); + _dl_uv_poll_start(&fdh->uv_handle, _ecore_main_uv_events_from_fdh(fdh) + , _ecore_main_uv_poll_cb); + DBG("_ecore_main_fdh_poll_add libuv DONE"); + } + else + { + DBG("_ecore_main_fdh_poll_add libuv file"); + fdh->uv_handle.data = fdh; + DBG("_ecore_main_fdh_poll_add2 %p", fdh); + _dl_uv_poll_init(_dl_uv_default_loop(), &fdh->uv_handle, fdh->fd); + DBG("_ecore_main_fdh_poll_add3 %p", fdh->uv_handle.data); + _dl_uv_poll_start(&fdh->uv_handle, _ecore_main_uv_events_from_fdh(fdh) + , _ecore_main_uv_poll_cb); + DBG("_ecore_main_fdh_poll_add libuv DONE"); + } +#elif defined(USE_G_MAIN_LOOP) fdh->gfd.fd = fdh->fd; fdh->gfd.events = _gfd_events_from_fdh(fdh); fdh->gfd.revents = 0; DBG("adding gpoll on %d %08x", fdh->fd, fdh->gfd.events); g_source_add_poll(ecore_glib_source, &fdh->gfd); - } #endif + } return r; } static inline void _ecore_main_fdh_poll_del(Ecore_Fd_Handler *fdh) { - if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0) +#ifdef HAVE_LIBUV + if(!_dl_uv_run) +#endif { - struct epoll_event ev; - int efd = _ecore_get_epoll_fd(); - - memset(&ev, 0, sizeof (ev)); - DBG("removing poll on %d", fdh->fd); - /* could get an EBADF if somebody closed the FD before removing it */ - if ((epoll_ctl(efd, EPOLL_CTL_DEL, fdh->fd, &ev) < 0)) - { - if (errno == EBADF) - { - WRN("fd %d was closed, can't remove from epoll - reinit!", - fdh->fd); - _ecore_main_loop_shutdown(); - _ecore_main_loop_init(); - } - else - { - ERR("Failed to delete epoll fd %d! (errno=%d)", fdh->fd, errno); - } - } - } -#ifdef USE_G_MAIN_LOOP + if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0) + { + struct epoll_event ev; + int efd = _ecore_get_epoll_fd(); + + memset(&ev, 0, sizeof (ev)); + DBG("removing poll on %d", fdh->fd); + /* could get an EBADF if somebody closed the FD before removing it */ + if ((epoll_ctl(efd, EPOLL_CTL_DEL, fdh->fd, &ev) < 0)) + { + if (errno == EBADF) + { + WRN("fd %d was closed, can't remove from epoll - reinit!", + fdh->fd); + _ecore_main_loop_shutdown(); + _ecore_main_loop_init(); + } + else + { + ERR("Failed to delete epoll fd %d! (errno=%d)", fdh->fd, errno); + } + } + } + } +#ifdef HAVE_LIBUV else +#endif { +#ifdef HAVE_LIBUV + DBG("_ecore_main_fdh_poll_del libuv %p", fdh); + uv_handle_t* h = (uv_handle_t*)&fdh->uv_handle; + _dl_uv_close(h, 0); + DBG("_ecore_main_fdh_poll_del libuv DONE"); +#elif USE_G_MAIN_LOOP fdh->gfd.fd = fdh->fd; fdh->gfd.events = _gfd_events_from_fdh(fdh); fdh->gfd.revents = 0; DBG("removing gpoll on %d %08x", fdh->fd, fdh->gfd.events); g_source_remove_poll(ecore_glib_source, &fdh->gfd); - } #endif + } } static inline int _ecore_main_fdh_poll_modify(Ecore_Fd_Handler *fdh) { + DBG("_ecore_main_fdh_poll_modify %p", fdh); int r = 0; - if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0) +#ifdef HAVE_LIBUV + if(!_dl_uv_run) +#endif { - struct epoll_event ev; - int efd = _ecore_get_epoll_fd(); + if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0) + { + struct epoll_event ev; + int efd = _ecore_get_epoll_fd(); - memset(&ev, 0, sizeof (ev)); - ev.events = _ecore_poll_events_from_fdh(fdh); - ev.data.ptr = fdh; - DBG("modifing epoll on %d to %08x", fdh->fd, ev.events); - r = epoll_ctl(efd, EPOLL_CTL_MOD, fdh->fd, &ev); + memset(&ev, 0, sizeof (ev)); + ev.events = _ecore_poll_events_from_fdh(fdh); + ev.data.ptr = fdh; + DBG("modifing epoll on %d to %08x", fdh->fd, ev.events); + r = epoll_ctl(efd, EPOLL_CTL_MOD, fdh->fd, &ev); + } } -#ifdef USE_G_MAIN_LOOP +#ifdef HAVE_LIBUV else +#endif { +#ifdef HAVE_LIBUV + _dl_uv_poll_start(&fdh->uv_handle, _ecore_main_uv_events_from_fdh(fdh) + , _ecore_main_uv_poll_cb); +#elif defined(USE_G_MAIN_LOOP) fdh->gfd.fd = fdh->fd; fdh->gfd.events = _gfd_events_from_fdh(fdh); fdh->gfd.revents = 0; DBG("modifing gpoll on %d to %08x", fdh->fd, fdh->gfd.events); - } #endif + } return r; } static inline int _ecore_main_fdh_epoll_mark_active(void) { + DBG("_ecore_main_fdh_epoll_mark_active"); struct epoll_event ev[32]; int i, ret; int efd = _ecore_get_epoll_fd(); @@ -832,9 +985,62 @@ detect_time_changes_stop(void) #endif } + +#ifdef HAVE_LIBUV +static inline +void +_ecore_main_loop_uv_check(uv_check_t* handle EINA_UNUSED); +static void _ecore_main_loop_uv_prepare(uv_prepare_t* handle); + +static +void _ecore_main_loop_timer_run(uv_timer_t* timer EINA_UNUSED) +{ + if(_ecore_main_uv_idling) + { + _ecore_main_uv_idling = EINA_FALSE; + _ecore_idle_exiter_call(); + _ecore_animator_run_reset(); + } + _ecore_time_loop_time = ecore_time_get(); + _ecore_main_loop_uv_check(NULL); + + _ecore_main_loop_uv_prepare(NULL); +} +static void _ecore_main_loop_uv_prepare(uv_prepare_t* handle); + +static inline +void +_ecore_main_loop_uv_check(uv_check_t* handle EINA_UNUSED) +{ + DBG("_ecore_main_loop_uv_check idling? %d", (int)_ecore_main_uv_idling); + in_main_loop++; + _ecore_lock(); + + if(do_quit) + goto quit; + + do + { + _ecore_main_fd_handlers_call(); + if (fd_handlers_with_buffer) + _ecore_main_fd_handlers_buf_call(); + _ecore_signal_received_process(); + _ecore_event_call(); + _ecore_main_fd_handlers_cleanup(); + _ecore_timer_expired_timers_call(_ecore_time_loop_time); + _ecore_timer_cleanup(); + } + while(fd_handlers_to_call); +quit: + in_main_loop--; + _ecore_unlock(); +} +#endif + void _ecore_main_loop_init(void) { + DBG("_ecore_main_loop_init"); epoll_fd = epoll_create(1); if ((epoll_fd < 0) && HAVE_EPOLL) WRN("Failed to create epoll fd!"); @@ -851,7 +1057,77 @@ _ecore_main_loop_init(void) _ecore_poll_events_from_fdh(fdh), fdh); _ecore_main_fdh_poll_add(fdh); } +#ifdef HAVE_LIBUV + { + DBG("loading lib uv"); +#ifdef HAVE_NODEJS + void* lib = dlopen(NULL, RTLD_LAZY); +#else + void* lib = dlopen("libuv.so", RTLD_GLOBAL | RTLD_LAZY); +#endif + if(lib && dlsym(lib, "uv_run")) + { + DBG("loaded lib uv"); + _dl_uv_run = dlsym(lib, "uv_run"); + assert(!!_dl_uv_run); + _dl_uv_stop = dlsym(lib, "uv_stop"); + assert(!!_dl_uv_stop); + _dl_uv_default_loop = dlsym(lib, "uv_default_loop"); + assert(!!_dl_uv_default_loop); + _dl_uv_poll_init_socket = dlsym(lib, "uv_poll_init_socket"); + assert(!!_dl_uv_poll_init_socket); + _dl_uv_poll_init = dlsym(lib, "uv_poll_init"); + assert(!!_dl_uv_poll_init); + _dl_uv_poll_start = dlsym(lib, "uv_poll_start"); + assert(!!_dl_uv_poll_start); + _dl_uv_poll_stop = dlsym(lib, "uv_poll_stop"); + assert(!!_dl_uv_poll_stop); + _dl_uv_timer_init = dlsym(lib, "uv_timer_init"); + assert(!!_dl_uv_timer_init); + _dl_uv_timer_start = dlsym(lib, "uv_timer_start"); + assert(!!_dl_uv_timer_start); + _dl_uv_timer_stop = dlsym(lib, "uv_timer_stop"); + assert(!!_dl_uv_timer_stop); + _dl_uv_prepare_init = dlsym(lib, "uv_prepare_init"); + assert(!!_dl_uv_prepare_init); + _dl_uv_prepare_start = dlsym(lib, "uv_prepare_start"); + assert(!!_dl_uv_prepare_start); + _dl_uv_prepare_stop = dlsym(lib, "uv_prepare_stop"); + assert(!!_dl_uv_prepare_stop); + _dl_uv_check_init = dlsym(lib, "uv_check_init"); + assert(!!_dl_uv_check_init); + _dl_uv_check_start = dlsym(lib, "uv_check_start"); + assert(!!_dl_uv_check_start); + _dl_uv_check_stop = dlsym(lib, "uv_check_stop"); + assert(!!_dl_uv_check_stop); + _dl_uv_close = dlsym(lib, "uv_close"); + assert(!!_dl_uv_close); + _dl_uv_loop_alive = dlsym(lib, "uv_loop_alive"); + assert(!!_dl_uv_loop_alive); + + //dlclose(lib); + + DBG("_dl_uv_prepare_init"); + _dl_uv_prepare_init(_dl_uv_default_loop(), &_ecore_main_uv_prepare); + DBG("_dl_uv_prepare_start"); + _dl_uv_prepare_start(&_ecore_main_uv_prepare, &_ecore_main_loop_uv_prepare); + DBG("_dl_uv_prepare_started"); + + DBG("_dl_uv_check_init"); + _dl_uv_check_init(_dl_uv_default_loop(), &_ecore_main_uv_check); + DBG("_dl_uv_check_start"); + _dl_uv_check_start(&_ecore_main_uv_check, &_ecore_main_loop_uv_check); + DBG("_dl_uv_check_started"); + + _dl_uv_timer_init(_dl_uv_default_loop(), &_ecore_main_uv_handle_timers); + } + /* else */ + /* DBG("did not load uv"); */ + DBG("loaded dlsyms uv"); + } +#endif + /* setup for the g_main_loop only integration */ #ifdef USE_G_MAIN_LOOP ecore_glib_source = g_source_new(&ecore_gsource_funcs, sizeof (GSource)); @@ -916,11 +1192,21 @@ _ecore_main_loop_shutdown(void) close(timer_fd); timer_fd = -1; } + +#ifdef HAVE_LIBUV + if(_dl_uv_run) + { + DBG("_ecore_main_loop_shutdown"); + _dl_uv_timer_stop(&_ecore_main_uv_handle_timers); + _dl_uv_close((uv_handle_t*)&_ecore_main_uv_handle_timers, 0); + } +#endif } void * _ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler) { + DBG("_ecore_main_fd_handler_del %p", fd_handler); if (fd_handler->delete_me) { ERR("fdh %p deleted twice", fd_handler); @@ -941,6 +1227,9 @@ EAPI void ecore_main_loop_iterate(void) { EINA_MAIN_LOOP_CHECK_RETURN; +#ifdef HAVE_LIBUV + if(!_dl_uv_run) { +#endif #ifndef USE_G_MAIN_LOOP _ecore_lock(); _ecore_time_loop_time = ecore_time_get(); @@ -949,12 +1238,20 @@ ecore_main_loop_iterate(void) #else g_main_context_iteration(NULL, 0); #endif +#ifdef HAVE_LIBUV + } + else + _dl_uv_run(_dl_uv_default_loop(), UV_RUN_ONCE | UV_RUN_NOWAIT); +#endif } EAPI int ecore_main_loop_iterate_may_block(int may_block) { EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); +#ifdef HAVE_LIBUV + if(!_dl_uv_run) { +#endif #ifndef USE_G_MAIN_LOOP _ecore_lock(); _ecore_time_loop_time = ecore_time_get(); @@ -966,11 +1263,18 @@ in_main_loop--; #else return g_main_context_iteration(NULL, may_block); #endif +#ifdef HAVE_LIBUV + } + else + _dl_uv_run(_dl_uv_default_loop(), may_block ? UV_RUN_ONCE | UV_RUN_NOWAIT : UV_RUN_ONCE); +#endif + return 0; } EAPI void ecore_main_loop_begin(void) { + DBG("ecore_main_loop_begin"); EINA_MAIN_LOOP_CHECK_RETURN; if (in_main_loop > 0) { @@ -981,6 +1285,9 @@ ecore_main_loop_begin(void) #ifdef HAVE_SYSTEMD sd_notify(0, "READY=1"); #endif +#ifdef HAVE_LIBUV + if(!_dl_uv_run) { +#endif #ifndef USE_G_MAIN_LOOP _ecore_lock(); in_main_loop++; @@ -998,6 +1305,20 @@ ecore_main_loop_begin(void) } do_quit = 0; #endif +#ifdef HAVE_LIBUV + } + else + { + DBG("uv_run"); + _ecore_time_loop_time = ecore_time_get(); + in_main_loop++; + while(!do_quit) + _dl_uv_run(_dl_uv_default_loop(), UV_RUN_DEFAULT); + in_main_loop--; + do_quit = 0; + DBG("quit"); + } +#endif eina_evlog("-mainloop", NULL, 0.0, NULL); } @@ -1009,6 +1330,9 @@ ecore_main_loop_quit(void) #ifdef USE_G_MAIN_LOOP if (ecore_main_loop) g_main_loop_quit(ecore_main_loop); +#elif defined(HAVE_LIBUV) + if (_dl_uv_run) + _dl_uv_stop(_dl_uv_default_loop()); #endif } @@ -1021,6 +1345,7 @@ ecore_main_loop_nested_get(void) EAPI Eina_Bool ecore_main_loop_animator_ticked_get(void) { + DBG("ecore_main_loop_animator_ticked_get"); return _ecore_animator_run_get(); } @@ -1047,6 +1372,7 @@ _ecore_main_fd_handler_add(int fd, const void *buf_data, Eina_Bool is_file) { + DBG("_ecore_main_fd_handler_add"); Ecore_Fd_Handler *fdh = NULL; if ((fd < 0) || (flags == 0) || (!func)) return NULL; @@ -1381,7 +1707,7 @@ _ecore_main_prepare_handlers(void) } } -#ifndef USE_G_MAIN_LOOP +#if !defined(USE_G_MAIN_LOOP) static int _ecore_main_select(double timeout) { @@ -1750,8 +2076,119 @@ _ecore_main_fd_handlers_buf_call(void) return ret; } -#ifndef USE_G_MAIN_LOOP +#ifdef HAVE_LIBUV +static void +_ecore_main_loop_uv_prepare(uv_prepare_t* handle EINA_UNUSED) +{ + _ecore_lock(); + _dl_uv_timer_stop(&_ecore_main_uv_handle_timers); + if(in_main_loop == 0 && do_quit) + { + _ecore_main_fd_handlers_cleanup(); + + while (fd_handlers) + { + Ecore_Fd_Handler *fdh; + + fdh = fd_handlers; + fd_handlers = (Ecore_Fd_Handler *)eina_inlist_remove(EINA_INLIST_GET(fd_handlers), + EINA_INLIST_GET(fdh)); + _ecore_main_fdh_poll_del(fdh); + ECORE_MAGIC_SET(fdh, ECORE_MAGIC_NONE); + ecore_fd_handler_mp_free(fdh); + } + if (fd_handlers_with_buffer) + fd_handlers_with_buffer = eina_list_free(fd_handlers_with_buffer); + if (fd_handlers_with_prep) + fd_handlers_with_prep = eina_list_free(fd_handlers_with_prep); + if (fd_handlers_to_delete) + fd_handlers_to_delete = eina_list_free(fd_handlers_to_delete); + if (file_fd_handlers) + file_fd_handlers = eina_list_free(file_fd_handlers); + + fd_handlers_to_call = NULL; + fd_handlers_to_call_current = NULL; + fd_handlers_to_delete = NULL; + fd_handler_current = NULL; + + _dl_uv_prepare_stop(&_ecore_main_uv_prepare); + _dl_uv_check_stop(&_ecore_main_uv_check); + _dl_uv_stop(_dl_uv_default_loop()); + + _ecore_unlock(); + return; + } + + in_main_loop++; + + if(!_ecore_main_uv_idling) + { + _ecore_main_uv_idling = EINA_TRUE; + _ecore_idle_enterer_call(); + _ecore_throttle(); + } + + double t = -1; + if(_ecore_main_uv_idling) + { + _ecore_idler_all_call(); + DBG("called idles"); + if(_ecore_idler_exist() || _ecore_event_exist()) + t = 0.0; + } + + if (do_quit) + { + DBG("do quit outside loop"); + + if(_ecore_main_uv_idling) + { + _ecore_idle_exiter_call(); + _ecore_animator_run_reset(); + + _ecore_main_uv_idling = EINA_FALSE; + } + + t = -1; + + _ecore_time_loop_time = ecore_time_get(); + _ecore_timer_enable_new(); + + goto done; + } + + assert(!fd_handlers_to_call); + + _ecore_time_loop_time = ecore_time_get(); + _ecore_timer_enable_new(); + if (_ecore_timers_exists() || t >= 0) + { + double t1 = _ecore_timer_next_get(); + if(t < 0 || (t1 >= 0 && t1 < t)) t = t1; + DBG("Should awake after %f", t); + + if (t >= 0.0) + { + //_dl_uv_timer_stop(&_ecore_main_uv_handle_timers); + _dl_uv_timer_start(&_ecore_main_uv_handle_timers, &_ecore_main_loop_timer_run, t * 1000 + , 0); + } + else + DBG("Is not going to awake with timer"); + } + else + DBG("Is not going to awake with timer"); + + done: + if (fd_handlers_with_prep) + _ecore_main_prepare_handlers(); + + _ecore_unlock(); + in_main_loop--; +} +#endif +#if !defined(USE_G_MAIN_LOOP) enum { SPIN_MORE, SPIN_RESTART, diff --git a/src/lib/ecore/ecore_private.h b/src/lib/ecore/ecore_private.h index a8676a242c..c59ecfaff7 100644 --- a/src/lib/ecore/ecore_private.h +++ b/src/lib/ecore/ecore_private.h @@ -450,7 +450,7 @@ GENERIC_ALLOC_FREE_HEADER(Ecore_Win32_Handler, ecore_win32_handler); extern Eo *_ecore_parent; #define ECORE_PARENT_CLASS ecore_parent_class_get() -const Eo_Class *ecore_parent_class_get(void) EINA_CONST; +EAPI const Eo_Class *ecore_parent_class_get(void) EINA_CONST; #undef EAPI #define EAPI diff --git a/src/lib/ecore_con/Ecore_Con_Eet.h b/src/lib/ecore_con/Ecore_Con_Eet.h index 4f1b7dfe75..0498d3c795 100644 --- a/src/lib/ecore_con/Ecore_Con_Eet.h +++ b/src/lib/ecore_con/Ecore_Con_Eet.h @@ -43,6 +43,10 @@ * @{ */ +#ifdef __cplusplus +extern "C" { +#endif + typedef Eo Ecore_Con_Eet; typedef struct _Ecore_Con_Reply Ecore_Con_Reply; @@ -300,4 +304,11 @@ EAPI void ecore_con_eet_raw_send(Ecore_Con_Reply *reply, const char *protocol_na * @} */ +#ifdef __cplusplus +} +#endif + +#undef EAPI +#define EAPI + #endif diff --git a/src/lib/efl/interfaces/efl_model_base.eo b/src/lib/efl/interfaces/efl_model_base.eo index 2dfa99aed5..494c131d16 100644 --- a/src/lib/efl/interfaces/efl_model_base.eo +++ b/src/lib/efl/interfaces/efl_model_base.eo @@ -58,7 +58,7 @@ interface Efl.Model.Base () return: Efl.Model.Load_Status; } values { - properties: const(array<const(char*)>*); [[array of current properties]] + properties: const(array<const(char)*>*); [[array of current properties]] } } @property property { diff --git a/src/lib/emotion/Emotion.h b/src/lib/emotion/Emotion.h index e2d7a7a704..3ea786391d 100644 --- a/src/lib/emotion/Emotion.h +++ b/src/lib/emotion/Emotion.h @@ -120,6 +120,10 @@ # endif #endif /* ! _WIN32 */ +#ifdef __cplusplus +extern "C" { +#endif + #ifndef EFL_NOLEGACY_API_SUPPORT #include "Emotion_Legacy.h" #endif @@ -266,26 +270,23 @@ typedef enum _Emotion_Aspect Emotion_Aspect; /**< Aspect ratio option. */ #define EMOTION_CHANNEL_AUTO -1 #define EMOTION_CHANNEL_DEFAULT 0 -#ifdef __cplusplus -extern "C" { -#endif - #define EMOTION_VERSION_MAJOR EFL_VERSION_MAJOR #define EMOTION_VERSION_MINOR EFL_VERSION_MINOR - /** - * @typedef Emotion_Version - * Represents the current version of Emotion - */ - typedef struct _Emotion_Version - { - int major; /** < major (binary or source incompatible changes) */ - int minor; /** < minor (new features, bugfixes, major improvements version) */ - int micro; /** < micro (bugfix, internal improvements, no new features version) */ - int revision; /** < git revision (0 if a proper release or the git revision number Emotion is built from) */ - } Emotion_Version; - - EAPI extern Emotion_Version *emotion_version; - + +/** + * @typedef Emotion_Version + * Represents the current version of Emotion + */ +typedef struct _Emotion_Version + { + int major; /** < major (binary or source incompatible changes) */ + int minor; /** < minor (new features, bugfixes, major improvements version) */ + int micro; /** < micro (bugfix, internal improvements, no new features version) */ + int revision; /** < git revision (0 if a proper release or the git revision number Emotion is built from) */ + } Emotion_Version; + +EAPI extern Emotion_Version *emotion_version; + /* api calls available */ /** @@ -873,7 +874,7 @@ EAPI Eina_Bool emotion_object_smooth_scale_get (const Evas_Object *obj); * @param obj The object target of the event. * @param ev The emotion event. * - * @see Emotion_Event + * @see Emotion_Event */ EAPI void emotion_object_event_simple_send (Evas_Object *obj, Emotion_Event ev); diff --git a/src/lib/emotion/emotion_smart.c b/src/lib/emotion/emotion_smart.c index ea1130e3fd..969780a172 100644 --- a/src/lib/emotion/emotion_smart.c +++ b/src/lib/emotion/emotion_smart.c @@ -1964,6 +1964,7 @@ _emotion_object_evas_object_smart_clip_unset(Evas_Object *obj EINA_UNUSED, Emoti if (sd->crop.clipper) evas_object_clip_unset(sd->crop.clipper); else evas_object_clip_unset(sd->obj); evas_object_clip_unset(sd->bg); + } #include "emotion_object.eo.c" diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h index fc450c22fd..ad70c0ca2f 100644 --- a/src/lib/eo/Eo.h +++ b/src/lib/eo/Eo.h @@ -535,15 +535,15 @@ typedef struct _Eo_Call_Cache } #ifndef _WIN32 -# define _EO_OP_API_ENTRY(a) a +# define _EO_OP_API_ENTRY(a) (void*)a #else # define _EO_OP_API_ENTRY(a) #a #endif -#define EO_OP_FUNC(_api, _private) { _EO_OP_API_ENTRY(_api), _private, EO_OP_TYPE_REGULAR } -#define EO_OP_CLASS_FUNC(_api, _private) { _EO_OP_API_ENTRY(_api), _private, EO_OP_TYPE_CLASS } -#define EO_OP_FUNC_OVERRIDE(_api, _private) { _EO_OP_API_ENTRY(_api), _private, EO_OP_TYPE_REGULAR_OVERRIDE } -#define EO_OP_CLASS_FUNC_OVERRIDE(_api, _private) { _EO_OP_API_ENTRY(_api), _private, EO_OP_TYPE_CLASS_OVERRIDE } +#define EO_OP_FUNC(_api, _private) { _EO_OP_API_ENTRY(_api), (void*)_private, EO_OP_TYPE_REGULAR } +#define EO_OP_CLASS_FUNC(_api, _private) { _EO_OP_API_ENTRY(_api), (void*)_private, EO_OP_TYPE_CLASS } +#define EO_OP_FUNC_OVERRIDE(_api, _private) { _EO_OP_API_ENTRY(_api), (void*)_private, EO_OP_TYPE_REGULAR_OVERRIDE } +#define EO_OP_CLASS_FUNC_OVERRIDE(_api, _private) { _EO_OP_API_ENTRY(_api), (void*)_private, EO_OP_TYPE_CLASS_OVERRIDE } // returns the OP id corresponding to the given api_func EAPI Eo_Op _eo_api_op_id_get(const void *api_func); diff --git a/src/tests/.gitignore b/src/tests/.gitignore index e69225df2e..741adfc01a 100644 --- a/src/tests/.gitignore +++ b/src/tests/.gitignore @@ -2,4 +2,5 @@ check-results.xml *_suite *_suite.log *_suite.trs +*.node */cxx_compile_test diff --git a/src/tests/ecore/ecore_test_ecore.c b/src/tests/ecore/ecore_test_ecore.c index a5331b49aa..968a7ec553 100644 --- a/src/tests/ecore/ecore_test_ecore.c +++ b/src/tests/ecore/ecore_test_ecore.c @@ -267,6 +267,39 @@ START_TEST(ecore_test_ecore_main_loop_fd_handler) } END_TEST +START_TEST(ecore_test_ecore_main_loop_fd_handler_activate_modify) +{ + Eina_Bool did = EINA_FALSE; + Ecore_Fd_Handler *fd_handler; + int comm[2]; + int ret; + + ret = ecore_init(); + fail_if(ret < 1); + + ret = pipe(comm); + fail_if(ret != 0); + + fd_handler = ecore_main_fd_handler_add + (comm[0], ECORE_FD_ERROR, _fd_handler_cb, &did, NULL, NULL); + fail_if(fd_handler == NULL); + + ecore_main_fd_handler_active_set(fd_handler, ECORE_FD_READ); + + ret = write(comm[1], "e", 1); + fail_if(ret != 1); + + ecore_main_loop_begin(); + + close(comm[0]); + close(comm[1]); + + fail_if(did != EINA_TRUE); + + ret = ecore_shutdown(); +} +END_TEST + static Eina_Bool _event_handler_cb(void *data, int type, void *event) { @@ -705,6 +738,7 @@ void ecore_test_ecore(TCase *tc) tcase_add_test(tc, ecore_test_ecore_main_loop_idle_exiter); tcase_add_test(tc, ecore_test_ecore_main_loop_timer); tcase_add_test(tc, ecore_test_ecore_main_loop_fd_handler); + tcase_add_test(tc, ecore_test_ecore_main_loop_fd_handler_activate_modify); tcase_add_test(tc, ecore_test_ecore_main_loop_event); tcase_add_test(tc, ecore_test_ecore_main_loop_timer_inner); tcase_add_test(tc, ecore_test_ecore_main_loop_event_recursive); diff --git a/src/tests/ecore/ecore_test_ecore_x.c b/src/tests/ecore/ecore_test_ecore_x.c index 18471fa962..8baa9a560f 100644 --- a/src/tests/ecore/ecore_test_ecore_x.c +++ b/src/tests/ecore/ecore_test_ecore_x.c @@ -2,10 +2,10 @@ # include <config.h> #endif -#include <Ecore_X.h> - #include "ecore_suite.h" +#include <Eina.h> + /* FIXME: Currently disable these tests. They are useless ATM and they just * make buildbot complain. Once we add useful tests here we'll also bother * with getting X on the server. */ @@ -14,6 +14,8 @@ /* TODO: change to HAVE_ECORE_X when xcb implementation is done */ #ifdef HAVE_ECORE_X_XLIB +#include <Ecore_X.h> + START_TEST(ecore_test_ecore_x_init) { int ret; diff --git a/src/tests/efl_js/benchmark_js_suite.cc b/src/tests/efl_js/benchmark_js_suite.cc new file mode 100644 index 0000000000..c7583f2b3e --- /dev/null +++ b/src/tests/efl_js/benchmark_js_suite.cc @@ -0,0 +1,7 @@ + +#include "suite_runner.hh" + +int main(int, char*[]) +{ + return run_script(TESTS_SRC_DIR "/ecore_js_suite.js", nullptr); +} diff --git a/src/tests/efl_js/benchmark_js_suite.js b/src/tests/efl_js/benchmark_js_suite.js new file mode 100755 index 0000000000..b3a5d7c86c --- /dev/null +++ b/src/tests/efl_js/benchmark_js_suite.js @@ -0,0 +1,205 @@ +#!/usr/bin/env node + +// Preamble +function assert(condition, message) { + if (!condition) { + print("Assertion failed ", message); + throw new Error(message || "Assertion failed"); + } +} + +if(typeof process !== 'undefined') +{ + console.log('running from nodejs'); + console.log('path', process.env.NODE_PATH); + + efl = require('efl'); + assert(efl != null, "could not load efl node module"); + + // Setup output aliases + print = console.log; + print_error = function() { + if (process.argv.indexOf("--supress-errors") == -1) + console.error.apply(null, arguments); + }; + print_info = function() { + if (process.argv.indexOf("--verbose") != -1) + console.info.apply(null, arguments); + }; + exit = efl.ecore_mainloop_quit; +} +else +{ + assert = function(test, message) { if (test !== true) throw message; }; + print('running from libv8') + //FIXME Add levels to v8 tests + print_error = print + print_info = print + exit = function() {} +} + +// Global flag for suite success // +suite_success = true; +// Global test summary +suite_ok = 0; +suite_fail = []; // Will store the name of the failures + +// Basic test function // +function start_test(test_name, test_func) { + print("[ RUN ] eina_js_suite: " + test_name); + var test_result = true; + try { + test_func(); + } catch (e) { + suite_success = false; + test_result = false; + print_error("Error: ", e, e.stack); + } + print("[ " + (test_result ? "PASS" : "FAIL") + " ] eina_js_suite: " + test_name); + if (test_result) + suite_ok += 1; + else + suite_fail.push(test_name); +} +// end Preamble +if (typeof process != "undefined") +{ + benchmark = require('benchmark_object'); + assert(benchmark != null, "could not load benchmark_object.node"); + Benchmark_Object = benchmark.BenchmarkObject; + benchmark_emptyarg = benchmark.benchmark_emptyarg; + benchmark_onearg = benchmark.benchmark_onearg; + benchmark_twoarg = benchmark.benchmark_twoarg; + benchmark_tenarg = benchmark.benchmark_tenarg; + benchmark_onecomplexarg = benchmark.benchmark_onecomplexarg; + benchmark_tencomplexarg = benchmark.benchmark_tencomplexarg; +} +else +{ + Benchmark_Object = suite.Benchmark_Object; +} + +start_test("empty function", function(){ + object = new Benchmark_Object(null); + + for(i = 0; i != 10; i++) + { + object.emptyarg(); + } + + time = process.hrtime(); + for(i = 0; i != 20000; i++) + { + object.emptyarg(); + } + time = process.hrtime(time); + console.log('JS empty function %d', time[0]*1000000000 + time[1]); + benchmark_emptyarg(); +}); + +start_test("onearg function", function(){ + object = new Benchmark_Object(null); + for(i = 0; i != 10; i++) + { + object.onearg(1); + } + + time = process.hrtime(); + for(i = 0; i != 20000; i++) + { + object.onearg(1); + } + time = process.hrtime(time); + console.log('JS onearg function %d', time[0]*1000000000 + time[1]); + + benchmark_onearg(); +}); + +start_test("twoarg function", function(){ + object = new Benchmark_Object(null); + for(i = 0; i != 10; i++) + { + object.twoarg(1, 2); + } + + time = process.hrtime(); + for(i = 0; i != 20000; i++) + { + object.twoarg(1, 2); + } + time = process.hrtime(time); + console.log('JS twoarg function %d', time[0]*1000000000 + time[1]); + + benchmark_twoarg(); +}); + +start_test("tenarg function", function(){ + object = new Benchmark_Object(null); + for(i = 0; i != 10; i++) + { + object.tenarg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + time = process.hrtime(); + for(i = 0; i != 20000; i++) + { + object.tenarg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + time = process.hrtime(time); + console.log('JS tenarg function %d', time[0]*1000000000 + time[1]); + benchmark_tenarg(); +}); + +start_test("onecomplexarg function", function(){ + object = new Benchmark_Object(null); + list = new efl.List('int') + for(i = 0; i != 10; i++) + { + object.onecomplexarg(list); + } + + time = process.hrtime(); + for(i = 0; i != 20000; i++) + { + object.onecomplexarg(list); + } + time = process.hrtime(time); + console.log('JS onecomplexarg function %d', time[0]*1000000000 + time[1]); + benchmark_onecomplexarg(); +}); + +start_test("tencomplexarg function", function(){ + object = new Benchmark_Object(null); + list = new efl.List('int') + for(i = 0; i != 10; i++) + { + object.tencomplexarg(list, list, list, list, list, list, list, list, list, list); + } + + time = process.hrtime(); + for(i = 0; i != 20000; i++) + { + object.tencomplexarg(list, list, list, list, list, list, list, list, list, list); + } + time = process.hrtime(time); + console.log('JS tencomplexarg function %d', time[0]*1000000000 + time[1]); + benchmark_tencomplexarg(); +}); + +// footer + +if (!suite_success) { + print ("[ Total tests run: %s ]", suite_ok + suite_fail.length); + print ("[ Total successful: %s ]", suite_ok); + print ("[ Total failures: %s ]", suite_fail.length); + print ("[ Tests failed: ]"); + for (var i = 0; i < suite_fail.length; i++) { + print ("[ %s]", suite_fail[i]); + }; + assert(false, "[ Test suite fail ]"); +} else { + print ("[ Test execution with success ]"); + print ("[ Total tests run: %s ]", suite_ok); +} + +exit(); diff --git a/src/tests/efl_js/benchmark_object.eo b/src/tests/efl_js/benchmark_object.eo new file mode 100644 index 0000000000..34dd142039 --- /dev/null +++ b/src/tests/efl_js/benchmark_object.eo @@ -0,0 +1,24 @@ +class Benchmark_Object (Eo.Base) +{ + legacy_prefix: null; + data: null; + methods { + emptyarg { + } + onearg { + params { one: int; } + } + twoarg { + params { one: int; two: int; } + } + tenarg { + params { one: int; two: int; three: int; four: int; five: int; six: int; seven: int; eight: int; nine: int; ten: int; } + } + onecomplexarg { + params { one: list<int>*; } + } + tencomplexarg { + params { one: list<int>*; two: list<int>*; three: list<int>*; four: list<int>*; five: list<int>*; six: list<int>*; seven: list<int>*; eight: list<int>*; nine: list<int>*; ten: list<int>*; } + } + } +} diff --git a/src/tests/efl_js/benchmark_object_impl.cc b/src/tests/efl_js/benchmark_object_impl.cc new file mode 100644 index 0000000000..538c31b2ce --- /dev/null +++ b/src/tests/efl_js/benchmark_object_impl.cc @@ -0,0 +1,110 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eo.h> +#include <Ecore.h> + +#include <stdlib.h> + +extern "C" { +#include "benchmark_object.eo.h" + +void _benchmark_object_emptyarg(Eo*, void*) +{ +} +void _benchmark_object_onearg(Eo*, void*, int) +{ +} +void _benchmark_object_twoarg(Eo*, void*, int, int) +{ +} +void _benchmark_object_tenarg(Eo*, void*, int, int, int, int, int, int, int, int, int, int) +{ +} +void _benchmark_object_onecomplexarg(Eo*, void*, Eina_List*) +{ +} +void _benchmark_object_tencomplexarg(Eo*, void*, Eina_List*, Eina_List*, Eina_List*, Eina_List*, Eina_List*, Eina_List*, Eina_List*, Eina_List*, Eina_List*, Eina_List*) +{ +} + +#include "benchmark_object.eo.c" +} + +#include "benchmark_object.eo.js.cc" + +#ifdef HAVE_NODEJS +namespace { +using efl::eina::js::compatibility_return_type; +using efl::eina::js::compatibility_callback_info_type; +using efl::eina::js::compatibility_return; +using efl::eina::js::compatibility_new; + +#define JS_BENCHMARK_ARGS0(v) +#define JS_BENCHMARK_ARGS1(v) v +#define JS_BENCHMARK_ARGS2(v) v,v +#define JS_BENCHMARK_ARGS10(v) v,v,v,v,v,v,v,v,v,v +#define JS_BENCHMARK_FUNC(name, number, v) \ + compatibility_return_type js_benchmark_object_##name##arg(compatibility_callback_info_type) \ + { \ + Eina_Counter* counter = eina_counter_new("counter"); \ + Eo* object = eo_add(BENCHMARK_OBJECT_CLASS, NULL); \ + Eina_List* l = NULL; \ + (void)l; \ + /* Warm */ \ + for(int i = 0; i != 10; i++) \ + { \ + eo_do(object, benchmark_object_##name##arg(JS_BENCHMARK_ARGS##number(v))); \ + } \ + /* Real loop */ \ + eina_counter_start(counter); \ + for(int i = 0; i != 20000; i++) \ + { \ + eo_do(object, benchmark_object_##name##arg(JS_BENCHMARK_ARGS##number(v))); \ + } \ + eina_counter_stop(counter, 20000); \ + fprintf(stderr, "%s", eina_counter_dump(counter)); \ + eo_del(object); \ + return compatibility_return(); \ + } + +JS_BENCHMARK_FUNC(empty, 0, 1) +JS_BENCHMARK_FUNC(one, 1, 1) +JS_BENCHMARK_FUNC(two, 2, 1) +JS_BENCHMARK_FUNC(ten, 10, 1) +JS_BENCHMARK_FUNC(onecomplex, 1, l) +JS_BENCHMARK_FUNC(tencomplex, 10, l) + + +void benchmark_object_module_init(v8::Handle<v8::Object> exports) +{ + fprintf(stderr, "test suite eolian_js_module_init\n"); fflush(stderr); + try + { + eina_init(); + eo_init(); + register_benchmark_object(exports, v8::Isolate::GetCurrent()); +#define JS_BENCHMARK_EXPORT(name) \ + exports->Set(compatibility_new<v8::String>(nullptr, "benchmark_" #name "arg") \ + , compatibility_new<v8::FunctionTemplate>(nullptr, &js_benchmark_object_##name##arg)->GetFunction()); + JS_BENCHMARK_EXPORT(empty) + JS_BENCHMARK_EXPORT(one) + JS_BENCHMARK_EXPORT(two) + JS_BENCHMARK_EXPORT(ten) + JS_BENCHMARK_EXPORT(onecomplex) + JS_BENCHMARK_EXPORT(tencomplex) + } + catch(...) + { + std::cerr << "Error" << std::endl; + std::abort(); + } +} + +} + +#include <eina_js_node.hh> + +NODE_MODULE(benchmark_object, ::benchmark_object_module_init) +#endif diff --git a/src/tests/efl_js/ecore_js_suite.cc b/src/tests/efl_js/ecore_js_suite.cc new file mode 100644 index 0000000000..c7583f2b3e --- /dev/null +++ b/src/tests/efl_js/ecore_js_suite.cc @@ -0,0 +1,7 @@ + +#include "suite_runner.hh" + +int main(int, char*[]) +{ + return run_script(TESTS_SRC_DIR "/ecore_js_suite.js", nullptr); +} diff --git a/src/tests/efl_js/ecore_js_suite.js b/src/tests/efl_js/ecore_js_suite.js new file mode 100755 index 0000000000..8534304c1b --- /dev/null +++ b/src/tests/efl_js/ecore_js_suite.js @@ -0,0 +1,352 @@ +#!/usr/bin/env node + +// Preamble +function assert(condition, message) { + if (!condition) { + print("Assertion failed ", message); + throw new Error(message || "Assertion failed"); + } +} + +if(typeof process !== 'undefined') +{ + console.log('running from nodejs'); + console.log('path', process.env.NODE_PATH); + console.log("teste1"); + + efl = require('efl'); + assert(efl != null, "could not load efl node module"); + + // Setup output aliases + print = console.log; + print_error = function() { + if (process.argv.indexOf("--supress-errors") == -1) + console.error.apply(null, arguments); + }; + print_info = function() { + if (process.argv.indexOf("--verbose") != -1) + console.info.apply(null, arguments); + }; + exit = efl.ecore_mainloop_quit; +} +else +{ + assert = function(test, message) { if (test !== true) throw message; }; + print('running from libv8') + //FIXME Add levels to v8 tests + print_error = print + print_info = print + exit = function() {} +} + +// Global flag for suite success // +suite_success = true; +// Global test summary +suite_ok = 0; +suite_fail = []; // Will store the name of the failures + +// Basic test function // +function start_test(test_name, test_func) { + print("[ RUN ] ecore_js_suite: " + test_name); + var test_result = true; + try { + test_func(); + } catch (e) { + suite_success = false; + test_result = false; + print_error("Error: ", e, e.stack); + } + print("[ " + (test_result ? "PASS" : "FAIL") + " ] ecore_js_suite: " + test_name); + if (test_result) + suite_ok += 1; + else + suite_fail.push(test_name); +} +// end Preamble + +// ecore preamble +function abs(n) { + if (n < 0) + return n * -1; + return n; +} +var TOLERANCE = 0.0001; +// end ecore preamble + +start_test("timers", function () { + var p = 2.5; + efl.ecore_timer_precision_set(p); + assert(abs(efl.ecore_timer_precision_get() - p) < TOLERANCE); + + p = 0.5; + efl.ecore_timer_precision_set(p); + assert(abs(efl.ecore_timer_precision_get() - p) < TOLERANCE); + + var ncalls = 0; + + captured = false; + efl.ecore_timer_add(1, function() { + print_info('ecore_timer_add handler'); + ++ncalls; + if (ncalls != 4) + return true; + + captured = true; + efl.ecore_job_add(efl.ecore_mainloop_quit); + return false; + }); + + efl.ecore_mainloop_begin(); + assert(captured); + + ncalls = 0; + captured = false; + + efl.ecore_timer_loop_add(1, function() { + ++ncalls; + if (ncalls != 4) + return true; + + captured = true; + efl.ecore_job_add(efl.ecore_mainloop_quit); + return false; + }); + + efl.ecore_mainloop_begin(); + assert(captured); + + captured = false; + + var timer = efl.ecore_timer_add(1, function() { + captured = true; + return false; + }); + + assert(timer.freeze_get() === false); + + timer.freeze(); + + assert(timer.freeze_get() === true); + + timer.thaw(); + + assert(timer.freeze_get() === false); + + timer.del(); + + efl.ecore_timer_add(2, function() { + efl.ecore_job_add(efl.ecore_mainloop_quit); + return false; + }); + + efl.ecore_mainloop_begin(); + assert(captured === false); +}); + +// Ecore event +start_test("ecore event", function () { + var myevent = efl.ecore_event_type_new(); + + captured = [0, 0, 0] + + var handler1 = efl.ecore_event_handler_add(myevent, function(event) { + assert(efl.ecore_event_current_type_get() === myevent); + assert(event === myevent); + captured[0] += 1; + return efl.ECORE_CALLBACK_PASS_ON; + }); + + var handler2 = efl.ecore_event_handler_add(myevent, function(event) { + assert(efl.ecore_event_current_type_get() === myevent); + assert(event === myevent); + captured[1] += 1; + return efl.ECORE_CALLBACK_DONE; + }); + + var handler3 = efl.ecore_event_handler_add(myevent, function(event) { + assert(efl.ecore_event_current_type_get() === myevent); + assert(event === myevent); + captured[2] += 1; + return efl.ECORE_CALLBACK_DONE; + }); + + efl.ecore_timer_add(1, function() { + efl.ecore_event_add(myevent); + assert(captured[0] === 0 && captured[1] === 0 && captured[2] === 0); + efl.ecore_timer_add(1, function() { + assert(captured[0] === 1 && captured[1] === 1 && captured[2] === 0); + handler1.del(); + efl.ecore_event_add(myevent); + efl.ecore_event_add(myevent); + efl.ecore_event_add(myevent).del(); + efl.ecore_timer_add(1, function() { + assert(captured[0] === 1 && captured[1] === 3 && captured[2] === 0); + efl.ecore_mainloop_quit(); + }); + }); + }); + + efl.ecore_mainloop_begin(); + + efl.ecore_event_add(myevent); + efl.ecore_event_add(myevent); + efl.ecore_event_add(myevent); + + var filter = efl.ecore_event_filter_add(function() { + return {count: 0}; + }, function(loop_data, event) { + assert(event === myevent); + var c = loop_data.count; + ++loop_data.count; + return c != 0; + }, function(loop_data) {}); + + efl.ecore_timer_add(1, efl.ecore_mainloop_quit); + efl.ecore_mainloop_begin(); + assert(captured[1] === 5); + filter.del(); + + efl.ecore_event_add(myevent); + efl.ecore_event_add(myevent); + efl.ecore_event_add(myevent); + + efl.ecore_timer_add(1, efl.ecore_mainloop_quit); + efl.ecore_mainloop_begin(); + assert(captured[1] === 8); + + handler2.del(); + handler3.del(); +}); + + // Ecore job +start_test("ecore jobs", function () { + captured = false; + + efl.ecore_job_add(function() { + captured = true; + efl.ecore_mainloop_quit(); + }); + + assert(captured === false); + efl.ecore_mainloop_begin(); + assert(captured === true); + + captured = false; + var job = efl.ecore_job_add(function() { + captured = true; + }); + efl.ecore_job_add(efl.ecore_mainloop_quit); + job.del(); + efl.ecore_mainloop_begin(); + assert(captured === false); +}); + +start_test("ecore idle", function () { + // Ecore idle + var counter = 1; + captured = [0, 0, 0, 0, 0]; + + efl.ecore_idler_add(function() { + print_info('ecore idle handler 1'); + captured[0] = counter; + counter += 1; + efl.ecore_job_add(function() { print_info('ecore job handler 1'); }); + return efl.ECORE_CALLBACK_DONE; + }); + + print_info('ecore idle 1'); + + efl.ecore_idle_enterer_add(function() { + print_info('ecore idle handler 2'); + captured[1] = counter; + counter += 1; + return efl.ECORE_CALLBACK_DONE; + }); + + print_info('ecore idle 2'); + + efl.ecore_idle_enterer_add(function() { + print_info('ecore idle handler 3'); + captured[2] = counter; + counter += 1; + return efl.ECORE_CALLBACK_DONE; + }); + + print_info('ecore idle 3'); + + efl.ecore_idle_enterer_before_add(function() { + print_info('ecore idle handler 4'); + captured[3] = counter; + counter += 1; + return efl.ECORE_CALLBACK_DONE; + }); + + print_info('ecore idle 4'); + + efl.ecore_idle_exiter_add(function() { + print_info('ecore idle handler 5'); + captured[4] = counter; + counter += 1; + efl.ecore_mainloop_quit(); + return efl.ECORE_CALLBACK_DONE; + }); + + print_info('ecore idle 5'); + + efl.ecore_mainloop_begin(); + + print_info('ecore idle 6'); + + assert(captured[0] === 4, "ecore_idler_add test"); + assert(captured[1] === 2, "ecore_idle_enterer_add test"); + assert(captured[2] === 3, "ecore_idle_enterer_add test two"); + assert(captured[3] === 1, "ecore_idle_enterer_before_add test"); + assert(captured[4] === 5, "ecore_idle_exiter_add test"); +}); + +// Ecore animator +start_test("ecore animator", function () { + efl.ecore_animator_frametime_set(1); + assert(efl.ecore_animator_frametime_get() === 1); + efl.ecore_animator_frametime_set(1 / 50); + assert(efl.ecore_animator_frametime_get() === (1 / 50)); + + assert(efl.ecore_animator_pos_map(0.5, efl.ECORE_POS_MAP_LINEAR, 0, 0) + === 0.5); + + efl.ecore_animator_source_set(efl.ECORE_ANIMATOR_SOURCE_CUSTOM); +}); + +// Ecore poller +start_test("ecore poller", function () { + efl.ecore_poller_poll_interval_set(efl.ECORE_POLLER_CORE, 42); + assert(efl.ecore_poller_poll_interval_get(efl.ECORE_POLLER_CORE) === 42); + efl.ecore_poller_poll_interval_set(efl.ECORE_POLLER_CORE, 2); + assert(efl.ecore_poller_poll_interval_get(efl.ECORE_POLLER_CORE) === 2); +}); + +start_test("ecore throttle", function () { + // Ecore throttle + + efl.ecore_throttle_adjust(3); + assert(efl.ecore_throttle_get() === 3); + efl.ecore_throttle_adjust(-3); + assert(efl.ecore_throttle_get() === 0); +}); + +// footer +if (!suite_success) { + print ("[ Total tests run: %s ]", suite_ok + suite_fail.length); + print ("[ Total successful: %s ]", suite_ok); + print ("[ Total failures: %s ]", suite_fail.length); + print ("[ Tests failed: ]"); + for (var i = 0; i < suite_fail.length; i++) { + print ("[ %s]", suite_fail[i]); + }; + assert(false, "[ Test suite fail ]"); +} else { + print ("[ Test execution with success ]"); + print ("[ Total tests run: %s ]", suite_ok); +} + +exit(); diff --git a/src/tests/efl_js/eina_js_containers_suite.cc b/src/tests/efl_js/eina_js_containers_suite.cc new file mode 100644 index 0000000000..5455b9438a --- /dev/null +++ b/src/tests/efl_js/eina_js_containers_suite.cc @@ -0,0 +1,7 @@ + +#include "suite_runner.hh" + +int main(int, char*[]) +{ + return run_script(TESTS_SRC_DIR "/eina_js_containers_suite.js", nullptr); +} diff --git a/src/tests/efl_js/eina_js_containers_suite.js b/src/tests/efl_js/eina_js_containers_suite.js new file mode 100755 index 0000000000..f4f6bf314e --- /dev/null +++ b/src/tests/efl_js/eina_js_containers_suite.js @@ -0,0 +1,552 @@ +#!/usr/bin/env node + +// Preamble +function assert(condition, message) { + if (!condition) { + print("Assertion failed ", message); + throw new Error(message || "Assertion failed"); + } +} + +if(typeof process !== 'undefined') +{ + console.log('running from nodejs'); + console.log('path', process.env.NODE_PATH); + console.log("teste1"); + + efl = require('efl'); + assert(efl != null, "could not load efl node module"); + + // Setup output aliases + print = console.log; + print_error = function() { + if (process.argv.indexOf("--supress-errors") == -1) + console.error.apply(null, arguments); + }; + print_info = function() { + if (process.argv.indexOf("--verbose") != -1) + console.info.apply(null, arguments); + }; + exit = efl.ecore_mainloop_quit; +} +else +{ + assert = function(test, message) { if (test !== true) throw message; }; + print('running from libv8') + //FIXME Add levels to v8 tests + print_error = print + print_info = print + exit = function() {} +} + +// Global flag for suite success // +suite_success = true; +// Global test summary +suite_ok = 0; +suite_fail = []; // Will store the name of the failures + +// Basic test function // +function start_test(test_name, test_func) { + print("[ RUN ] eina_js_suite: " + test_name); + var test_result = true; + try { + test_func(); + } catch (e) { + suite_success = false; + test_result = false; + print_error("Error: ", e, e.stack); + } + print("[ " + (test_result ? "PASS" : "FAIL") + " ] eina_js_suite: " + test_name); + if (test_result) + suite_ok += 1; + else + suite_fail.push(test_name); +} +// end Preamble + +start_test("container_test default list should have size zero", function(){ + var container = new efl.List; + assert (container.length == 0); +}); + +start_test("container test default Array should have size zero", function(){ + var container = new efl.Array; + assert (container.length == 0); +}); + +start_test("container_test empty list access should return undefined", function(){ + var empty_l = new efl.List; + assert (typeof empty_l[0] === "undefined"); + assert (typeof empty_l[1] === "undefined"); +}); + +start_test("container_test empty Array access should return undefined", function(){ + var empty_l = new efl.Array; + assert (typeof empty_l[0] === "undefined"); + assert (typeof empty_l[1] === "undefined"); +}); + +start_test("container_test empty list indexOf should return -1", function(){ + var empty_l = new efl.List; + assert(empty_l.indexOf(0) == -1); + assert(empty_l.indexOf(42) == -1); +}); + +start_test("container_test empty Array indexOf should return -1", function(){ + var empty_l = new efl.Array; + assert(empty_l.indexOf(0) == -1); + assert(empty_l.indexOf(42) == -1); +}); + +start_test("container_test List indexOf should not break with wrong type", function(){ + container_indexof_wrong_type(efl.List); +}); + +start_test("container_test Array indexOf should not break with wrong type", function(){ + container_indexof_wrong_type(efl.Array); +}); + +function container_indexof_wrong_type(T) { + var x = new T("int"); + var raised = false; + try { + x.indexOf("float") + } catch (err) { + raised = true; + } + + assert(!raised, "container index of should not break with wrong types"); +} + +start_test("container_test list[0] = x on empty list", function(){ + var empty_l = new efl.List; + assert(empty_l.length == 0); + empty_l[0] = 42; + assert(empty_l.length == 1); + assert(empty_l[0] == 42); +}); + +start_test("container_test array[0] = x on empty Array", function(){ + var empty_l = new efl.Array; + assert(empty_l.length == 0); + empty_l[0] = 42; + assert(empty_l.length == 1); + assert(empty_l[0] == 42); +}); + +start_test("container_test out of bounds x[i] setter should resize list", function(){ + container_out_of_bound_setter(efl.List); +}); + +start_test("container_test out of bounds x[i] setter should resize Array", function(){ + container_out_of_bound_setter(efl.Array); +}); + +function container_out_of_bound_setter(T1) { + var empty_l = new T1; + assert(empty_l.length == 0); + empty_l[9] = 1; + assert(empty_l.length == 10); + for (var i = 0; i < 9; i++) { + assert(empty_l[i] == 0); + }; + assert(empty_l[9] == 1); +} + +start_test("container_test push items should increase list length", function(){ + container_push_length(efl.List); +}); + +start_test("container_test push items should increase Array length", function(){ + container_push_length(efl.Array); +}); + +function container_push_length(T1) { + var l1 = new T1; + print_info("l1 ", l1.toString()); + l1.push(1); + assert (l1.length == 1); + l1.push(2); + assert (l1.length == 2); + l1.push(3); + assert (l1.length == 3); +} + +start_test("container_test list simple push and access valid items", function(){ + container_push_access_valid(efl.List); +}); + +start_test("container_test Array simple push and access valid items", function(){ + container_push_access_valid(efl.Array); +}); + +function container_push_access_valid(T1) { + var l1 = new T1; + l1.push(1); + l1.push(2); + assert (l1[0] == 1); + assert (l1[1] == 2); +} + +start_test("container_test list simple push and access items out of bounds", function(){ + container_push_out_of_bounds(efl.List); +}); + +start_test("container_test Array simple push and access items out of bounds", function(){ + container_push_out_of_bounds(efl.Array); +}); + +function container_push_out_of_bounds(T1) { + var l1 = new T1; + l1.push(1); + l1.push(2); + assert (typeof l1[3] === "undefined"); + assert (typeof l1[42] === "undefined"); +} + +start_test("container_test list push and pop", function() { + container_push_pop(efl.List); +}); + +start_test("container_test Array push and pop", function() { + container_push_pop(efl.Array); +}); + +function container_push_pop(T1) { + var l1 = new T1; + + assert(typeof l1.pop() === "undefined", "pop on empty container should return undefined"); + + l1.push(1); + l1.push(2); + assert(l1.length == 2); + assert(l1.pop() == 2, "Pop should return last element"); + assert(l1.length == 1, "Pop should decrease list length"); + assert(l1.pop() == 1, "Pop should return last element even if it's the only element"); + assert(l1.length == 0, "Pop on single element list should leave it empty"); +} + +start_test("container_test list simple push and indexOf valid elements", function(){ + container_push_indexof_valid(efl.List) +}); + +start_test("container_test Array simple push and indexOf valid elements", function(){ + container_push_indexof_valid(efl.Array) +}); + +function container_push_indexof_valid(T1) { + var l1 = new T1; + l1.push(1); + l1.push(2); + assert(l1.indexOf(1) == 0); + assert(l1.indexOf(2) == 1); +} + +start_test("container_test list simple push and indexOf elements out of bounds", function(){ + container_push_indexof_out_of_bounds(efl.List); +}); + +start_test("container_test list simple push and indexOf elements out of bounds", function(){ + container_push_indexof_out_of_bounds(efl.Array); +}); + +function container_push_indexof_out_of_bounds(T1) { + var l1 = new T1; + l1.push(1); + l1.push(2); + assert(l1.indexOf(3) == -1); + assert(l1.indexOf(44) == -1); +} + +start_test("container_test list concat filled + empty shouldn't change length", function(){ + container_filled_concat_empty_length(efl.List); +}); + +start_test("container_test array concat filled + empty shouldn't change length", function(){ + container_filled_concat_empty_length(efl.Array); +}); + +function container_filled_concat_empty_length(T1) { + var empty_l = new T1; + var l1 = new T1; + l1.push(1); + l1.push(2); + l1.push(3); + var cle = l1.concat(empty_l); + assert (cle.length == 3); +} + +start_test("container_test list concat empty + filled shouldn't change length", function(){ + container_empty_concat_filled_length(efl.List); +}); + +start_test("container_test array concat empty + filled shouldn't change length", function(){ + container_empty_concat_filled_length(efl.Array); +}); + +function container_empty_concat_filled_length(T1) { + var empty_l = new T1; + var l1 = new T1; + l1.push(1); + l1.push(2); + l1.push(3); + var cel = empty_l.concat(l1); + assert (cel.length == 3); +} + +start_test("container_test concat two valid lists", function(){ + container_concat_two_valid_containers(efl.List, efl.List); +}); + +start_test("container_test concat two valid arrays", function(){ + container_concat_two_valid_containers(efl.Array, efl.Array); +}); + +function container_concat_two_valid_containers(T1, T2) { + l1 = new T1; + l1.push(1); + l1.push(2); + l1.push(3); + l2 = new T2; + l2.push(1); + l2.push(2); + l2.push(3); + var c = l1.concat(l2); + + assert (c.length == (l1.length + l2.length)); + assert (c[0] == l1[0]); + assert (c[1] == l1[1]); + assert (c[2] == l1[2]); + assert (c[3] == l2[0]); + assert (c[4] == l2[1]); + assert (c[5] == l2[2]); + assert (c.indexOf(c[0]) == 0); + assert (c.indexOf(c[1]) == 1); + assert (c.indexOf(c[2]) == 2); + assert (c.indexOf(c[3]) == 0); + assert (c.indexOf(c[4]) == 1); + assert (c.indexOf(c[5]) == 2); + assert (c.lastIndexOf(c[0]) == 3); + assert (c.lastIndexOf(c[1]) == 4); + assert (c.lastIndexOf(c[2]) == 5); + assert (c.lastIndexOf(c[3]) == 3); + assert (c.lastIndexOf(c[4]) == 4); + assert (c.lastIndexOf(c[5]) == 5); +} + +start_test("container_test concat different types", function() { + container_concat_diff_types(efl.Array, efl.List); + container_concat_diff_types(efl.List, efl.Array); +}); + +function container_concat_diff_types(T1, T2) { + var l1 = new T1; + var l2 = new T2; + var raised = false; + + try { + l1.concat(l2); + assert(false, "Should raise exception after concatenating two different types.") + } catch (err) { + raised = true; + assert(err.name == "TypeError", "Exception should be TypeError."); + } + + assert(raised, "Exception was not raised after concatenating different types."); +} + +start_test("container_test toString list", function(){ + container_to_string(efl.List); +}); + +start_test("container_test toString array", function(){ + container_to_string(efl.Array); +}); + +function container_to_string(T) { + var x = new T("int"); + + assert("" == x.toString(), "toString empty container"); + + x.push(1); + assert("1" == x.toString(), "toString single element"); + + x.push(2); + assert("1,2" == x.toString(), "toString two elements"); + + x.push(100); + assert("1,2,100" == x.toString(), "toString three elements"); +} + +start_test("container_test join list", function(){ + container_join(efl.List); +}); + +start_test("container_test join Array", function(){ + container_join(efl.Array); +}); + +function container_join(T) { + var x = new T("int"); + var ref = new Array; + + assert(ref.join() == x.join(), "default join on empty containers"); + assert(ref.join(':') == x.join(':'), "arg join on empty containers"); + + x.push(42); + ref.push(42); + + assert(ref.join() == x.join(), "default join on single-element containers"); + assert(ref.join(':') == x.join(':'), "arg join on single-element containers"); + + x.push(314); + ref.push(314); + + assert(ref.join() == x.join(), "default join on multiple-element containers"); + assert(ref.join(':') == x.join(':'), "arg join on multiple-element containers"); +} + +start_test("container_test join wrong arguments", function(){ + +}); + +function container_join_wrong_type(T1, T2) { + var l1 = new T1("int"); + var raised = false; + + try { + l1.join({}); + assert(false, "Should raise exception after trying to join with wrong argument type."); + } catch (err) { + raised = true; + assert(err.name == "TypeError", "Exception should be TypeError."); + } + + assert(raised, "Exception was not raised after join with wrong argument type."); +} + +start_test("container_test slice list simple", function () { + container_slice_simple(efl.List); +}); + +start_test("container_test slice Array simple", function () { + container_slice_simple(efl.Array); +}); + +function container_slice_simple(T1) { + l1 = new T1; + l1.push(1); + l1.push(2); + l1.push(3); + + var s1 = l1.slice(1, 3); + assert (s1.length == 2); + assert (s1[0] == l1[1]); + assert (s1[1] == l1[2]); +} + +start_test("container_test slice list single argument", function() { + container_slice_single_arg(efl.List); +}); + +start_test("container_test slice Array single argument", function() { + container_slice_single_arg(efl.Array); +}); + +function container_slice_single_arg(T1) { + l1 = new T1; + l1.push(0); + l1.push(1); + l1.push(2); + l1.push(3); + l1.push(4); + + var s1 = l1.slice(1); + assert(s1.length == (l1.length - 1)); + assert(s1[0] == l1[1]); + assert(s1[1] == l1[2]); + assert(s1[2] == l1[3]); + assert(s1[3] == l1[4]); +} + +start_test("container_test slice list no arguments", function() { + container_slice_no_args(efl.List); +}); + +start_test("container_test slice Array no arguments", function() { + container_slice_no_args(efl.Array); +}); + +function container_slice_no_args(T1) { + l1 = new T1; + l1.push(0); + l1.push(1); + l1.push(2); + l1.push(3); + l1.push(4); + + var s1 = l1.slice(); + assert(s1.length == l1.length); + assert(s1[0] == l1[0]); + assert(s1[1] == l1[1]); + assert(s1[2] == l1[2]); + assert(s1[3] == l1[3]); + assert(s1[4] == l1[4]); +} + +start_test("container test list of strings", function(){ + container_test_generic(new efl.List("string"), ["The", "quick", "brown", "fox"]); +}); + +start_test("container test array of strings", function(){ + container_test_generic(new efl.Array("string"), ["The", "quick", "brown", "fox"]); +}); + +start_test("container test list of floats", function(){ + container_test_generic(new efl.List("float"), [3.42, 3.14, 1.22, 0.0]); +}); + +start_test("container test Array of floats", function(){ + container_test_generic(new efl.Array("float"), [3.42, 3.14, 1.22, 0.0]); +}); + +start_test("container test list of bools", function(){ + container_test_generic(new efl.List("bool"), [true, false, false, false]); +}); + +start_test("container test array of bools", function(){ + container_test_generic(new efl.Array("bool"), [true, false, false, false]); +}); + +function container_test_generic(list, js_ref_list) { + assert(list.length == 0); + list.push(js_ref_list[0]); + list.push(js_ref_list[1]); + list.push(js_ref_list[2]); + list.push(js_ref_list[3]); + + assert(list.indexOf(js_ref_list[0]) == 0, "First pushed element has index 0"); + assert(list.indexOf(js_ref_list[1]) == 1, "Second pushed element has index 1"); + assert(list.lastIndexOf(js_ref_list[0]) == 0, "First element is unique, so its lastIndexOf should be 0"); + + assert(list.toString() == js_ref_list.toString(), "toString must be equal to JS.") + assert(list.pop() == js_ref_list[3], "Pop should return the last list element"); +} + +// footer + +if (!suite_success) { + print ("[ Total tests run: %s ]", suite_ok + suite_fail.length); + print ("[ Total successful: %s ]", suite_ok); + print ("[ Total failures: %s ]", suite_fail.length); + print ("[ Tests failed: ]"); + for (var i = 0; i < suite_fail.length; i++) { + print ("[ %s]", suite_fail[i]); + }; + assert(false, "[ Test suite fail ]"); +} else { + print ("[ Test execution with success ]"); + print ("[ Total tests run: %s ]", suite_ok); +} + +exit(); diff --git a/src/tests/efl_js/eina_js_suite.cc b/src/tests/efl_js/eina_js_suite.cc new file mode 100644 index 0000000000..68345b5068 --- /dev/null +++ b/src/tests/efl_js/eina_js_suite.cc @@ -0,0 +1,7 @@ + +#include "suite_runner.hh" + +int main(int, char*[]) +{ + return run_script(TESTS_SRC_DIR "/eina_js_suite.js", nullptr); +} diff --git a/src/tests/efl_js/eina_js_suite.js b/src/tests/efl_js/eina_js_suite.js new file mode 100755 index 0000000000..811e1f6756 --- /dev/null +++ b/src/tests/efl_js/eina_js_suite.js @@ -0,0 +1,360 @@ +#!/usr/bin/env node + +// Preamble +function assert(condition, message) { + if (!condition) { + print("Assertion failed ", message); + throw new Error(message || "Assertion failed"); + } +} + +if(typeof process !== 'undefined') +{ + console.log('running from nodejs'); + console.log('path', process.env.NODE_PATH); + console.log("teste1"); + + efl = require('efl'); + assert(efl != null, "could not load efl node module"); + + // Setup output aliases + print = console.log; + print_error = function() { + if (process.argv.indexOf("--supress-errors") == -1) + console.error.apply(null, arguments); + }; + print_info = function() { + if (process.argv.indexOf("--verbose") != -1) + console.info.apply(null, arguments); + }; + exit = efl.ecore_mainloop_quit; +} +else +{ + assert = function(test, message) { if (test !== true) throw message; }; + print('running from libv8') + //FIXME Add levels to v8 tests + print_error = print + print_info = print + exit = function() {} +} + +// Global flag for suite success // +suite_success = true; +// Global test summary +suite_ok = 0; +suite_fail = []; // Will store the name of the failures + +// Basic test function // +function start_test(test_name, test_func) { + print("[ RUN ] eina_js_suite: " + test_name); + var test_result = true; + try { + test_func(); + } catch (e) { + suite_success = false; + test_result = false; + print_error("Error: ", e, e.stack); + } + print("[ " + (test_result ? "PASS" : "FAIL") + " ] eina_js_suite: " + test_name); + if (test_result) + suite_ok += 1; + else + suite_fail.push(test_name); +} + +function array_equal(a, b) { + if (a === b) return true; + if (a == null || b == null) return false; + if (a.length != b.length) return false; + + for (var i = 0; i < a.length; ++i) { + if (a[i] !== b[i] + && (Object.prototype.toString.call(a[i]) === '[object Array]' + && Object.prototype.toString.call(b[i] === '[object Array]') + && !array_equal(a[i], b[i]))) + return false; + } + return true; +} +// end Preamble + +// eina Preamble +// Functions to get the line in NodeJS and V8 +Object.defineProperty(global, '__stack', { +get: function() { + var orig = Error.prepareStackTrace; + Error.prepareStackTrace = function(_, stack) { + return stack; + }; + var err = new Error; + Error.captureStackTrace(err, arguments.callee); + var stack = err.stack; + Error.prepareStackTrace = orig; + return stack; + } +}); + +Object.defineProperty(global, '__line', { +get: function() { + return __stack[1].getLineNumber(); + } +}); + +Object.defineProperty(global, '__function', { +get: function() { + return __stack[1].getFunctionName(); + } +}); +// end eina Preamble + +// value tests +start_test("value tests int get test", function () { + print_info("x"); + + var my_value = new efl.value(1); + print_info("x"); + var wrapped = my_value.get(); + print_info("x"); + assert(typeof(wrapped) === 'number', 'typeof wrapped is not number'); + print_info("x"); + assert(wrapped === 1, 'wrapped should be 1'); + print_info("x"); +}); + +start_test("value tests int set test", function(){ + var my_value = new efl.value(1); + var wrapped = my_value.get(); + my_value.set(2); + print_info("x"); + assert(wrapped === 1, 'Setting a value should not change a previous wrapped result'); + print_info("x"); + wrapped = my_value.get(); + print_info("x"); + assert(typeof(wrapped) === 'number', 'wrapped value after setting to number should be a number'); + print_info("x"); + assert(wrapped === 2, 'wrapped is different from value set'); + print_info("x"); +}); + +start_test("value tests int set to bool", function(){ + var my_value = new efl.value(2); + var wrapped = my_value.get(); + my_value.set(true); + print_info("x"); + assert(wrapped === 2, 'Setting a value should not change a previous wrapped result'); + print_info("x"); + wrapped = my_value.get(); + print_info("x"); + // boolean is represented as integer in the efl::eina::value layer + print_info("x"); + assert(typeof(wrapped) === 'number', 'value.get from bool value should be a number'); + print_info("x"); + assert(wrapped === 1, 'value.get from a true boolean should be 1'); + print_info("x"); +}); + +start_test("value tests set value to complex object", function() { + var my_value = new efl.value(1); + print_info("x"); + var captured = false; + print_info("x"); + try { + print_info("x"); + my_value.set({type: 'complex object'}); + print_info("x"); + } catch(e) { + print_info("x"); + assert(e.code === 'std::bad_cast', 'Trying to set a complex object to a value should raise std::bad_cast'); + print_info("x"); + captured = true; + print_info("x"); + } + print_info("x"); + assert(captured === true, 'Trying to set a complex object should raise an exception'); + print_info("x"); +}); + +start_test("value tests create value from complex object", function() { + print_info("x"); + var captured = false; + print_info("x"); + try { + print_info("x"); + my_value = new efl.value({type: 'complex object'}); + print_info("x"); + } catch(e) { + print_info("e.code ", e.code, ' ', typeof e); + assert(e.code === 'std::bad_cast', 'Trying to create a value from a complex object should raise std::bad_cast'); + print_info("x"); + captured = true; + print_info("x"); + } + assert(captured === true, 'Trying to create a value from a complex object should raise an exception'); +}); +// log + +start_test("log tests basic", function () { + function f1(){ efl.logPrint(efl.LOG_DOMAIN_GLOBAL, efl.LOG_LEVEL_DBG, 'I changed again'); }; f1(); + efl.logPrint(efl.LOG_DOMAIN_GLOBAL, efl.LOG_LEVEL_CRITICAL, 'Cool to Hate'); + function f2(){ efl.logPrint(efl.LOG_DOMAIN_GLOBAL, efl.LOG_LEVEL_WARN, 'One Fine Day'); }; f2(); + function f3(){ efl.logPrint(efl.mydomain, efl.LOG_LEVEL_INFO, 'Never Gonna Find Me'); }; f3(); +}); + +start_test("log tests domains", function() { + var mydomain2 = efl.registerLogDomain('mydomain2', ''); + efl.setLogDomainRegisteredLevel(mydomain2, efl.LOG_LEVEL_DBG); + assert(efl.getLogDomainRegisteredLevel(mydomain2) === efl.LOG_LEVEL_DBG, 'Level set is not LEVEL_DBG'); + efl.logPrint(mydomain2, efl.LOG_LEVEL_ERR, "The Kids Aren't Alright"); + + efl.unregisterLogDomain(mydomain2); +}); + +start_test("log tests properties", function() { + efl.setLogColorDisable(true); + assert(efl.getLogColorDisable() === true, 'getLogColorDisable is false after setting to true'); + efl.setLogColorDisable(false); + assert(efl.getLogColorDisable() === false, 'getLogColorDisable is true after setting to false'); + + efl.setLogFileDisable(true); + assert(efl.getLogFileDisable() === true, 'getLogFileDisable is false after setting to true'); + efl.setLogFileDisable(false); + assert(efl.getLogFileDisable() === false, 'getLogFileDisable is true after setting to false'); + + efl.setLogFunctionDisable(true); + assert(efl.getLogFunctionDisable() === true, 'getLogFunctionDisable is false after setting to true'); + efl.setLogFunctionDisable(false); + assert(efl.getLogFunctionDisable() === false, 'getLogFunctionDisable is true after setting to false'); + + efl.setLogAbortOnCritical(true); + assert(efl.getLogAbortOnCritical() === true, 'getLogAbortOnCritical is false after setting to true'); + efl.setLogAbortOnCritical(false); + assert(efl.getLogAbortOnCritical() === false, 'getLogAbortOnCritical is true after setting to false'); + +}); + +start_test("log tests print callback", function() { + var entered = false; + var line_number = 0; + + // Setup + var mydomain = efl.registerLogDomain('mydomain', 'deadbeef'); + efl.setLogDomainRegisteredLevel(mydomain, efl.LOG_LEVEL_WARN); + + efl.setLogPrintCb(function(domain, color, level, file, func, line, msg) { + assert(domain === 'mydomain', 'log print callback incorrect domain'); + assert(color === 'deadbeef', 'log print callback incorrect color'); + assert(level === efl.LOG_LEVEL_WARN, 'log print callback incorrect level'); + assert(function(){ var components = file.split('/'); return components[components.length - 1]; }() === 'eina_js_suite.js' + , 'log print callback incorrect file'); + assert(func === 'f4', 'log print callback incorrect func'); + assert(line === line_number, 'log print callback incorrect line'); + assert(msg === 'What Happened To You', 'log print callback incorrect message'); + entered = true; + }); + + function f4() { + line_number = __line + 1; + efl.logPrint(mydomain, efl.LOG_LEVEL_WARN, 'What Happened To You'); + }; + f4(); + assert(entered === true, 'log_print callback was not called'); + +}); + +start_test("log tests levels", function(){ + efl.setLogLevel(efl.LOG_LEVEL_DBG); + assert(efl.getLogLevel() === efl.LOG_LEVEL_DBG, 'log level was not DBG'); + assert(efl.checkLogLevel(efl.LOG_LEVEL_INFO) === true, 'log level INFO was not accepted when DBG level set'); + efl.setLogLevel(efl.LOG_LEVEL_CRITICAL); + assert(efl.getLogLevel() === efl.LOG_LEVEL_CRITICAL, 'log level was not CRITICAL'); + assert(efl.checkLogLevel(efl.LOG_LEVEL_INFO) === false, 'log level INFO was accepted when CRITICAL level set'); + + assert(efl.getLogAbortOnCritical() === false, 'log abort on critical get should not be true'); + efl.setLogAbortOnCritical(true); + assert(efl.getLogAbortOnCritical() === true, 'log abort on critical should be true'); + + efl.setLogAbortOnCriticalLevel(efl.LOG_LEVEL_CRITICAL); + assert(efl.getLogAbortOnCriticalLevel() == efl.LOG_LEVEL_CRITICAL, 'log critical trigger level is not CRITICAL'); + efl.setLogAbortOnCriticalLevel(efl.LOG_LEVEL_ERR); + assert(efl.getLogAbortOnCriticalLevel() == efl.LOG_LEVEL_ERR, 'log critical trigger level is not ERR'); + + efl.setLogDomainLevel('mydomain', efl.LOG_LEVEL_WARN); + assert(efl.getLogDomainLevel('mydomain') === efl.LOG_LEVEL_WARN, 'log level for mydomain is not WARN'); + efl.setLogDomainLevel('mydomain', efl.LOG_LEVEL_INFO); + assert(efl.getLogDomainLevel('mydomain') === efl.LOG_LEVEL_INFO, 'log level for mydomain is not INFO'); + + assert(typeof(efl.LOG_STATE_START) === 'number', 'type of LOG_STATE_START is not number'); + assert(typeof(efl.LOG_STATE_STOP) === 'number', 'type of LOG_STATE_STOP is not number'); + assert(typeof(efl.logTiming) === 'function', 'type of log_timing is not function'); +}); + +start_test("log helper functions", function(){ + var messages = [ + [efl.LOG_LEVEL_CRITICAL, "critical"], + [efl.LOG_LEVEL_ERR, "error"], + [efl.LOG_LEVEL_WARN, "warning"], + [efl.LOG_LEVEL_INFO, "info"], + [efl.LOG_LEVEL_DBG, "debug"] + ]; + var caught_messages = []; + + efl.setLogLevel(efl.LOG_LEVEL_WARN); + efl.setLogAbortOnCritical(false); + + efl.setLogPrintCb(function(domain, color, level, file, func, line, msg) { + caught_messages.push([level, msg]); + }); + + efl.logCritical(messages[0][1]); + efl.logError(messages[1][1]); + efl.logWarning(messages[2][1]); + efl.logInfo(messages[3][1]); + efl.logDebug(messages[4][1]); + + assert(array_equal(messages.slice(0, 3), caught_messages), "Must received only the messages above the desired level."); +}); + +start_test("log helper wrong type", function(){ + var raised = false; + try { + efl.log_info(442); + } catch (err) { + raised = true; + assert(err.name == "TypeError", "Raised exception must be TypeError."); + } + assert(raised, "Passing anything other than a string must raise TypeError."); +}); + +start_test("log color constants", function(){ + assert(typeof efl.COLOR_LIGHTRED == "string", "efl.COLOR_LIGHTRED must be a string."); + assert(typeof efl.COLOR_RED == "string", "efl.COLOR_RED must be a string."); + assert(typeof efl.COLOR_LIGHTBLUE == "string", "efl.COLOR_LIGHTBLUE must be a string."); + assert(typeof efl.COLOR_BLUE == "string", "efl.COLOR_BLUE must be a string."); + assert(typeof efl.COLOR_GREEN == "string", "efl.COLOR_GREEN must be a string."); + assert(typeof efl.COLOR_YELLOW == "string", "efl.COLOR_YELLOW must be a string."); + assert(typeof efl.COLOR_ORANGE == "string", "efl.COLOR_ORANGE must be a string."); + assert(typeof efl.COLOR_WHITE == "string", "efl.COLOR_WHITE must be a string."); + assert(typeof efl.COLOR_LIGHTCYAN == "string", "efl.COLOR_LIGHTCYAN must be a string."); + assert(typeof efl.COLOR_CYAN == "string", "efl.COLOR_CYAN must be a string."); + assert(typeof efl.COLOR_RESET == "string", "efl.COLOR_RESET must be a string."); + assert(typeof efl.COLOR_HIGH == "string", "efl.COLOR_HIGH must be a string."); +}); + +// footer + +if (!suite_success) { + print ("[ Total tests run: %s ]", suite_ok + suite_fail.length); + print ("[ Total successful: %s ]", suite_ok); + print ("[ Total failures: %s ]", suite_fail.length); + print ("[ Tests failed: ]"); + for (var i = 0; i < suite_fail.length; i++) { + print ("[ %s]", suite_fail[i]); + }; + assert(false, "[ Test suite fail ]"); +} else { + print ("[ Test execution with success ]"); + print ("[ Total tests run: %s ]", suite_ok); +} + +exit(); diff --git a/src/tests/efl_js/eio_js_suite.cc b/src/tests/efl_js/eio_js_suite.cc new file mode 100644 index 0000000000..ba2df9d767 --- /dev/null +++ b/src/tests/efl_js/eio_js_suite.cc @@ -0,0 +1,7 @@ + +#include "suite_runner.hh" + +int main(int, char*[]) +{ + return run_script(TESTS_SRC_DIR "/eio_js_suite.js", nullptr); +} diff --git a/src/tests/efl_js/eio_js_suite.js b/src/tests/efl_js/eio_js_suite.js new file mode 100755 index 0000000000..01eb09c171 --- /dev/null +++ b/src/tests/efl_js/eio_js_suite.js @@ -0,0 +1,89 @@ +#!/usr/bin/env node + +// Preamble +function assert(condition, message) { + if (!condition) { + print("Assertion failed ", message); + throw new Error(message || "Assertion failed"); + } +} + +if(typeof process !== 'undefined') +{ + console.log('running from nodejs'); + console.log('path', process.env.NODE_PATH); + console.log("teste1"); + + efl = require('efl'); + assert(efl != null, "could not load efl node module"); + + // Setup output aliases + print = console.log; + print_error = function() { + if (process.argv.indexOf("--supress-errors") == -1) + console.error.apply(null, arguments); + }; + print_info = function() { + if (process.argv.indexOf("--verbose") != -1) + console.info.apply(null, arguments); + }; + exit = efl.ecore_mainloop_quit; +} +else +{ + assert = function(test, message) { if (test !== true) throw message; }; + print('running from libv8') + //FIXME Add levels to v8 tests + print_error = print + print_info = print + exit = function() {} +} + +// Global flag for suite success // +suite_success = true; +// Global test summary +suite_ok = 0; +suite_fail = []; // Will store the name of the failures + +// Basic test function // +function start_test(test_name, test_func) { + print("[ RUN ] eio_js_suite: " + test_name); + var test_result = true; + try { + test_func(); + } catch (e) { + suite_success = false; + test_result = false; + print_error("Error: ", e, e.stack); + } + print("[ " + (test_result ? "PASS" : "FAIL") + " ] eio_js_suite: " + test_name); + if (test_result) + suite_ok += 1; + else + suite_fail.push(test_name); +} +// end Preamble + +// Eio tests +start_test('test constants', function () { + assert(typeof(efl.EIO_FILE_COPY) === 'number'); +}); +// TODO: more tests + +// footer + +if (!suite_success) { + print ("[ Total tests run: %s ]", suite_ok + suite_fail.length); + print ("[ Total successful: %s ]", suite_ok); + print ("[ Total failures: %s ]", suite_fail.length); + print ("[ Tests failed: ]"); + for (var i = 0; i < suite_fail.length; i++) { + print ("[ %s]", suite_fail[i]); + }; + assert(false, "[ Test suite fail ]"); +} else { + print ("[ Test execution with success ]"); + print ("[ Total tests run: %s ]", suite_ok); +} + +exit(); diff --git a/src/tests/efl_js/eldbus_js_suite.cc b/src/tests/efl_js/eldbus_js_suite.cc new file mode 100644 index 0000000000..791c0c6c3c --- /dev/null +++ b/src/tests/efl_js/eldbus_js_suite.cc @@ -0,0 +1,7 @@ + +#include "suite_runner.hh" + +int main(int, char*[]) +{ + return run_script(TESTS_SRC_DIR "/eldbus_js_suite.js", nullptr); +} diff --git a/src/tests/efl_js/eldbus_js_suite.js b/src/tests/efl_js/eldbus_js_suite.js new file mode 100755 index 0000000000..30869072c4 --- /dev/null +++ b/src/tests/efl_js/eldbus_js_suite.js @@ -0,0 +1,114 @@ +#!/usr/bin/env node + +// Preamble +function assert(condition, message) { + if (!condition) { + print("Assertion failed ", message); + throw new Error(message || "Assertion failed"); + } +} + +if(typeof process !== 'undefined') +{ + console.log('running from nodejs'); + console.log('path', process.env.NODE_PATH); + console.log("teste1"); + + efl = require('efl'); + assert(efl != null, "could not load efl node module"); + + // Setup output aliases + print = console.log; + print_error = function() { + if (process.argv.indexOf("--supress-errors") == -1) + console.error.apply(null, arguments); + }; + print_info = function() { + if (process.argv.indexOf("--verbose") != -1) + console.info.apply(null, arguments); + }; + exit = efl.ecore_mainloop_quit; +} +else +{ + assert = function(test, message) { if (test !== true) throw message; }; + print('running from libv8') + //FIXME Add levels to v8 tests + print_error = print + print_info = print + exit = function() {} +} + +// Global flag for suite success // +suite_success = true; +// Global test summary +suite_ok = 0; +suite_fail = []; // Will store the name of the failures + +// Basic test function // +function start_test(test_name, test_func) { + print("[ RUN ] eldbus_js_suite: " + test_name); + var test_result = true; + try { + test_func(); + } catch (e) { + suite_success = false; + test_result = false; + print_error("Error: ", e, e.stack); + } + print("[ " + (test_result ? "PASS" : "FAIL") + " ] eldbus_js_suite: " + test_name); + if (test_result) + suite_ok += 1; + else + suite_fail.push(test_name); +} +// end Preamble + +// Eldbus core tests +start_test('test constants', function () { + assert(typeof(efl.ELDBUS_FDO_BUS) === 'string'); + assert(typeof(efl.ELDBUS_FDO_PATH) === 'string'); + assert(typeof(efl.ELDBUS_FDO_INTERFACE) === 'string'); + assert(typeof(efl.ELDBUS_FDO_INTERFACE_PROPERTIES) === 'string'); + assert(typeof(efl.ELDBUS_FDO_INTERFACE_INTROSPECTABLE) === 'string'); + assert(typeof(efl.ELDBUS_FDO_INTEFACE_PEER) === 'string'); + assert(typeof(efl.ELDBUS_ERROR_PENDING_CANCELED) === 'string'); + assert(typeof(efl.ELDBUS_ERROR_PENDING_TIMEOUT) === 'string'); +}); + +// Eldbus connection tests +start_test('test connection constants', function () { + assert(typeof(efl.ELDBUS_TIMEOUT_INFINITE) === 'number'); + assert(typeof(efl.ELDBUS_CONNECTION_TYPE_UNKNOWN) === 'number'); + assert(typeof(efl.ELDBUS_CONNECTION_TYPE_SESSION) === 'number'); + assert(typeof(efl.ELDBUS_CONNECTION_TYPE_SYSTEM) === 'number'); + assert(typeof(efl.ELDBUS_CONNECTION_TYPE_STARTER) === 'number'); + assert(typeof(efl.ELDBUS_CONNECTION_TYPE_ADDRESS) === 'number'); + assert(typeof(efl.ELDBUS_CONNECTION_TYPE_LAST) === 'number'); + assert(typeof(efl.ELDBUS_CONNECTION_EVENT_DEL) === 'number'); + assert(typeof(efl.ELDBUS_CONNECTION_EVENT_DISCONNECTED) === 'number'); + assert(typeof(efl.ELDBUS_CONNECTION_EVENT_LAST) === 'number'); +}); +// Eldbus connection + +// TODO... + +// finished tests + +// footer + +if (!suite_success) { + print ("[ Total tests run: %s ]", suite_ok + suite_fail.length); + print ("[ Total successful: %s ]", suite_ok); + print ("[ Total failures: %s ]", suite_fail.length); + print ("[ Tests failed: ]"); + for (var i = 0; i < suite_fail.length; i++) { + print ("[ %s]", suite_fail[i]); + }; + assert(false, "[ Test suite fail ]"); +} else { + print ("[ Test execution with success ]"); + print ("[ Total tests run: %s ]", suite_ok); +} + +exit(); diff --git a/src/tests/efl_js/ethumb_js_suite.cc b/src/tests/efl_js/ethumb_js_suite.cc new file mode 100644 index 0000000000..5d0149f2ff --- /dev/null +++ b/src/tests/efl_js/ethumb_js_suite.cc @@ -0,0 +1,7 @@ + +#include "suite_runner.hh" + +int main(int, char*[]) +{ + return run_script(TESTS_SRC_DIR "/ethumb_js_suite.js", nullptr); +} diff --git a/src/tests/efl_js/ethumb_js_suite.js b/src/tests/efl_js/ethumb_js_suite.js new file mode 100755 index 0000000000..5dd78fc493 --- /dev/null +++ b/src/tests/efl_js/ethumb_js_suite.js @@ -0,0 +1,93 @@ +#!/usr/bin/env node + +// Preamble +function assert(condition, message) { + if (!condition) { + print("Assertion failed ", message); + throw new Error(message || "Assertion failed"); + } +} + +if(typeof process !== 'undefined') +{ + console.log('running from nodejs'); + console.log('path', process.env.NODE_PATH); + console.log("teste1"); + + efl = require('efl'); + assert(efl != null, "could not load efl node module"); + + // Setup output aliases + print = console.log; + print_error = function() { + if (process.argv.indexOf("--supress-errors") == -1) + console.error.apply(null, arguments); + }; + print_info = function() { + if (process.argv.indexOf("--verbose") != -1) + console.info.apply(null, arguments); + }; + exit = efl.ecore_mainloop_quit; +} +else +{ + assert = function(test, message) { if (test !== true) throw message; }; + print('running from libv8') + //FIXME Add levels to v8 tests + print_error = print + print_info = print + exit = function() {} +} + +// Global flag for suite success // +suite_success = true; +// Global test summary +suite_ok = 0; +suite_fail = []; // Will store the name of the failures + +// Basic test function // +function start_test(test_name, test_func) { + print("[ RUN ] ethumb_js_suite: " + test_name); + var test_result = true; + try { + test_func(); + } catch (e) { + suite_success = false; + test_result = false; + print_error("Error: ", e, e.stack); + } + print("[ " + (test_result ? "PASS" : "FAIL") + " ] ethumb_js_suite: " + test_name); + if (test_result) + suite_ok += 1; + else + suite_fail.push(test_name); +} +// end Preamble + +efl.ethumb_client_init(); + +// Ethumb tests + +start_test('dummy test', function () { + assert(true); +}); + +efl.ethumb_client_shutdown(); + +// footer + +if (!suite_success) { + print ("[ Total tests run: %s ]", suite_ok + suite_fail.length); + print ("[ Total successful: %s ]", suite_ok); + print ("[ Total failures: %s ]", suite_fail.length); + print ("[ Tests failed: ]"); + for (var i = 0; i < suite_fail.length; i++) { + print ("[ %s]", suite_fail[i]); + }; + assert(false, "[ Test suite fail ]"); +} else { + print ("[ Test execution with success ]"); + print ("[ Total tests run: %s ]", suite_ok); +} + +exit(); diff --git a/src/tests/efl_js/suite_runner.hh b/src/tests/efl_js/suite_runner.hh new file mode 100644 index 0000000000..9686ba5e90 --- /dev/null +++ b/src/tests/efl_js/suite_runner.hh @@ -0,0 +1,147 @@ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eina.hh> + +#include <cassert> +#include <cstdlib> +#include <fstream> + +#include <Eina_Js.hh> +#include <Efl_Js.hh> + +const char* ToCString(const v8::String::Utf8Value& value) { + return *value ? *value : "<string conversion failed>"; +} + +// Executes a string within the current v8 context. +void ExecuteString(v8::Isolate* isolate, + v8::Handle<v8::String> source, + v8::Handle<v8::Value> name) +{ + efl::eina::js::compatibility_handle_scope handle_scope(isolate); + v8::TryCatch try_catch; + v8::ScriptOrigin origin(name); + v8::Handle<v8::Script> script = v8::Script::Compile(source, &origin); + if (script.IsEmpty()) { + std::cerr << "Compilation failed" << std::endl; + std::exit(-1); + } + else + { + std::cerr << "Compilation succesful" << std::endl; + v8::Handle<v8::Value> result = script->Run(); + if (result.IsEmpty()) { + std::cout << "Failed with exception thrown" << std::endl; + if(try_catch.HasCaught()) + { + if(!try_catch.Message().IsEmpty() && !try_catch.Message()->Get().IsEmpty()) + std::cerr << "Exception " << ToCString(v8::String::Utf8Value(try_catch.Message()->Get())) + << std::endl; + else + std::cerr << "Exception without message" << std::endl; + } + std::exit(-1); + } + } +} + +efl::eina::js::compatibility_return_type Print(efl::eina::js::compatibility_callback_info_type args) +{ + bool first = true; + for (int i = 0; i < args.Length(); i++) { + efl::eina::js::compatibility_handle_scope handle_scope(args.GetIsolate()); + if (first) { + first = false; + } else { + printf(" "); + } + v8::String::Utf8Value str(args[i]); + const char* cstr = ToCString(str); + printf("%s", cstr); + } + printf("\n"); + fflush(stdout); + return efl::eina::js::compatibility_return(); +} + +std::vector<char> read_script(const char* file) +{ + std::vector<char> script; + std::ifstream script_file(file); + script_file.seekg(0, std::ios::end); + std::size_t script_size = script_file.tellg(); + script_file.seekg(0, std::ios::beg); + script.resize(script_size+1); + script_file.rdbuf()->sgetn(&script[0], script_size); + auto line_break = std::find(script.begin(), script.end(), '\n'); + assert(line_break != script.end()); + ++line_break; + std::fill(script.begin(), line_break, ' '); + + std::cerr << "program:" << std::endl; + std::copy(script.begin(), script.end(), std::ostream_iterator<char>(std::cerr)); + std::cerr << "end of program" << std::endl; + + return script; +} + +int run_script(const char* file, void(*init)(v8::Handle<v8::Object>)) +{ + efl::eina::js::compatibility_initialize(); + v8::Isolate* isolate = efl::eina::js::compatibility_isolate_new(); + assert(isolate != 0); + + v8::Isolate::Scope isolate_scope(isolate); + + efl::eina::js::compatibility_handle_scope handle_scope(isolate); + v8::Handle<v8::Context> context + = efl::eina::js::compatibility_new<v8::Context> + (isolate, nullptr + , efl::eina::js::compatibility_new<v8::ObjectTemplate>(isolate)); + if (context.IsEmpty()) { + fprintf(stderr, "Error creating context\n"); + return 1; + } + context->Enter(); + { + // Enter the execution environment before evaluating any code. + v8::Context::Scope context_scope(context); + v8::Local<v8::Object> global = context->Global(); + + global->Set(efl::eina::js::compatibility_new<v8::String>(isolate, "print") + , efl::eina::js::compatibility_new<v8::FunctionTemplate>(isolate, & ::Print) + ->GetFunction()); + + std::cerr << __LINE__ << std::endl; + v8::Handle<v8::Object> exports = efl::eina::js::compatibility_new<v8::Object>(isolate); + global->Set(efl::eina::js::compatibility_new<v8::String>(isolate, "efl"), exports); + + efl_js::init(exports); + + if(init) + { + v8::Handle<v8::Object> exports = efl::eina::js::compatibility_new<v8::Object>(isolate); + global->Set(efl::eina::js::compatibility_new<v8::String>(isolate, "suite"), exports); + init(exports); + } + std::cerr << __LINE__ << std::endl; + + { + efl::eina::js::compatibility_handle_scope handle_scope(v8::Isolate::GetCurrent()); + std::cerr << __LINE__ << std::endl; + std::vector<char> script = read_script(file); + v8::Local<v8::String> name(efl::eina::js::compatibility_new<v8::String> + (nullptr, file)); + ExecuteString(v8::Isolate::GetCurrent(), + efl::eina::js::compatibility_new<v8::String> + (v8::Isolate::GetCurrent(), &script[0]), name); + std::cerr << __LINE__ << std::endl; + } + } + context->Exit(); + + return 0; +} diff --git a/src/tests/efl_js/testproj/hello.project b/src/tests/efl_js/testproj/hello.project new file mode 100644 index 0000000000..6d094fcf1d --- /dev/null +++ b/src/tests/efl_js/testproj/hello.project @@ -0,0 +1,9 @@ +{ + "Name": "test-project", + "Entry": "main.js", + "Version": "0.42", + "Sources": [ + ["main.js", "."], + ["hello.txt", "."] + ] +}
\ No newline at end of file diff --git a/src/tests/efl_js/testproj/hello.txt b/src/tests/efl_js/testproj/hello.txt new file mode 100644 index 0000000000..8fe2a4b5ad --- /dev/null +++ b/src/tests/efl_js/testproj/hello.txt @@ -0,0 +1 @@ +The quick brown fox jumps over the lazy dog.
\ No newline at end of file diff --git a/src/tests/efl_js/testproj/main.js b/src/tests/efl_js/testproj/main.js new file mode 100644 index 0000000000..e9cf00a97d --- /dev/null +++ b/src/tests/efl_js/testproj/main.js @@ -0,0 +1,5 @@ +var fs = require('fs'); + +text = fs.readFileSync('hello.txt', {encoding: 'utf8'}); + +console.log(text);
\ No newline at end of file diff --git a/src/tests/efl_js/timer.js b/src/tests/efl_js/timer.js new file mode 100644 index 0000000000..95c3011080 --- /dev/null +++ b/src/tests/efl_js/timer.js @@ -0,0 +1,33 @@ + +var efl = require('efl'); + +var loop = new efl.Ecore_Mainloop(null); + +var secondsToWait = parseFloat(process.argv[2]); + +if (isNaN(secondsToWait)) + { + secondsToWait = 2; + } + +console.log('Waiting ' + secondsToWait + ' seconds...'); + +if (false) + { + var timer = new efl.Timer(null, secondsToWait, + function(){ + console.log("Timer cb called;"); + loop.quit(); + }, null); + } +else + { + setTimeout(function(){ + console.log("Js callback called;"); + loop.quit(); + }, secondsToWait*1000); + } + +loop.begin(); + +process.exit(0);
\ No newline at end of file diff --git a/src/tests/eolian_js/constructor_method_class.eo b/src/tests/eolian_js/constructor_method_class.eo new file mode 100644 index 0000000000..f307a18fc5 --- /dev/null +++ b/src/tests/eolian_js/constructor_method_class.eo @@ -0,0 +1,59 @@ +class Constructor_Method_Class (Eo.Base) +{ + legacy_prefix: null; + data: Constructor_Method_Class_Data; + methods { + @property fail { + get { + } + values { + is_fail: bool; + } + } + constructor1 { + params { @in one: int; } + } + constructor2 { + params { @in two: double; } + } + method1 { + params { @in one: int; } + } + method2 { + params { @in one: int; } + return: int; + } + method3 { + params { @in one: int; @in two: double; } + } + method4 { + params { @in one: int; @in two: double; } + return: int; + } + outmethod1 { + params { @out one: int; } + } + outmethod2 { + params { @out one: int; } + return: int; + } + outmethod3 { + params { @out one: int; @out two: double; } + } + classoutmethod1 { + params { @in one: int; @in two: double; } + return: free(own(Constructor_Method_Class *), eo_unref) @warn_unused; + } + classoutmethod2 { + params { @in one: int; @in two: double; @out out_class: own(Constructor_Method_Class *); } + } + } + implements { + Eo.Base.constructor; + Eo.Base.finalize; + } + constructors { + .constructor1; + .constructor2; + } +} diff --git a/src/tests/eolian_js/eolian_js_suite.cc b/src/tests/eolian_js/eolian_js_suite.cc new file mode 100644 index 0000000000..cea5d19d33 --- /dev/null +++ b/src/tests/eolian_js/eolian_js_suite.cc @@ -0,0 +1,61 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Eina.hh> +#include <Eina_Js.hh> + +#include <check.h> + +#include <cassert> +#include <cstdio> +#include <cstdlib> + +#ifndef HAVE_NODEJS +#include "suite_runner.hh" +void eolian_js_test_register_eolian_js_binding(v8::Handle<v8::Object> exports); + +int main(int, char*[]) +{ + return run_script(TESTS_SRC_DIR "/eolian_js_suite.js", &eolian_js_test_register_eolian_js_binding); +} +#else +#ifdef HAVE_NODE_NODE_H +#include <node/node.h> +#elif defined(HAVE_NODEJS_DEPS_NODE_NODE_H) +#include <nodejs/deps/node/node.h> +#elif defined(HAVE_NODEJS_DEPS_NODE_INCLUDE_NODE_H) +#include <nodejs/deps/node/include/node.h> +#elif defined(HAVE_NODEJS_SRC_NODE_H) +#include <nodejs/src/node.h> +#elif defined(HAVE_NODE_H) +#include <node.h> +#else +#error We must have at least one node header to include +#endif +void eolian_js_test_register_eolian_js_binding(v8::Handle<v8::Object> exports); + +namespace { + +void eolian_js_module_init(v8::Handle<v8::Object> exports) +{ + fprintf(stderr, "test suite eolian_js_module_init\n"); fflush(stderr); + try + { + eina_init(); + eo_init(); + eolian_js_test_register_eolian_js_binding(exports); + std::cerr << "registered" << std::endl; + } + catch(...) + { + std::cerr << "Error" << std::endl; + std::abort(); + } +} + +} + +NODE_MODULE(eolian_js_suite_mod, ::eolian_js_module_init) + +#endif diff --git a/src/tests/eolian_js/eolian_js_suite.js b/src/tests/eolian_js/eolian_js_suite.js new file mode 100755 index 0000000000..146127323e --- /dev/null +++ b/src/tests/eolian_js/eolian_js_suite.js @@ -0,0 +1,796 @@ +#!/usr/bin/env node + +// Preamble // +function assert(condition, message) { + if (!condition) { + print("Assertion failed ", message); + throw new Error(message || "Assertion failed"); + } +} + +if(typeof process !== 'undefined') +{ + console.log('running from nodejs'); + console.log('path', process.env.NODE_PATH); + console.log("teste1"); + + efl = require('efl'); + assert(efl != null, "could not load efl node module"); + + // Setup output aliases + print = console.log; + printError = function() { + if (process.argv.indexOf("--supress-errors") == -1) + console.error.apply(null, arguments); + }; + printInfo = function() { + if (process.argv.indexOf("--verbose") != -1) + console.info.apply(null, arguments); + }; + exit = efl.ecore_mainloop_quit; +} +else +{ + assert = function(test, message) { if (test !== true) throw message; }; + print('running from libv8') + //FIXME Add levels to v8 tests + printError = print + printInfo = print + exit = function() {} +} + +// Global flag for suite success // +suiteSuccess = true; +// Global test summary +suiteOk = 0; +suiteFail = []; // Will store the name of the failures + +// Basic test function // +function startTest(testName, testFunc) { + print("[ RUN ] eolian_js_suite: " + testName); + var testResult = true; + try { + testFunc(); + } catch (e) { + suiteSuccess = false; + testResult = false; + printError("Error: ", e, e.stack); + } + print("[ " + (testResult ? "PASS" : "FAIL") + " ] eolian_js_suite: " + testName); + if (testResult) + suiteOk += 1; + else + suiteFail.push(testName); +} +// end Preamble + +// eolian Preamble +if (typeof process != "undefined") +{ + suite = require('eolian_js_suite_mod'); + assert(suite != null, "could not load eolian_js_suite_mod"); + ConstructorMethodClass = suite.ConstructorMethodClass; + TestObject = suite.Test.Object; +} +else +{ + ConstructorMethodClass = suite.ConstructorMethodClass; + TestObject = suite.Test.Object; +} + +function expectException(func) { + var exceptionCaught = false; + try { + func(); + } catch (e) { + exceptionCaught = true; + } + assert(exceptionCaught, "Exception expected but not thrown!"); +} +// end eolian Preamble + +// Test cases // +startTest("constructor_null_parent", function() { + var obj = new TestObject(null); + assert(obj !== null); +}); + +startTest("integral_in_and_out_parameters", function() { + var obj = new TestObject(null); + + var expectedValue = 1234; + obj.methodIntegralInA(expectedValue); + + var actualValue = obj.methodIntegralOutA(); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); +}); + +startTest("integral_inout_parameter", function() { + var obj = new TestObject(null); + + var expectedValue = 1234; + var actualValue = obj.methodIntegralInout(-expectedValue); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); + + var expectedValue = -4321; + var actualValue = obj.methodIntegralInout(-expectedValue); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); +}); + +startTest("integral_return_value", function() { + var obj = new TestObject(null); + + var expectedValue = 1234; + obj.methodIntegralInA(expectedValue); + + var actualValue = obj.methodIntegralReturnA(); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); +}); + +startTest("more_parameters_than_expected_is_ok", function() { + var obj = new TestObject(null); + var expectedValue = 1234; + obj.methodIntegralInA(expectedValue, 4321); + + var actualValue = obj.methodIntegralOutA(); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); +}); + +startTest("less_parameters_that_expected_fails", function() { + var obj = new TestObject(null); + expectException(function() { + obj.methodIntegralInA(); + }); +}); + +startTest("wrong_parameter_type_fails", function() { + var obj = new TestObject(null); + expectException(function() { + obj.methodIntegralInA('string'); + }); +}); + +startTest("mixed_in_out_and_result", function() { + var obj = new TestObject(null); + var ret = obj.methodDivMod(7, 3); + var success = ret[0]; + var quotient = ret[1]; + var remainder = ret[2]; + assert(success); + assert(2 == quotient); + assert(1 == remainder); + + ret = obj.methodDivMod(42, 0); + success = ret[0]; + assert(!success); +}); + +startTest("boolean", function() { + var obj = new TestObject(null); + var ret = obj.methodAnd(false, false); + assert(ret == false); + ret = obj.methodAnd(false, true); + assert(ret == false); + ret = obj.methodAnd(true, false); + assert(ret == false); + ret = obj.methodAnd(true, true); + assert(ret); +}); + +startTest("floating_point", function() { + var obj = new TestObject(null); + var ret = obj.methodModf(3.14159); + assert(Math.abs(ret[0] - 0.14159) < 0.00001, "Math.abs(ret[0] - 0.14159) < 0.00001 (" + Math.abs(ret[0] - 0.14159) + " < 0.00001)"); + assert(ret[1] == 3, "ret[1] == 3 (" + ret[1] + " == 3)"); +}); + +startTest("string_inout", function() { + var obj = new TestObject(null); + var ret = obj.methodUppercase('hello world'); + assert(ret == "HELLO WORLD", "ret == " + ret); +}); + +startTest("in_null_string", function() { + var obj = new TestObject(null); + var success = obj.methodInNull(null); + assert(success, "success == " + success); +}); + + +startTest("out_null_string", function() { + var obj = new TestObject(null); + var ret = obj.methodOutNull(); + assert(ret[0], "success == " + ret[0]); + assert(ret[1] === null, "output == " + ret[1]); +}); + + +startTest("inout_null_string", function() { + var obj = new TestObject(null); + var ret = obj.methodInoutNull(null); + assert(ret[0], "success == " + ret[0]); + assert(ret[1] === null, "output == " + ret[1]); +}); + + +startTest("return_null_string", function() { + var obj = new TestObject(null); + var ret = obj.methodReturnNull(); + assert(ret === null, "ret == " + ret); +}); + + +startTest("null_values", function() { + var obj = new TestObject(null); + var ret = obj.methodNull(null, null); + assert(ret[0] === null, "ret == " + ret[0]); + assert(ret[1] === null, "ret == " + ret[1]); + assert(ret[2] === null, "ret == " + ret[2]); +}); + +startTest("enum_values", function() { + var obj = new TestObject(null); + var ret = obj.methodInEnumReturnEnum(suite.Test.EnumEx.SECOND); + assert(ret === suite.Test.EnumEx.SECOND); + var value = suite.Test.EnumEx.THIRD; + assert(value === 2); + ret = obj.methodInEnumReturnEnum(value); + assert(ret === value); +}); + +startTest("struct_values", function() { + var obj = new TestObject(null); + var newStruct = new suite.Test.StructEx; + newStruct.valueInt = 42; + newStruct.valueEnum = suite.Test.EnumEx.FOURTH; + var ret = newStruct.valueInt; + assert(ret === 42); + ret = newStruct.valueEnum; + assert(ret === suite.Test.EnumEx.FOURTH); + ret = obj.methodInStructReturnStruct(newStruct); + assert(ret.valueInt === 42); + assert(ret.valueEnum === suite.Test.EnumEx.FOURTH); +}); + +startTest("event_simple", function() { + var v = false; + var obj = new TestObject(null); + var ret = obj.on + ("test", + function() + { + printInfo('Event called') + v = true; + } + ); + printInfo('going to call event'); + obj.callEvent(); + printInfo('is event called?'); + assert(v); +}); + +startTest("event_object_call", function() { + var v = false; + var obj = new TestObject(null); + var ret = obj.on + ("test", + function() + { + printInfo('Event called'); + var o = arguments[0]; + assert(o != null); + var expectedValue = 1234; + o.methodIntegralInA(expectedValue); + var actualValue = o.methodIntegralOutA(); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); + v = true; + } + ); + printInfo('going to call event'); + obj.callEvent(); + printInfo('is event called?'); + assert(v); +}); + +startTest("event_structarg", function() { + var v = false; + var obj = new TestObject(null); + var ret = obj.on + ("test_structarg", + function() + { + printInfo('Event called'); + var s = arguments[1]; + assert(s != null); + assert(s.valueInt === 42); + assert(s.valueEnum === suite.Test.EnumEx.THIRD); + v = true; + } + ); + printInfo('going to call event'); + obj.callEvent(); + printInfo('is event called?'); + assert(v); +}); + +startTest("event_stringarg", function() { + var v = false; + var obj = new TestObject(null); + var ret = obj.on + ("test_stringarg", + function() + { + printInfo('Event called'); + var s = arguments[1]; + assert(s === "foo"); + v = true; + } + ); + printInfo('going to call event'); + obj.callEvent(); + printInfo('is event called?'); + assert(v); +}); + +// // TODO: disabled. Not implemented yet +// startTest("integral_array", function() { +// var obj = new TestObject(null); +// var ret = obj.methodArrayAt([1, 2, 3, 4, 5], 1); +// assert(ret == 2, "ret == " + ret); +// }); + +startTest("array_in_array_out", function() { + var obj = new TestObject(null); + var newArray = obj.methodArrayWith42(); + assert(newArray != null); + var arr = obj.methodArrayInArrayOut(newArray); + assert(arr != null); + assert(arr[0] === 42); + assert(newArray[0] === arr[0]); +}); + +startTest("method_array_of_objects", function() { + var obj = new TestObject(null); + var arr = obj.methodArrayOfObjects(null); + assert(arr != null); + assert(arr[0] != null); + arr = obj.methodArrayOfObjects(arr); + assert(arr != null); + var v = arr[0]; + assert(v != null); + // assert(v == obj); // TODO: check if same Eo object pointer? + var expectedValue = 1234; + v.methodIntegralInA(expectedValue); + var actualValue = v.methodIntegralOutA(); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); +}); + +// FIXME +// startTest("method_array_of_strings", function() { +// var obj = new TestObject(null); +// var arr = obj.methodArrayOfStrings(null); +// assert(arr != null); +// assert(arr[0] === "foo"); +// arr = obj.methodArrayOfStrings(arr); +// assert(arr != null); +// assert(arr[0] === "foo"); +// }); + +startTest("method_array_of_ints", function() { + var obj = new TestObject(null); + var arr = obj.methodArrayOfInts(null); + assert(arr != null); + assert(arr[0] === 42); + arr = obj.methodArrayOfInts(arr); + assert(arr != null); + assert(arr[0] === 42); +}); + +startTest("method_array_of_bools", function() { + var obj = new TestObject(null); + var arr = obj.methodArrayOfBools(null); + assert(arr != null); + assert(arr[0] === true); + arr = obj.methodArrayOfBools(arr); + assert(arr != null); + assert(arr[0] === true); +}); + +startTest("method_array_of_doubles", function() { + var obj = new TestObject(null); + var arr = obj.methodArrayOfDoubles(null); + assert(arr != null); + assert(arr[0] === 42.0); + arr = obj.methodArrayOfDoubles(arr); + assert(arr != null); + assert(arr[0] === 42.0); +}); + +startTest("method_array_of_enums", function() { + var obj = new TestObject(null); + var arr = obj.methodArrayOfEnums(null); + assert(arr != null); + assert(arr[0] === suite.Test.EnumEx.THIRD); + arr = obj.methodArrayOfEnums(arr); + assert(arr != null); + assert(arr[0] === suite.Test.EnumEx.THIRD); +}); + +startTest("method_array_of_structs", function() { + var obj = new TestObject(null); + var arr = obj.methodArrayOfStructs(null); + assert(arr != null); + var s = arr[0]; + assert(s != null); + assert(s.valueInt === 42); + assert(s.valueEnum === suite.Test.EnumEx.THIRD); + arr = obj.methodArrayOfStructs(arr); + s = arr[0]; + assert(s != null); + assert(s.valueInt === 42); + assert(s.valueEnum === suite.Test.EnumEx.THIRD); +}); + +startTest("list_in_list_out", function() { + var obj = new TestObject(null); + var newList = obj.methodListWith42(); + assert(newList != null); + var lis = obj.methodListInListOut(newList); + assert(lis != null); + // assert(lis == newList); // TODO: check same list pointer? + assert(lis[0] === 42); + assert(newList[0] === lis[0]); +}); + +startTest("method_list_of_objects", function() { + var obj = new TestObject(null); + var lis = obj.methodListOfObjects(null); + assert(lis != null); + assert(lis[0] != null); + lis = obj.methodListOfObjects(lis); + assert(lis != null); + var v = lis[0]; + assert(v != null); + // assert(v == obj); // TODO: check if same Eo object pointer? + var expectedValue = 1234; + v.methodIntegralInA(expectedValue); + var actualValue = v.methodIntegralOutA(); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); +}); + +// FIXME +// startTest("method_list_of_strings", function() { +// var obj = new TestObject(null); +// var lis = obj.methodListOfStrings(null); +// assert(lis != null); +// assert(lis[0] === "foo"); +// lis = obj.methodListOfStrings(lis); +// assert(lis != null); +// assert(lis[0] === "foo"); +// }); + +startTest("method_list_of_ints", function() { + var obj = new TestObject(null); + var lis = obj.methodListOfInts(null); + assert(lis != null); + assert(lis[0] === 42); + lis = obj.methodListOfInts(lis); + assert(lis != null); + assert(lis[0] === 42); +}); + +startTest("method_list_of_bools", function() { + var obj = new TestObject(null); + var lis = obj.methodListOfBools(null); + assert(lis != null); + assert(lis[0] === true); + lis = obj.methodListOfBools(lis); + assert(lis != null); + assert(lis[0] === true); +}); + +startTest("method_list_of_doubles", function() { + var obj = new TestObject(null); + var lis = obj.methodListOfDoubles(null); + assert(lis != null); + assert(lis[0] === 42.0); + lis = obj.methodListOfDoubles(lis); + assert(lis != null); + assert(lis[0] === 42.0); +}); + +startTest("method_list_of_enums", function() { + var obj = new TestObject(null); + var lis = obj.methodListOfEnums(null); + assert(lis != null); + assert(lis[0] === suite.Test.EnumEx.THIRD); + lis = obj.methodListOfEnums(lis); + assert(lis != null); + assert(lis[0] === suite.Test.EnumEx.THIRD); +}); + +startTest("method_list_of_structs", function() { + var obj = new TestObject(null); + var lis = obj.methodListOfStructs(null); + assert(lis != null); + var s = lis[0]; + assert(s != null); + assert(s.valueInt === 42); + assert(s.valueEnum === suite.Test.EnumEx.THIRD); + lis = obj.methodListOfStructs(lis); + s = lis[0]; + assert(s != null); + assert(s.valueInt === 42); + assert(s.valueEnum === suite.Test.EnumEx.THIRD); +}); + +startTest("method_accessor_of_objects", function() { + var obj = new TestObject(null); + var acc = obj.methodAccessorOfObjects(null); + assert(acc != null); + assert(acc.get(0) != null); + acc = obj.methodAccessorOfObjects(acc); + assert(acc != null); + var v = acc.get(0); + assert(v != null); + var expectedValue = 1234; + v.methodIntegralInA(expectedValue); + var actualValue = v.methodIntegralOutA(); + assert(actualValue == expectedValue, actualValue + " == " + expectedValue); +}); + +// FIXME +// startTest("method_accessor_of_strings", function() { +// var obj = new TestObject(null); +// var acc = obj.methodAccessorOfStrings(null); +// assert(acc != null); +// assert(acc.get(0) === "foo"); +// acc = obj.methodAccessorOfStrings(acc); +// assert(acc != null); +// assert(acc.get(0) === "foo"); +// }); + +startTest("method_accessor_of_ints", function() { + var obj = new TestObject(null); + var acc = obj.methodAccessorOfInts(null); + assert(acc != null); + assert(acc.get(0) === 42); + acc = obj.methodAccessorOfInts(acc); + assert(acc != null); + assert(acc.get(0) === 42); +}); + +startTest("method_accessor_of_bools", function() { + var obj = new TestObject(null); + var acc = obj.methodAccessorOfBools(null); + assert(acc != null); + assert(acc.get(0) === true); + acc = obj.methodAccessorOfBools(acc); + assert(acc != null); + assert(acc.get(0) === true); +}); + +startTest("method_accessor_of_doubles", function() { + var obj = new TestObject(null); + var acc = obj.methodAccessorOfDoubles(null); + assert(acc != null); + assert(acc.get(0) === 42.0); + acc = obj.methodAccessorOfDoubles(acc); + assert(acc != null); + assert(acc.get(0) === 42.0); +}); + +startTest("method_accessor_of_enums", function() { + var obj = new TestObject(null); + var acc = obj.methodAccessorOfEnums(null); + assert(acc != null); + assert(acc.get(0) === suite.Test.EnumEx.THIRD); + acc = obj.methodAccessorOfEnums(acc); + assert(acc != null); + assert(acc.get(0) === suite.Test.EnumEx.THIRD); +}); + +startTest("method_accessor_of_structs", function() { + var obj = new TestObject(null); + var acc = obj.methodAccessorOfStructs(null); + assert(acc != null); + var s = acc.get(0); + assert(s != null); + assert(s.valueInt === 42); + assert(s.valueEnum === suite.Test.EnumEx.THIRD); + acc = obj.methodAccessorOfStructs(acc); + assert(acc != null); + s = acc.get(0); + assert(s != null); + assert(s.valueInt === 42); + assert(s.valueEnum === suite.Test.EnumEx.THIRD); +}); + +// Combinations of complex types // + +// FIXME +// startTest("method_array_of_arrays_of_ints", function() { +// var obj = new TestObject(null); +// var arr = obj.methodArrayOfArraysOfInts(null); +// assert(arr != null); +// var a = arr[0]; +// assert(a != null); +// assert(a[0] === 42); +// arr = obj.methodArrayOfArraysOfInts(arr); +// assert(arr != null); +// a = arr[0]; +// assert(a != null); +// assert(a[0] === 42); +// }); + +// FIXME +// startTest("method_list_of_lists_of_ints", function() { +// var obj = new TestObject(null); +// var lis = obj.methodListOfListsOfInts(null); +// assert(lis != null); +// var l = lis[0]; +// assert(l != null); +// assert(l[0] === 42); +// lis = obj.methodListOfListsOfInts(lis); +// assert(lis != null); +// l = lis[0]; +// assert(l != null); +// assert(l[0] === 42); +// }); + +// FIXME +// startTest("method_array_of_lists_of_ints", function() { +// var obj = new TestObject(null); +// var arr = obj.methodArrayOfListsOfInts(null); +// assert(arr != null); +// var l = arr[0]; +// assert(l != null); +// assert(l[0] === 42); +// arr = obj.methodArrayOfListsOfInts(arr); +// assert(arr != null); +// l = arr[0]; +// assert(l != null); +// assert(l[0] === 42); +// }); + +// FIXME +// startTest("method_list_of_arrays_of_ints", function() { +// var obj = new TestObject(null); +// var lis = obj.methodListOfArraysOfInts(null); +// assert(lis != null); +// var a = lis[0]; +// assert(a != null); +// assert(a[0] === 42); +// lis = obj.methodListOfArraysOfInts(lis); +// assert(lis != null); +// a = lis[0]; +// assert(a != null); +// assert(a[0] === 42); +// }); + +startTest("new Constructor_Method_Class", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + assert(obj); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("Constructor_Method_Class method1", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + obj.method1(2); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("Constructor_Method_Class method2", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + var r = obj.method2(3); + assert(r === 5); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("Constructor_Method_Class method3", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + obj.method3(3, 11.1); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("Constructor_Method_Class method4", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + var r = obj.method4(3, 11.1); + assert(r == 5); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("Constructor_Method_Class method3 less parameters than expected", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + expectException(function() { + obj.method3(3); + }); +}); + +startTest("Constructor_Method_Class constructor less parameters than expected", function() { + expectException(function() { + var obj = new ConstructorMethodClass(null, 5); + }); +}); + +startTest("Constructor_Method_Class constructor wrong parameter types", function() { + expectException(function() { + var obj = new ConstructorMethodClass(null, 5.1, 10); + }); +}); + +// Out parameters // + +startTest("Constructor_Method_Class outmethod1", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + var r = obj.outmethod1(); + assert(r == 5); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("Constructor_Method_Class outmethod2", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + var r = obj.outmethod2(); + assert(Array.isArray(r)); + printInfo("Return is array from outmethod2"); + assert(r[0] == 11); + assert(r[1] == 10); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("Constructor_Method_Class outmethod3", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + var r = obj.outmethod3(); + assert(Array.isArray(r)); + printInfo("Return is array from outmethod3"); + assert(r[0] == 11); + assert(r[1] == 5.1); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("Constructor_Method_Class classoutmethod1", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + var c = obj.classoutmethod1(5, 10.0); + assert(c); + var r = c.method4(3, 11.1); + assert(r == 5); + assert(c.getFail() == false, "object fail flag set"); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("Constructor_Method_Class classoutmethod2", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + printInfo('1'); + var c = obj.classoutmethod2(5, 10.0); + assert(c); + var r = c.method4(3, 11.1); + assert(r); + assert(r == 5); + assert(c.getFail() == false, "object fail flag set"); + assert(obj.getFail() == false, "object fail flag set"); +}); + +startTest("cast", function() { + var obj = new ConstructorMethodClass(null, 5, 10.0); + var c = obj.classoutmethod1(5, 10.0); + print('classoutmethod1'); + assert(c); + var d = c.cast('Constructor_Method_Class'); + assert(d); +}); + +if (!suiteSuccess) { + print ("[ Total tests run: %s ]", suiteOk + suiteFail.length); + print ("[ Total successful: %s ]", suiteOk); + print ("[ Total failures: %s ]", suiteFail.length); + print ("[ Tests failed: ]"); + for (var i = 0; i < suiteFail.length; i++) { + print ("[ %s]", suiteFail[i]); + }; + assert(false, "[ Test suite fail ]"); +} else { + print ("[ Test execution with success ]"); + print ("[ Total tests run: %s ]", suiteOk); +} + +exit(); diff --git a/src/tests/eolian_js/eolian_js_test_constructor_method_impl.c b/src/tests/eolian_js/eolian_js_test_constructor_method_impl.c new file mode 100644 index 0000000000..1f454ebbf2 --- /dev/null +++ b/src/tests/eolian_js/eolian_js_test_constructor_method_impl.c @@ -0,0 +1,147 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eo.h> +#include <Ecore.h> + +#include <stdlib.h> + +#include "constructor_method_class.eo.h" + +#include <check.h> + +struct _Constructor_Method_Class_Data +{ + Eina_Bool fail; +}; +typedef struct _Constructor_Method_Class_Data Constructor_Method_Class_Data; + +#define MY_CLASS CONSTRUCTOR_METHOD_CLASS_CLASS + +EOLIAN static Eo_Base * +_constructor_method_class_eo_base_constructor(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd) +{ + pd->fail = EINA_FALSE; + return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor()); +} + +EOLIAN static void +_constructor_method_class_constructor1(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd, int one) +{ + fprintf(stderr, "one == %d\n", one); + fflush(stderr); + if (one != 5) + pd->fail = EINA_TRUE; +} + +EOLIAN static void +_constructor_method_class_constructor2(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd, double two) +{ + fprintf(stderr, "two == %f\n", two); + fflush(stderr); + if (two != 10.0) + pd->fail = EINA_TRUE; +} + +EOLIAN static Eo * +_constructor_method_class_eo_base_finalize(Eo *obj, Constructor_Method_Class_Data *pd) +{ + if (pd->fail) + return NULL; + + return eo_do_super_ret(obj, MY_CLASS, obj, eo_finalize()); +} + +EOLIAN static Eina_Bool +_constructor_method_class_fail_get(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd) +{ + return pd->fail; +} + +EOLIAN static void +_constructor_method_class_method1(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd, int one) +{ + fprintf(stderr, "method1 one == %d\n", one); + fflush(stderr); + if (one != 2) + pd->fail = EINA_TRUE; +} + +EOLIAN static int +_constructor_method_class_method2(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd, int one) +{ + fprintf(stderr, "method2 one == %d\n", one); + fflush(stderr); + if (one != 3) + pd->fail = EINA_TRUE; + return 5; +} + +EOLIAN static void +_constructor_method_class_method3(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd, int one, double two) +{ + fprintf(stderr, "method3 one == %d two == %f\n", one, two); + fflush(stderr); + if (one != 3) + pd->fail = EINA_TRUE; + if (two != 11.1) + pd->fail = EINA_TRUE; +} + +EOLIAN static int +_constructor_method_class_method4(Eo * obj EINA_UNUSED, Constructor_Method_Class_Data *pd, int one, double two) +{ + fprintf(stderr, "method4 one == %d two == %f\n", one, two); + fflush(stderr); + if (one != 3) + pd->fail = EINA_TRUE; + if (two != 11.1) + pd->fail = EINA_TRUE; + return 5; +} + +EOLIAN static void +_constructor_method_class_outmethod1(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd EINA_UNUSED, int *one) +{ + fprintf(stderr, "outmethod1\n"); + fflush(stderr); + *one = 5; +} + +EOLIAN static int +_constructor_method_class_outmethod2(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd EINA_UNUSED, int *one) +{ + fprintf(stderr, "outmethod2\n"); + fflush(stderr); + *one = 10; + return 11; +} + +EOLIAN static void +_constructor_method_class_outmethod3(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd EINA_UNUSED, int *one, double *two) +{ + fprintf(stderr, "outmethod3\n"); + fflush(stderr); + *one = 11; + *two = 5.1; +} + +EOLIAN static Constructor_Method_Class * +_constructor_method_class_classoutmethod1(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd EINA_UNUSED, int one, double two) +{ + fprintf(stderr, "classoutmethod1\n"); + fflush(stderr); + return eo_add(MY_CLASS, NULL, constructor_method_class_constructor1(one), constructor_method_class_constructor2(two)); +} + +EOLIAN static void +_constructor_method_class_classoutmethod2(Eo* obj EINA_UNUSED, Constructor_Method_Class_Data *pd EINA_UNUSED, int one, double two, Constructor_Method_Class **out_class) +{ + fprintf(stderr, "classoutmethod2\n"); + fflush(stderr); + *out_class = eo_add(MY_CLASS, NULL, constructor_method_class_constructor1(one), constructor_method_class_constructor2(two)); +} + + +#include <constructor_method_class.eo.c> diff --git a/src/tests/eolian_js/eolian_js_test_eolian_js_binding.cc b/src/tests/eolian_js/eolian_js_test_eolian_js_binding.cc new file mode 100644 index 0000000000..dbdd016a34 --- /dev/null +++ b/src/tests/eolian_js/eolian_js_test_eolian_js_binding.cc @@ -0,0 +1,44 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eo_Js.hh> +#include <Eina.hh> +#include <Eo.hh> + +#include <check.h> + + +#include <iostream> +#include <cassert> +#include <fstream> + +typedef struct _Elm_Calendar_Mark Elm_Calendar_Mark; + +#include "constructor_method_class.eo.js.cc" +#include "test_object.eo.js.cc" + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# define EAPI __declspec(dllimport) +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +void eolian_js_test_register_eolian_js_binding(v8::Handle<v8::Object> exports) +{ + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + test::register_object(exports, isolate); + register_constructor_method_class(exports, isolate); +} diff --git a/src/tests/eolian_js/eolian_js_test_evas_box.cc b/src/tests/eolian_js/eolian_js_test_evas_box.cc new file mode 100644 index 0000000000..e859f2a24f --- /dev/null +++ b/src/tests/eolian_js/eolian_js_test_evas_box.cc @@ -0,0 +1,151 @@ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <Eo_Js.hh> +#include <Eina.hh> +#include <Eo.hh> + +#include <check.h> + +#include <iostream> + +#include <cassert> +#include <tuple> + +namespace evas { +EAPI void register_box(v8::Handle<v8::Object> global, v8::Isolate* isolate); +} + +namespace { + +static const char script[] = + "function assert(condition, message) {\n" + " if (!condition) {\n" + " print(\"Assertion failed \", message);\n" + " throw message || \"Assertion failed\";\n" + " }\n" + "}\n" + "print(\"teste\");\n" + "x = new Box();\n" + ; + +const char* ToCString(const v8::String::Utf8Value& value) { + return *value ? *value : "<string conversion failed>"; +} + +// Executes a string within the current v8 context. +bool ExecuteString(v8::Isolate* isolate, + v8::Handle<v8::String> source, + v8::Handle<v8::Value> name) +{ + efl::eina::js::compatibility_handle_scope handle_scope(isolate); + v8::TryCatch try_catch; + v8::ScriptOrigin origin(name); + v8::Handle<v8::Script> script = v8::Script::Compile(source, &origin); + if (script.IsEmpty()) { + std::abort(); + // Print errors that happened during compilation. + // if (report_exceptions) + // ReportException(isolate, &try_catch); + return false; + } + else + { + v8::Handle<v8::Value> result = script->Run(); + if (result.IsEmpty()) { + std::cout << "Failed with exception thrown" << std::endl; + assert(try_catch.HasCaught()); + std::abort(); + // Print errors that happened during execution. + // if (report_exceptions) + // ReportException(isolate, &try_catch); + return false; + } else { + assert(!try_catch.HasCaught()); + // if (print_result && !result->IsUndefined()) { + // // If all went well and the result wasn't undefined then print + // // the returned value. + // v8::String::Utf8Value str(result); + // const char* cstr = ToCString(str); + // printf("%s\n", cstr); + // } + return true; + } + } +} + +efl::eina::js::compatibility_return_type Print(efl::eina::js::compatibility_callback_info_type args) { + bool first = true; + for (int i = 0; i < args.Length(); i++) { + efl::eina::js::compatibility_handle_scope handle_scope(args.GetIsolate()); + if (first) { + first = false; + } else { + printf(" "); + } + v8::String::Utf8Value str(args[i]); + const char* cstr = ToCString(str); + printf("%s", cstr); + } + printf("\n"); + fflush(stdout); +} + +START_TEST(eolian_js_test_evas_box) +{ + int argc = 1; + const char* argv[] = {"test"}; + efl::eina::eina_init eina_init; + efl::eo::eo_init eo_init; + + //v8::V8::InitializeICU(); + v8::V8::Initialize(); + v8::V8::SetFlagsFromCommandLine(&argc, const_cast<char**>(argv), true); + + v8::Isolate* isolate = efl::eina::js::compatibility_isolate_new(); + + v8::Isolate::Scope isolate_scope(isolate); + + assert(isolate != 0); + + v8::Handle<v8::Context> context; + efl::eina::js::compatibility_handle_scope handle_scope(isolate); + + { + // Create a template for the global object. + v8::Handle<v8::ObjectTemplate> global = efl::eina::js::compatibility_new<v8::ObjectTemplate>(isolate); + // Bind the global 'print' function to the C++ Print callback. + global->Set(efl::eina::js::compatibility_new<v8::String>(isolate, "print"), + efl::eina::js::compatibility_new<v8::FunctionTemplate>(isolate, Print)); + + context = efl::eina::js::compatibility_new<v8::Context>(isolate, nullptr, global); + + } + if (context.IsEmpty()) { + fprintf(stderr, "Error creating context\n"); + } + context->Enter(); + { + // Enter the execution environment before evaluating any code. + v8::Context::Scope context_scope(context); + v8::Local<v8::String> name(efl::eina::js::compatibility_new<v8::String>(/*context->GetIsolate()*/nullptr, "(shell)")); + + evas::register_box(context->Global(), isolate); + + efl::eina::js::compatibility_handle_scope handle_scope(/*context->GetIsolate()*/nullptr); + ExecuteString(/*context->GetIsolate()*/isolate, + efl::eina::js::compatibility_new<v8::String>/*FromUtf8*/(/*context->GetIsolate()*/nullptr, script), + name); + } + context->Exit(); +} +END_TEST + +} + +void eolian_js_test_evas_box(TCase* tc) +{ + tcase_add_test(tc, eolian_js_test_evas_box); +} 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 new file mode 100644 index 0000000000..6f35b7ecdd --- /dev/null +++ b/src/tests/eolian_js/eolian_js_test_test_object_impl.c @@ -0,0 +1,620 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Eo.h> +#include <Ecore.h> + +#include "test_object.eo.h" + +#include <check.h> + +#include <assert.h> +#include <ctype.h> +#include <math.h> +#include <stdlib.h> + +struct _Test_Object_Data +{ + int a; +}; + +typedef struct _Test_Object_Data Test_Object_Data; + +#define MY_CLASS TEST_OBJECT_CLASS + +EOLIAN static Eo_Base * +_test_object_eo_base_constructor(Eo* obj, Test_Object_Data *pd) +{ + fprintf(stdout, "_test_object_eo_base_constructor\n"); + + pd->a = 0; + return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor()); +} + +EOLIAN static Eo * +_test_object_eo_base_finalize(Eo *obj, Test_Object_Data *pd EINA_UNUSED) +{ + fprintf(stdout, "_test_object_eo_base_finalize\n"); + + return eo_do_super_ret(obj, MY_CLASS, obj, eo_finalize()); +} + +EOLIAN static void +_test_object_eo_base_destructor(Eo* obj, Test_Object_Data *pd EINA_UNUSED) +{ + fprintf(stdout, "_test_object_eo_base_destructor\n"); + eo_do_super(obj, MY_CLASS, eo_destructor()); +} + + +EOLIAN static void +_test_object_method_integral_in_a(Eo* obj EINA_UNUSED, + Test_Object_Data *pd, + int a) +{ + fprintf(stdout, "_test_object_method_integral_in_a(%d)\n", a); + pd->a = a; +} + +EOLIAN static void +_test_object_method_integral_out_a(Eo* obj EINA_UNUSED, + Test_Object_Data *pd, + int *a) +{ + fprintf(stdout, "_test_object_method_integral_out_a(%p)\n", a); + *a = pd->a; +} + +EOLIAN static void +_test_object_method_integral_inout(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + int *a) +{ + fprintf(stdout, "_test_object_method_integral_inout(%d [%p])\n", *a, a); + *a = -(*a); +} + +EOLIAN static int +_test_object_method_integral_return_a(Eo* obj EINA_UNUSED, + Test_Object_Data *pd) +{ + fprintf(stdout, "_test_object_method_integral_return_a()\n"); + return pd->a; +} + +EOLIAN static Eina_Bool +_test_object_method_div_mod(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + int a, + int b, + int *quotient, + int *remainder) +{ + fprintf(stdout, "_test_object_method_div_mod(%d, %d, %p, %p)\n", a, b, quotient, remainder); + if (0 == b) return EINA_FALSE; + *quotient = a / b; + *remainder = a % b; + return EINA_TRUE; +} + +EOLIAN static Eina_Bool +_test_object_method_and(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Bool a, + Eina_Bool b) +{ + fprintf(stdout, "_test_object_method_and(%d, %d)\n", a, b); + return a && b; +} + +EOLIAN static double +_test_object_method_modf(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + double x, + double *int_part) +{ + fprintf(stdout, "_test_object_method_modf(%f, %p)\n", x, int_part); + return modf(x, int_part); +} + +EOLIAN static void +_test_object_method_uppercase(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + char **str) +{ + fprintf(stdout, "_test_object_method_uppercase('%s')\n", *str); + if (!*str) return; + + char *p = *str; + while ('\0' != *p) + { + *p = toupper(*p); + p++; + } +} + +EOLIAN static Eina_Bool +_test_object_method_in_null(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + char *a) +{ + fprintf(stdout, "_test_object_method_in_null(%p)\n", a); + return NULL == a; +} + +EOLIAN static Eina_Bool +_test_object_method_out_null(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + char **a) +{ + fprintf(stdout, "_test_object_method_out_null(%p)\n", a); + *a = NULL; + return EINA_TRUE; +} + +EOLIAN static Eina_Bool +_test_object_method_inout_null(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + char **a) +{ + fprintf(stdout, "_test_object_method_inout_null(%p)\n", a); + return NULL == *a; +} + +EOLIAN static char * +_test_object_method_return_null(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED) +{ + fprintf(stdout, "_test_object_method_return_null()\n"); + return NULL; +} + +EOLIAN static void +_test_object_call_event(Eo* obj, Test_Object_Data *pd EINA_UNUSED) +{ + fprintf(stderr, "_test_object_event_call()\n"); fflush(stderr); + static Test_Struct_Ex s = {42, TEST_ENUM_EX_THIRD}; + eo_do(obj, eo_event_callback_call(TEST_OBJECT_EVENT_TEST, NULL)); + eo_do(obj, eo_event_callback_call(TEST_OBJECT_EVENT_TEST_STRUCTARG, &s)); + eo_do(obj, eo_event_callback_call(TEST_OBJECT_EVENT_TEST_STRINGARG, "foo")); +} + +EOLIAN static char * +_test_object_method_null(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + char *in, + char **out, + char **inout) +{ + fprintf(stdout, "_test_object_method_null(%p, %p, %p)\n", in, out, inout); + assert(!in); + *out = NULL; + *inout = NULL; + return NULL; +} + +// Arrays // + +EOLIAN static int +_test_object_method_array_at(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *array, + int index) +{ + fprintf(stdout, "_test_object_method_array_at(%p, %d)\n", array, index); + return *((int*)eina_array_data_get(array, index)); +} + +EOLIAN static Eina_Array * +_test_object_method_array_with_42(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED) +{ + fprintf(stdout, "_test_object_method_array_with_42()\n"); + Eina_Array *arr = eina_array_new(2); + int* n = malloc(sizeof(int)); + *n = 42; + eina_array_push(arr, n); + return arr; +} + +EOLIAN static void +_test_object_method_array_in_array_out(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in, + Eina_Array **a_out) +{ + fprintf(stdout, "_test_object_method_array_in_array_out(%p, %p)\n", a_in, a_out); + *a_out = a_in; +} + +EOLIAN static Eina_Array * +_test_object_method_array_of_objects(Eo* obj, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in) +{ + fprintf(stdout, "_test_object_method_array_of_objects(%p)\n", a_in); + if (a_in) return a_in; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, obj); + return arr; +} + + +EOLIAN static Eina_Array * +_test_object_method_array_of_strings(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in) +{ + fprintf(stdout, "_test_object_method_array_of_strings(%p)\n", a_in); + if (a_in) return a_in; + Eina_Array *arr = eina_array_new(2); + const char* v = "foo"; + fprintf(stdout, "v = %p\n", v); + eina_array_push(arr, v); + return arr; +} + +EOLIAN static Eina_Array * +_test_object_method_array_of_ints(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in) +{ + fprintf(stdout, "_test_object_method_array_of_ints(%p)\n", a_in); + if (a_in) return a_in; + int *v = malloc(sizeof(int)); + *v = 42; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return arr; +} + +EOLIAN static Eina_Array * +_test_object_method_array_of_bools(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in) +{ + fprintf(stdout, "_test_object_method_array_of_bools(%p)\n", a_in); + if (a_in) return a_in; + Eina_Bool *v = malloc(sizeof(Eina_Bool)); + *v = EINA_TRUE; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return arr; +} + +EOLIAN static Eina_Array * +_test_object_method_array_of_doubles(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in) +{ + fprintf(stdout, "_test_object_method_array_of_doubles(%p)\n", a_in); + if (a_in) return a_in; + double *v = malloc(sizeof(double)); + *v = 42; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return arr; +} + +EOLIAN static Eina_Array * +_test_object_method_array_of_enums(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in) +{ + fprintf(stdout, "_test_object_method_array_of_enums(%p)\n", a_in); + if (a_in) return a_in; + Test_Enum_Ex *v = malloc(sizeof(Test_Enum_Ex)); + *v = TEST_ENUM_EX_THIRD; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return arr; +} + +EOLIAN static Eina_Array * +_test_object_method_array_of_structs(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in) +{ + fprintf(stdout, "_test_object_method_array_of_structs(%p)\n", a_in); + if (a_in) return a_in; + Test_Struct_Ex *v = malloc(sizeof(Test_Struct_Ex)); + v->value_int = 42; + v->value_enum = TEST_ENUM_EX_THIRD; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return arr; +} + +EOLIAN static Eina_Array * +_test_object_method_array_of_arrays_of_ints(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in) +{ + fprintf(stdout, "_test_object_method_array_of_arrays_of_ints(%p)\n", a_in); + if (a_in) return a_in; + int *v = malloc(sizeof(int)); + *v = 42; + Eina_Array *a1 = eina_array_new(2); + eina_array_push(a1, v); + Eina_Array *a2 = eina_array_new(2); + eina_array_push(a2, a1); + return a2; +} + +// Lists // + +EOLIAN static Eina_List * +_test_object_method_list_with_42(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED) +{ + fprintf(stdout, "_test_object_method_list_with_42()\n"); + int* n = malloc(sizeof(int)); + *n = 42; + return eina_list_append(NULL, n); +} + +EOLIAN static void +_test_object_method_list_in_list_out(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in, + Eina_List **l_out) +{ + fprintf(stdout, "_test_object_method_list_in_list_out(%p , %p)\n", l_in, l_out); + *l_out = l_in; +} + +EOLIAN static Eina_List * +_test_object_method_list_of_objects(Eo* obj, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in) +{ + fprintf(stdout, "_test_object_method_list_of_objects(%p)\n", l_in); + if (l_in) return l_in; + return eina_list_append(NULL, obj); +} + + +EOLIAN static Eina_List * +_test_object_method_list_of_strings(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in) +{ + fprintf(stdout, "_test_object_method_list_of_strings(%p)\n", l_in); + if (l_in) return l_in; + return eina_list_append(NULL, "foo"); +} + +EOLIAN static Eina_List * +_test_object_method_list_of_ints(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in) +{ + fprintf(stdout, "_test_object_method_list_of_ints(%p)\n", l_in); + if (l_in) return l_in; + int *v = malloc(sizeof(int)); + *v = 42; + return eina_list_append(NULL, v); +} + +EOLIAN static Eina_List * +_test_object_method_list_of_bools(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in) +{ + fprintf(stdout, "_test_object_method_list_of_bools(%p)\n", l_in); + if (l_in) return l_in; + Eina_Bool *v = malloc(sizeof(Eina_Bool)); + *v = EINA_TRUE; + return eina_list_append(NULL, v); +} + +EOLIAN static Eina_List * +_test_object_method_list_of_doubles(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in) +{ + fprintf(stdout, "_test_object_method_list_of_doubles(%p)\n", l_in); + if (l_in) return l_in; + double *v = malloc(sizeof(double)); + *v = 42; + return eina_list_append(NULL, v); +} + +EOLIAN static Eina_List * +_test_object_method_list_of_enums(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in) +{ + fprintf(stdout, "_test_object_method_list_of_enums(%p)\n", l_in); + if (l_in) return l_in; + Test_Enum_Ex *v = malloc(sizeof(Test_Enum_Ex)); + *v = TEST_ENUM_EX_THIRD; + return eina_list_append(NULL, v); +} + +EOLIAN static Eina_List * +_test_object_method_list_of_structs(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in) +{ + fprintf(stdout, "_test_object_method_list_of_structs(%p)\n", l_in); + if (l_in) return l_in; + Test_Struct_Ex *v = malloc(sizeof(Test_Struct_Ex)); + v->value_int = 42; + v->value_enum = TEST_ENUM_EX_THIRD; + return eina_list_append(NULL, v); +} + +// Accessors // + +EOLIAN static Eina_Accessor * +_test_object_method_accessor_of_objects(Eo* obj, + Test_Object_Data *pd EINA_UNUSED, + Eina_Accessor *a_in) +{ + fprintf(stdout, "_test_object_method_accessor_of_objects(%p)\n", a_in); + if (a_in) return a_in; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, obj); + return eina_array_accessor_new(arr); +} + +EOLIAN static Eina_Accessor * +_test_object_method_accessor_of_strings(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Accessor *a_in) +{ + fprintf(stdout, "_test_object_method_accessor_of_strings(%p)\n", a_in); + if (a_in) return a_in; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, "foo"); + return eina_array_accessor_new(arr); +} + +EOLIAN static Eina_Accessor * +_test_object_method_accessor_of_ints(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Accessor *a_in) +{ + fprintf(stdout, "_test_object_method_accessor_of_ints(%p)\n", a_in); + if (a_in) return a_in; + int *v = malloc(sizeof(int)); + *v = 42; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return eina_array_accessor_new(arr); +} + +EOLIAN static Eina_Accessor * +_test_object_method_accessor_of_bools(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Accessor *a_in) +{ + fprintf(stdout, "_test_object_method_accessor_of_bools(%p)\n", a_in); + if (a_in) return a_in; + Eina_Bool *v = malloc(sizeof(Eina_Bool)); + *v = EINA_TRUE; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return eina_array_accessor_new(arr); +} + +EOLIAN static Eina_Accessor * +_test_object_method_accessor_of_doubles(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Accessor *a_in) +{ + fprintf(stdout, "_test_object_method_accessor_of_doubles(%p)\n", a_in); + if (a_in) return a_in; + double *v = malloc(sizeof(double)); + *v = 42.0; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return eina_array_accessor_new(arr); +} + +EOLIAN static Eina_Accessor * +_test_object_method_accessor_of_enums(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Accessor *a_in) +{ + fprintf(stdout, "_test_object_method_accessor_of_enums(%p)\n", a_in); + if (a_in) return a_in; + Test_Enum_Ex *v = malloc(sizeof(Test_Enum_Ex)); + *v = TEST_ENUM_EX_THIRD; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return eina_array_accessor_new(arr); +} + +EOLIAN static Eina_Accessor * +_test_object_method_accessor_of_structs(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Accessor *a_in) +{ + fprintf(stdout, "_test_object_method_accessor_of_structs(%p)\n", a_in); + if (a_in) return a_in; + Test_Struct_Ex *v = malloc(sizeof(Test_Struct_Ex)); + v->value_int = 42; + v->value_enum = TEST_ENUM_EX_THIRD; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return eina_array_accessor_new(arr); +} + +// Combinations of complex types + +EOLIAN static Eina_List * +_test_object_method_list_of_lists_of_ints(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in) +{ + fprintf(stdout, "_test_object_method_list_of_lists_of_ints(%p)\n", l_in); + if (l_in) return l_in; + int *v = malloc(sizeof(int)); + *v = 42; + return eina_list_append(NULL, eina_list_append(NULL, v)); +} + +EOLIAN static Eina_Array * +_test_object_method_array_of_lists_of_ints(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_Array *a_in) +{ + fprintf(stdout, "_test_object_method_array_of_lists_of_ints(%p)\n", a_in); + if (a_in) return a_in; + int *v = malloc(sizeof(int)); + *v = 42; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, eina_list_append(NULL, v)); + return arr; +} + +EOLIAN static Eina_List * +_test_object_method_list_of_arrays_of_ints(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Eina_List *l_in) +{ + fprintf(stdout, "_test_object_method_list_of_arrays_of_ints(%p)\n", l_in); + if (l_in) return l_in; + int *v = malloc(sizeof(int)); + *v = 42; + Eina_Array *arr = eina_array_new(2); + eina_array_push(arr, v); + return eina_list_append(NULL, arr); +} + +EOLIAN static const Eina_List * +_test_object_method_list_with_opaque_elements(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED) +{ + fprintf(stdout, "_test_object_method_list_with_opaque_elements()\n"); + return NULL; +} + +EOLIAN static Test_Enum_Ex +_test_object_method_in_enum_return_enum(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Test_Enum_Ex e) +{ + fprintf(stdout, "_test_object_method_in_enum_return_enum(%d)\n", e); + return e; +} + +EOLIAN static Test_Struct_Ex * +_test_object_method_in_struct_return_struct(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED, + Test_Struct_Ex *s) +{ + fprintf(stdout, "_test_object_method_in_struct_return_struct()\n"); + return s; +} + +EOLIAN static void +_test_object_event_repeated_event_name(Eo* obj EINA_UNUSED, + Test_Object_Data *pd EINA_UNUSED) +{ +} + +#include <test_object.eo.c> diff --git a/src/tests/eolian_js/test_object.eo b/src/tests/eolian_js/test_object.eo new file mode 100644 index 0000000000..c292c248e7 --- /dev/null +++ b/src/tests/eolian_js/test_object.eo @@ -0,0 +1,305 @@ +enum Test.Enum_Ex { + first = 0, + second, + third, + fourth +} + +struct Test.Struct_Ex { + value_int: int; + value_enum: Test.Enum_Ex; +} + +class Test.Object (Eo.Base) { + legacy_prefix: null; + methods { + method_integral_in_a { + [[ tests integral in ]] + params { a: int; } + } + method_integral_out_a { + [[ tests integral out ]] + params { @out a: int; } + } + method_integral_inout { + [[ tests integral inout ]] + params { @inout a: int; } + } + method_integral_return_a { + [[ tests integral result ]] + return: int; + } + method_div_mod { + [[ tests mixed in, outs and result ]] + params { + a: int; + b: int; + @out quotient: int; + @out remainder: int; + } + return: bool; + } + method_and { + [[ tests boolean ]] + params { + a: bool; + b: bool; + } + return: bool; + } + method_modf { + [[ tests floating point ]] + params { + a: double; + @out int_part: double; + } + return: double; + } + method_uppercase { + [[ tests string ]] + params { + @inout str: char*; + } + } + method_in_null { + [[ tests null input ]] + params { + a: char*; + } + return: bool; + } + method_out_null { + [[ tests null output ]] + params { + @out a: char*; + } + return: bool; + } + method_inout_null { + [[ tests null output ]] + params { + @inout a: char*; + } + return: bool; + } + method_return_null { + [[ tests null return ]] + return: char*; + } + method_null { + [[ tests null values ]] + params { + in: char*; + @out out: char*; + @inout inout: char*; + } + return: char*; + } + method_array_at { + [[ tests array ]] + params { + array: array<int>*; + index: int; + } + return: int; + } + method_array_with_42 { + [[ tests parameters ]] + return: free(own(array<int> *), eina_array_free) @warn_unused; + } + method_array_in_array_out { + [[ tests parameters ]] + params { + @in a_in: array<int> *; + @out a_out: array<int> *; + } + } + method_array_of_objects { + params { + @in a_in: array<Test.Object *> *; + } + return: array<Test.Object *> *; + } + method_array_of_strings { + params { + @in a_in: array<const(char) *> *; + } + return: array<const(char) *> *; + } + method_array_of_ints { + params { + @in a_in: array<int> *; + } + return: array<int> *; + } + method_array_of_bools { + params { + @in a_in: array<bool> *; + } + return: array<bool> *; + } + method_array_of_doubles { + params { + @in a_in: array<double> *; + } + return: array<double> *; + } + method_array_of_enums { + params { + @in a_in: array<Test.Enum_Ex> *; + } + return: array<Test.Enum_Ex> *; + } + method_array_of_structs { + params { + @in a_in: array<Test.Struct_Ex> *; + } + return: array<Test.Struct_Ex> *; + } + method_list_with_42 { + [[ tests parameters ]] + return: free(own(list<int> *), eina_list_free) @warn_unused; + } + method_list_in_list_out { + [[ tests parameters ]] + params { + @in l_in: list<int> *; + @out l_out: list<int> *; + } + } + method_list_of_objects { + params { + @in l_in: list<Test.Object *> *; + } + return: list<Test.Object *> *; + } + method_list_of_strings { + params { + @in l_in: list<const(char) *> *; + } + return: list<const(char) *> *; + } + method_list_of_ints { + params { + @in l_in: list<int> *; + } + return: list<int> *; + } + method_list_of_bools { + params { + @in l_in: list<bool> *; + } + return: list<bool> *; + } + method_list_of_doubles { + params { + @in l_in: list<double> *; + } + return: list<double> *; + } + method_list_of_enums { + params { + @in l_in: list<Test.Enum_Ex> *; + } + return: list<Test.Enum_Ex> *; + } + method_list_of_structs { + params { + @in l_in: list<Test.Struct_Ex> *; + } + return: list<Test.Struct_Ex> *; + } + method_accessor_of_objects { + params { + @in a_in: accessor<Test.Object *> *; + } + return: accessor<Test.Object *> *; + } + method_accessor_of_strings { + params { + @in a_in: accessor<const(char) *> *; + } + return: accessor<const(char) *> *; + } + method_accessor_of_ints { + params { + @in a_in: accessor<int> *; + } + return: accessor<int> *; + } + method_accessor_of_bools { + params { + @in a_in: accessor<bool> *; + } + return: accessor<bool> *; + } + method_accessor_of_doubles { + params { + @in a_in: accessor<double> *; + } + return: accessor<double> *; + } + method_accessor_of_enums { + params { + @in a_in: accessor<Test.Enum_Ex> *; + } + return: accessor<Test.Enum_Ex> *; + } + method_accessor_of_structs { + params { + @in a_in: accessor<Test.Struct_Ex> *; + } + return: accessor<Test.Struct_Ex> *; + } + method_array_of_arrays_of_ints { + params { + @in a_in: array<array<int> *> *; + } + return: array<array<int> *> *; + } + method_list_of_lists_of_ints { + params { + @in l_in: list<list<int> *> *; + } + return: list<list<int> *> *; + } + method_array_of_lists_of_ints { + params { + @in a_in: array<list<int> *> *; + } + return: array<list<int> *> *; + } + method_list_of_arrays_of_ints { + params { + @in l_in: list<array<int> *> *; + } + return: list<array<int> *> *; + } + method_list_with_opaque_elements { + return: const(list<Elm.Calendar.Mark*>)*; + } + method_in_enum_return_enum { + params { e: Test.Enum_Ex; } + return: Test.Enum_Ex; + } + method_in_struct_return_struct { + params { e: Test.Struct_Ex *; } + return: Test.Struct_Ex *; + } + call_event { + } + event_repeated_event_name { + } + } + implements { + Eo.Base.finalize; + Eo.Base.constructor; + Eo.Base.destructor; + } + events { + test; + test,structarg: Test.Struct_Ex; + test,stringarg: const(char)*; + repeated,event,name; + } +} |