forked from enlightenment/efl
[eina_js] add binding for accessor
This commit is contained in:
parent
f250ae0c47
commit
e7003affa2
|
@ -21,7 +21,8 @@ lib_eina_js_libeina_js_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
|
|||
lib_eina_js_libeina_js_la_SOURCES = \
|
||||
bindings/eina_js/eina_js_container.cc \
|
||||
bindings/eina_js/eina_js_value.cc \
|
||||
bindings/eina_js/eina_js_error.cc
|
||||
bindings/eina_js/eina_js_error.cc \
|
||||
bindings/eina_js/eina_js_accessor.cc
|
||||
|
||||
#installed_einacxxmainheadersdir = $(includedir)/eina-cxx-@VMAJ@
|
||||
#dist_installed_einacxxmainheaders_DATA = \
|
||||
|
@ -60,10 +61,12 @@ if EFL_ENABLE_TESTS
|
|||
|
||||
check_PROGRAMS += tests/eina_js/eina_js_suite \
|
||||
tests/eina_js/eina_js_value \
|
||||
tests/eina_js/eina_js_error
|
||||
tests/eina_js/eina_js_error \
|
||||
tests/eina_js/eina_js_accessor
|
||||
TESTS += tests/eina_js/eina_js_suite \
|
||||
tests/eina_js/eina_js_value \
|
||||
tests/eina_js/eina_js_error
|
||||
tests/eina_js/eina_js_error \
|
||||
tests/eina_js/eina_js_accessor
|
||||
|
||||
tests_eina_js_eina_js_suite_SOURCES = \
|
||||
tests/eina_js/eina_js_suite.cc
|
||||
|
@ -74,6 +77,9 @@ tests/eina_js/eina_js_value.cc
|
|||
tests_eina_js_eina_js_error_SOURCES = \
|
||||
tests/eina_js/eina_js_error.cc
|
||||
|
||||
tests_eina_js_eina_js_accessor_SOURCES = \
|
||||
tests/eina_js/eina_js_accessor.cc
|
||||
|
||||
tests_eina_js_eina_js_suite_CXXFLAGS = -I$(top_builddir)/src/lib/efl \
|
||||
-DTESTS_WD=\"`pwd`\" \
|
||||
-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eina_js\" \
|
||||
|
@ -114,6 +120,19 @@ tests_eina_js_eina_js_error_CXXFLAGS = -I$(top_builddir)/src/lib/efl \
|
|||
tests_eina_js_eina_js_error_LDADD = @CHECK_LIBS@ @USE_EINA_JS_LIBS@ @USE_EINA_LIBS@ @USE_EO_LIBS@
|
||||
tests_eina_js_eina_js_error_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EINA_JS_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@
|
||||
|
||||
tests_eina_js_eina_js_accessor_CXXFLAGS = -I$(top_builddir)/src/lib/efl \
|
||||
-DTESTS_WD=\"`pwd`\" \
|
||||
-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eina_js\" \
|
||||
-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)/src/tests/eina_js\" \
|
||||
-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eina_js\" \
|
||||
@CHECK_CFLAGS@ \
|
||||
@EINA_CXX_CFLAGS@ \
|
||||
@EO_CXX_CFLAGS@ \
|
||||
@EO_CFLAGS@ \
|
||||
@EINA_JS_CFLAGS@
|
||||
tests_eina_js_eina_js_accessor_LDADD = @CHECK_LIBS@ @USE_EINA_JS_LIBS@ @USE_EINA_LIBS@ @USE_EO_LIBS@
|
||||
tests_eina_js_eina_js_accessor_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EINA_JS_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <eina_js_accessor.hh>
|
||||
|
||||
namespace efl { namespace js {
|
||||
|
||||
EAPI void register_destroy_accessor(v8::Isolate *isolate,
|
||||
v8::Handle<v8::Object> global,
|
||||
v8::Handle<v8::String> name)
|
||||
{
|
||||
using v8::Value;
|
||||
using v8::Object;
|
||||
using v8::Handle;
|
||||
using v8::FunctionTemplate;
|
||||
using v8::FunctionCallbackInfo;
|
||||
|
||||
typedef void (*deleter_t)(void*);
|
||||
|
||||
auto f = [](const FunctionCallbackInfo<Value> &info) {
|
||||
if (info.Length() != 1 || !info[0]->IsObject())
|
||||
return;
|
||||
|
||||
Handle<Object> o = info[0]->ToObject();
|
||||
|
||||
deleter_t deleter = reinterpret_cast<deleter_t>
|
||||
(o->GetAlignedPointerFromInternalField(1));
|
||||
deleter(o->GetAlignedPointerFromInternalField(0));
|
||||
};
|
||||
|
||||
global->Set(name, FunctionTemplate::New(isolate, f)->GetFunction());
|
||||
}
|
||||
|
||||
} } // namespace efl { namespace js {
|
|
@ -0,0 +1,93 @@
|
|||
#ifndef EINA_JS_ACCESSOR_HH
|
||||
#define EINA_JS_ACCESSOR_HH
|
||||
|
||||
#include <v8.h>
|
||||
#include <Eina.hh>
|
||||
#include <memory>
|
||||
|
||||
#include <eina_js_value.hh>
|
||||
|
||||
namespace efl { namespace js {
|
||||
|
||||
/* Creates a copy from \p a accessor and exports it to be manipulated by the JS
|
||||
code */
|
||||
template<class T>
|
||||
v8::Local<v8::Object> export_accessor(::efl::eina::accessor<T> &a,
|
||||
v8::Isolate *isolate)
|
||||
{
|
||||
using v8::Local;
|
||||
using v8::Value;
|
||||
using v8::String;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::FunctionTemplate;
|
||||
using v8::ObjectTemplate;
|
||||
|
||||
typedef ::efl::eina::accessor<T> value_type;
|
||||
typedef value_type *ptr_type;
|
||||
typedef void (*deleter_t)(void*);
|
||||
|
||||
auto obj_tpl = ObjectTemplate::New(isolate);
|
||||
obj_tpl->SetInternalFieldCount(2);
|
||||
|
||||
auto ret = obj_tpl->NewInstance();
|
||||
|
||||
auto get = [](const FunctionCallbackInfo<Value> &info) {
|
||||
if (info.Length() != 1 || !info[0]->IsNumber())
|
||||
return;
|
||||
|
||||
auto idx = [&info]() -> std::size_t {
|
||||
auto idx = info[0];
|
||||
|
||||
if (idx->IsInt32())
|
||||
return idx->ToInt32()->Value();
|
||||
else if (idx->IsUint32())
|
||||
return idx->ToUint32()->Value();
|
||||
else
|
||||
return idx->ToNumber()->Value();
|
||||
}();
|
||||
|
||||
void *ptr = info.Holder()->GetAlignedPointerFromInternalField(0);
|
||||
auto &value = *static_cast<ptr_type>(ptr);
|
||||
info.GetReturnValue().Set(value_cast<Local<Value>>(value[idx],
|
||||
info.GetIsolate()));
|
||||
};
|
||||
|
||||
ret->Set(String::NewFromUtf8(isolate, "get"),
|
||||
FunctionTemplate::New(isolate, get)->GetFunction());
|
||||
|
||||
{
|
||||
deleter_t deleter = [](void *a) {
|
||||
delete static_cast<ptr_type>(a);
|
||||
};
|
||||
std::unique_ptr<value_type> ptr(new value_type(a));
|
||||
ret->SetAlignedPointerInInternalField(0, ptr.get());
|
||||
ret->SetAlignedPointerInInternalField(1,
|
||||
reinterpret_cast<void*>(deleter));
|
||||
ptr.release();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Extracts and returns a copy from the internal accessor object from the JS
|
||||
object */
|
||||
template<class T>
|
||||
::efl::eina::accessor<T> import_accessor(v8::Handle<v8::Object> o)
|
||||
{
|
||||
typedef ::efl::eina::accessor<T> value_type;
|
||||
typedef value_type *ptr_type;
|
||||
|
||||
ptr_type acc = reinterpret_cast<ptr_type>
|
||||
(o->GetAlignedPointerFromInternalField(0));
|
||||
|
||||
return value_type(*acc);
|
||||
}
|
||||
|
||||
/* 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 */
|
|
@ -0,0 +1,99 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <eina_js_accessor.hh>
|
||||
#include <Eo.hh>
|
||||
|
||||
void print(const v8::FunctionCallbackInfo<v8::Value> &args)
|
||||
{
|
||||
bool first = true;
|
||||
for (int i = 0; i < args.Length(); i++) {
|
||||
v8::HandleScope handle_scope(args.GetIsolate());
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
v8::String::Utf8Value str(args[i]);
|
||||
std::cout << std::string(*str, str.length());
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static const char script[] =
|
||||
"function assert(test, message) { if (test !== true) throw message; };"
|
||||
|
||||
"assert(acc.get(0) === 42, '#1');"
|
||||
"assert(acc.get(1) === 24, '#2');"
|
||||
"destroy_accessor(acc);"
|
||||
;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
efl::eina::eina_init eina_init;
|
||||
efl::eo::eo_init eo_init;
|
||||
|
||||
v8::V8::Initialize();
|
||||
v8::V8::InitializeICU();
|
||||
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
|
||||
v8::Isolate* isolate = v8::Isolate::New();
|
||||
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Context> context
|
||||
= v8::Context::New(isolate, NULL, v8::ObjectTemplate::New(isolate));
|
||||
|
||||
if (context.IsEmpty()) {
|
||||
fprintf(stderr, "Error creating context\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
// Enter the execution environment before evaluating any code.
|
||||
v8::Context::Scope context_scope(context);
|
||||
v8::Handle<v8::Object> global = context->Global();
|
||||
|
||||
global->Set(v8::String::NewFromUtf8(isolate, "print"),
|
||||
v8::FunctionTemplate::New(isolate, print)->GetFunction());
|
||||
efl::js::register_destroy_accessor(isolate, global,
|
||||
v8::String::NewFromUtf8(isolate,
|
||||
"destroy_accessor"));
|
||||
|
||||
Eina_Array *array = [](){
|
||||
int impl[2] = {42, 24};
|
||||
Eina_Array *a = eina_array_new(2);
|
||||
eina_array_push(a, impl);
|
||||
eina_array_push(a, impl+1);
|
||||
return a;
|
||||
}();
|
||||
efl::eina::accessor<int> acc(eina_array_accessor_new(array));
|
||||
|
||||
v8::Local<v8::Object> wrapped_acc = efl::js::export_accessor(acc, isolate);
|
||||
|
||||
global->Set(v8::String::NewFromUtf8(isolate, "acc"), wrapped_acc);
|
||||
|
||||
assert(efl::js::import_accessor<int>(wrapped_acc)[0] == 42);
|
||||
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::TryCatch try_catch;
|
||||
auto source = v8::String::NewFromUtf8(isolate, script);
|
||||
v8::Handle<v8::Script> script = v8::Script::Compile(std::move(source));
|
||||
|
||||
assert(!script.IsEmpty());
|
||||
|
||||
/*v8::Handle<v8::Value> result = */script->Run();
|
||||
|
||||
if (try_catch.HasCaught()) {
|
||||
v8::String::Utf8Value message(try_catch.Message()->Get());
|
||||
std::cerr << std::string(*message, message.length()) << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
eina_array_free(array);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue