[eina_js] add binding for accessor

This commit is contained in:
Vinícius dos Santos Oliveira 2014-12-23 03:05:07 -03:00
parent f250ae0c47
commit e7003affa2
4 changed files with 249 additions and 3 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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 */

View File

@ -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);
}
}