aboutsummaryrefslogtreecommitdiff
path: root/system/include
diff options
context:
space:
mode:
authorChad Austin <chad@chadaustin.me>2012-09-25 17:43:20 -0700
committerChad Austin <chad@chadaustin.me>2012-09-25 18:14:22 -0700
commit86305a27d4552167f76dd9e19e0c8e45aa645caa (patch)
tree502d7b67bd9c2c3bf4e284dbe70d50ecf87cf0b8 /system/include
parentc74da50989604747e3174429d0538f668b4ff7e7 (diff)
Add embind headers
Diffstat (limited to 'system/include')
-rw-r--r--system/include/emscripten/bind.h602
-rw-r--r--system/include/emscripten/val.h177
-rw-r--r--system/include/emscripten/wire.h223
3 files changed, 1002 insertions, 0 deletions
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h
new file mode 100644
index 00000000..0f1997bb
--- /dev/null
+++ b/system/include/emscripten/bind.h
@@ -0,0 +1,602 @@
+#pragma once
+
+#include <stddef.h>
+#include <string>
+#include <emscripten/val.h>
+#include <emscripten/wire.h>
+#include <boost/optional.hpp>
+
+namespace emscripten {
+ namespace internal {
+ typedef void (*GenericFunction)();
+ typedef long GenericEnumValue;
+
+ // Implemented in JavaScript. Don't call these directly.
+ extern "C" {
+ void _embind_fatal_error(
+ const char* name,
+ const char* payload) __attribute__((noreturn));
+
+ void _embind_register_void(
+ TypeID voidType,
+ const char* name);
+
+ void _embind_register_bool(
+ TypeID boolType,
+ const char* name,
+ bool trueValue,
+ bool falseValue);
+
+ void _embind_register_integer(
+ TypeID integerType,
+ const char* name);
+
+ void _embind_register_float(
+ TypeID floatType,
+ const char* name);
+
+ void _embind_register_cstring(
+ TypeID stringType,
+ const char* name);
+
+ void _embind_register_emval(
+ TypeID emvalType,
+ const char* name);
+
+ void _embind_register_function(
+ const char* name,
+ TypeID returnType,
+ unsigned argCount,
+ TypeID argTypes[],
+ GenericFunction invoker,
+ GenericFunction function);
+
+ void _embind_register_tuple(
+ TypeID tupleType,
+ const char* name,
+ GenericFunction constructor,
+ GenericFunction destructor);
+
+ void _embind_register_tuple_element(
+ TypeID tupleType,
+ TypeID elementType,
+ GenericFunction getter,
+ GenericFunction setter,
+ size_t memberPointerSize,
+ void* memberPointer);
+
+ void _embind_register_tuple_element_accessor(
+ TypeID tupleType,
+ TypeID elementType,
+ GenericFunction staticGetter,
+ size_t getterSize,
+ void* getter,
+ GenericFunction staticSetter,
+ size_t setterSize,
+ void* setter);
+
+ void _embind_register_struct(
+ TypeID structType,
+ const char* name,
+ GenericFunction constructor,
+ GenericFunction destructor);
+
+ void _embind_register_struct_field(
+ TypeID structType,
+ const char* name,
+ TypeID fieldType,
+ GenericFunction getter,
+ GenericFunction setter,
+ size_t memberPointerSize,
+ void* memberPointer);
+
+ void _embind_register_class(
+ TypeID classType,
+ const char* className,
+ GenericFunction destructor);
+
+ void _embind_register_class_constructor(
+ TypeID classType,
+ unsigned argCount,
+ TypeID argTypes[],
+ GenericFunction constructor);
+
+ void _embind_register_class_method(
+ TypeID classType,
+ const char* methodName,
+ TypeID returnType,
+ unsigned argCount,
+ TypeID argTypes[],
+ GenericFunction invoker,
+ size_t memberFunctionSize,
+ void* memberFunction);
+
+ void _embind_register_class_field(
+ TypeID classType,
+ const char* fieldName,
+ TypeID fieldType,
+ GenericFunction getter,
+ GenericFunction setter,
+ size_t memberPointerSize,
+ void* memberPointer);
+
+ void _embind_register_class_classmethod(
+ TypeID classType,
+ const char* methodName,
+ TypeID returnType,
+ unsigned argCount,
+ TypeID argTypes[],
+ GenericFunction method);
+
+ void _embind_register_enum(
+ TypeID enumType,
+ const char* name);
+
+ void _embind_register_enum_value(
+ TypeID enumType,
+ const char* valueName,
+ GenericEnumValue value);
+
+ void _embind_register_interface(
+ TypeID interfaceType,
+ const char* name,
+ GenericFunction constructor,
+ GenericFunction destructor);
+ }
+
+ extern void registerStandardTypes();
+
+ class BindingsDefinition {
+ public:
+ template<typename Function>
+ BindingsDefinition(Function fn) {
+ fn();
+ }
+ };
+ }
+}
+
+namespace emscripten {
+ namespace internal {
+ template<typename ReturnType, typename... Args>
+ struct Invoker {
+ static typename internal::BindingType<ReturnType>::WireType invoke(
+ ReturnType (fn)(Args...),
+ typename internal::BindingType<Args>::WireType... args
+ ) {
+ return internal::BindingType<ReturnType>::toWireType(
+ fn(
+ internal::BindingType<Args>::fromWireType(args)...
+ )
+ );
+ }
+ };
+
+ template<typename... Args>
+ struct Invoker<void, Args...> {
+ static void invoke(
+ void (fn)(Args...),
+ typename internal::BindingType<Args>::WireType... args
+ ) {
+ return fn(
+ internal::BindingType<Args>::fromWireType(args)...
+ );
+ }
+ };
+ }
+
+ template<typename ReturnType, typename... Args>
+ void function(const char* name, ReturnType (fn)(Args...)) {
+ internal::registerStandardTypes();
+
+ internal::ArgTypeList<Args...> args;
+ internal::_embind_register_function(
+ name,
+ internal::getTypeID<ReturnType>(),
+ args.count,
+ args.types,
+ reinterpret_cast<internal::GenericFunction>(&internal::Invoker<ReturnType, Args...>::invoke),
+ reinterpret_cast<internal::GenericFunction>(fn));
+ }
+
+ namespace internal {
+ template<typename ClassType, typename... Args>
+ ClassType* raw_constructor(
+ typename internal::BindingType<Args>::WireType... args
+ ) {
+ return new ClassType(
+ internal::BindingType<Args>::fromWireType(args)...
+ );
+ }
+
+ template<typename ClassType>
+ void raw_destructor(ClassType* ptr) {
+ delete ptr;
+ }
+
+ template<typename ClassType, typename ReturnType, typename... Args>
+ struct MethodInvoker {
+ typedef ReturnType (ClassType::*MemberPointer)(Args...);
+ typename internal::BindingType<ReturnType>::WireType invoke(
+ ClassType* ptr,
+ const MemberPointer& method,
+ typename internal::BindingType<Args>::WireType... args
+ ) {
+ return internal::BindingType<ReturnType>::toWireType(
+ (ptr->*method)(
+ internal::BindingType<Args>::fromWireType(args)...
+ )
+ );
+ }
+ };
+
+ template<typename ClassType, typename... Args>
+ struct MethodInvoker<ClassType, void, Args...> {
+ typedef void (ClassType::*MemberPointer)(Args...);
+ static void invoke(
+ ClassType* ptr,
+ const MemberPointer& method,
+ typename internal::BindingType<Args>::WireType... args
+ ) {
+ return (ptr->*method)(
+ internal::BindingType<Args>::fromWireType(args)...
+ );
+ }
+ };
+
+ template<typename ClassType, typename ReturnType, typename... Args>
+ struct ConstMethodInvoker {
+ typedef ReturnType (ClassType::*MemberPointer)(Args...) const;
+ static typename internal::BindingType<ReturnType>::WireType invoke(
+ const ClassType* ptr,
+ const MemberPointer& method,
+ typename internal::BindingType<Args>::WireType... args
+ ) {
+ return internal::BindingType<ReturnType>::toWireType(
+ (ptr->*method)(
+ internal::BindingType<Args>::fromWireType(args)...
+ )
+ );
+ }
+ };
+
+ template<typename ClassType, typename... Args>
+ struct ConstMethodInvoker<ClassType, void, Args...> {
+ typedef void (ClassType::*MemberPointer)(Args...) const;
+ static void invoke(
+ const ClassType* ptr,
+ const MemberPointer& method,
+ typename internal::BindingType<Args>::WireType... args
+ ) {
+ return (ptr->*method)(
+ internal::BindingType<Args>::fromWireType(args)...
+ );
+ }
+ };
+
+ template<typename ClassType, typename FieldType>
+ struct FieldAccess {
+ typedef FieldType ClassType::*MemberPointer;
+ typedef internal::BindingType<FieldType> FieldBinding;
+ typedef typename FieldBinding::WireType WireType;
+
+ static WireType get(
+ ClassType& ptr,
+ const MemberPointer& field
+ ) {
+ return FieldBinding::toWireType(ptr.*field);
+ }
+
+ static void set(
+ ClassType& ptr,
+ const MemberPointer& field,
+ WireType value
+ ) {
+ ptr.*field = FieldBinding::fromWireType(value);
+ }
+
+ template<typename Getter>
+ static WireType propertyGet(
+ ClassType& ptr,
+ const Getter& getter
+ ) {
+ return FieldBinding::toWireType(getter(ptr));
+ }
+
+ template<typename Setter>
+ static void propertySet(
+ ClassType& ptr,
+ const Setter& setter,
+ WireType value
+ ) {
+ setter(ptr, FieldBinding::fromWireType(value));
+ }
+ };
+ }
+
+ template<typename ClassType>
+ class value_tuple {
+ public:
+ value_tuple(const char* name) {
+ internal::registerStandardTypes();
+ internal::_embind_register_tuple(
+ internal::getTypeID<ClassType>(),
+ name,
+ reinterpret_cast<internal::GenericFunction>(&internal::raw_constructor<ClassType>),
+ reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<ClassType>));
+ }
+
+ template<typename ElementType>
+ value_tuple& element(ElementType ClassType::*field) {
+ internal::_embind_register_tuple_element(
+ internal::getTypeID<ClassType>(),
+ internal::getTypeID<ElementType>(),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::get),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::set),
+ sizeof(field),
+ &field);
+
+ return *this;
+ }
+
+ template<typename ElementType>
+ value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType)) {
+ internal::_embind_register_tuple_element_accessor(
+ internal::getTypeID<ClassType>(),
+ internal::getTypeID<ElementType>(),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>),
+ sizeof(getter),
+ &getter,
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>),
+ sizeof(setter),
+ &setter);
+ return *this;
+ }
+
+ template<typename ElementType>
+ value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&)) {
+ internal::_embind_register_tuple_element_accessor(
+ internal::getTypeID<ClassType>(),
+ internal::getTypeID<ElementType>(),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>),
+ sizeof(getter),
+ &getter,
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>),
+ sizeof(setter),
+ &setter);
+ return *this;
+ }
+
+ template<typename ElementType>
+ value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, const ElementType&&)) {
+ internal::_embind_register_tuple_element_accessor(
+ internal::getTypeID<ClassType>(),
+ internal::getTypeID<ElementType>(),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>),
+ sizeof(getter),
+ &getter,
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>),
+ sizeof(setter),
+ &setter);
+ return *this;
+ }
+
+ template<typename ElementType>
+ value_tuple& element(ElementType (*getter)(const ClassType&), void (*setter)(ClassType&, ElementType&)) {
+ internal::_embind_register_tuple_element_accessor(
+ internal::getTypeID<ClassType>(),
+ internal::getTypeID<ElementType>(),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertyGet<ElementType(const ClassType&)>),
+ sizeof(getter),
+ &getter,
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, ElementType>::template propertySet<void(ClassType&, ElementType)>),
+ sizeof(setter),
+ &setter);
+ return *this;
+ }
+ };
+
+ template<typename ClassType>
+ class value_struct {
+ public:
+ value_struct(const char* name) {
+ internal::registerStandardTypes();
+ internal::_embind_register_struct(
+ internal::getTypeID<ClassType>(),
+ name,
+ reinterpret_cast<internal::GenericFunction>(&internal::raw_constructor<ClassType>),
+ reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<ClassType>));
+ }
+
+ template<typename FieldType>
+ value_struct& field(const char* fieldName, FieldType ClassType::*field) {
+ internal::_embind_register_struct_field(
+ internal::getTypeID<ClassType>(),
+ fieldName,
+ internal::getTypeID<FieldType>(),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::get),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::set),
+ sizeof(field),
+ &field);
+
+ return *this;
+ }
+ };
+
+ // TODO: support class definitions without constructors.
+ // TODO: support external class constructors
+ template<typename ClassType>
+ class class_ {
+ public:
+ class_(const char* name) {
+ internal::registerStandardTypes();
+ internal::_embind_register_class(
+ internal::getTypeID<ClassType>(),
+ name,
+ reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<ClassType>));
+ }
+
+ template<typename... ConstructorArgs>
+ class_& constructor() {
+ internal::ArgTypeList<ConstructorArgs...> args;
+ internal::_embind_register_class_constructor(
+ internal::getTypeID<ClassType>(),
+ args.count,
+ args.types,
+ reinterpret_cast<internal::GenericFunction>(&internal::raw_constructor<ClassType, ConstructorArgs...>));
+ }
+
+ template<typename ReturnType, typename... Args>
+ class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...)) {
+ internal::ArgTypeList<Args...> args;
+ internal::_embind_register_class_method(
+ internal::getTypeID<ClassType>(),
+ methodName,
+ internal::getTypeID<ReturnType>(),
+ args.count,
+ args.types,
+ reinterpret_cast<internal::GenericFunction>(&internal::MethodInvoker<ClassType, ReturnType, Args...>::invoke),
+ sizeof(memberFunction),
+ &memberFunction);
+ return *this;
+ }
+
+ template<typename ReturnType, typename... Args>
+ class_& method(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const) {
+ internal::ArgTypeList<Args...> args;
+ internal::_embind_register_class_method(
+ internal::getTypeID<ClassType>(),
+ methodName,
+ internal::getTypeID<ReturnType>(),
+ args.count,
+ args.types,
+ reinterpret_cast<internal::GenericFunction>(&internal::ConstMethodInvoker<ClassType, ReturnType, Args...>::invoke),
+ sizeof(memberFunction),
+ &memberFunction);
+ return *this;
+ }
+
+ template<typename FieldType>
+ class_& field(const char* fieldName, FieldType ClassType::*field) {
+ internal::_embind_register_class_field(
+ internal::getTypeID<ClassType>(),
+ fieldName,
+ internal::getTypeID<FieldType>(),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::get),
+ reinterpret_cast<internal::GenericFunction>(&internal::FieldAccess<ClassType, FieldType>::set),
+ sizeof(field),
+ &field);
+ return *this;
+ }
+
+ template<typename ReturnType, typename... Args>
+ class_& classmethod(const char* methodName, ReturnType (*classMethod)(Args...)) {
+ internal::ArgTypeList<Args...> args;
+ internal::_embind_register_class_classmethod(
+ internal::getTypeID<ClassType>(),
+ methodName,
+ internal::getTypeID<ReturnType>(),
+ args.count,
+ args.types,
+ reinterpret_cast<internal::GenericFunction>(classMethod));
+ return *this;
+ }
+ };
+
+ template<typename EnumType>
+ class enum_ {
+ public:
+ enum_(const char* name) {
+ _embind_register_enum(
+ internal::getTypeID<EnumType>(),
+ name);
+ }
+
+ enum_& value(const char* name, EnumType value) {
+ // TODO: there's still an issue here.
+ // if EnumType is an unsigned long, then JS may receive it as a signed long
+ static_assert(sizeof(value) <= sizeof(internal::GenericEnumValue), "enum type must fit in a GenericEnumValue");
+
+ _embind_register_enum_value(
+ internal::getTypeID<EnumType>(),
+ name,
+ static_cast<internal::GenericEnumValue>(value));
+ return *this;
+ }
+ };
+
+ template<typename InterfaceType>
+ class wrapper : public InterfaceType {
+ public:
+ // Not necessary in any example so far, but appeases a compiler warning.
+ virtual ~wrapper() {}
+
+ typedef InterfaceType interface;
+
+ void initialize(internal::EM_VAL handle) {
+ if (jsobj) {
+ internal::_embind_fatal_error(
+ "Cannot initialize interface wrapper twice",
+ typeid(InterfaceType).name());
+ }
+ jsobj = val::take_ownership(handle);
+ }
+
+ template<typename ReturnType, typename... Args>
+ ReturnType call(const char* name, Args... args) {
+ assertInitialized();
+ return Caller<ReturnType, Args...>::call(*jsobj, name, args...);
+ }
+
+ private:
+ // this class only exists because you can't partially specialize function templates
+ template<typename ReturnType, typename... Args>
+ struct Caller {
+ static ReturnType call(val& v, const char* name, Args... args) {
+ return v.call(name, args...).template as<ReturnType>();
+ }
+ };
+
+ template<typename... Args>
+ struct Caller<void, Args...> {
+ static void call(val& v, const char* name, Args... args) {
+ v.call(name, args...);
+ }
+ };
+
+ void assertInitialized() {
+ if (!jsobj) {
+ internal::_embind_fatal_error(
+ "Cannot invoke call on uninitialized interface wrapper.",
+ typeid(InterfaceType).name());
+ }
+ }
+
+ boost::optional<val> jsobj;
+ };
+
+ namespace internal {
+ template<typename WrapperType>
+ WrapperType* create_interface_wrapper(EM_VAL e) {
+ WrapperType* p = new WrapperType;
+ p->initialize(e);
+ return p;
+ }
+ }
+
+ template<typename WrapperType>
+ class interface {
+ public:
+ typedef typename WrapperType::interface InterfaceType;
+
+ interface(const char* name) {
+ _embind_register_interface(
+ internal::getTypeID<InterfaceType>(),
+ name,
+ reinterpret_cast<internal::GenericFunction>(&internal::create_interface_wrapper<WrapperType>),
+ reinterpret_cast<internal::GenericFunction>(&internal::raw_destructor<WrapperType>));
+ }
+ };
+}
+
+#define EMSCRIPTEN_BINDINGS(fn) static emscripten::internal::BindingsDefinition anon_symbol(fn);
diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h
new file mode 100644
index 00000000..96db9326
--- /dev/null
+++ b/system/include/emscripten/val.h
@@ -0,0 +1,177 @@
+#pragma once
+
+#include <stdint.h> // uintptr_t
+#include <emscripten/wire.h>
+
+namespace emscripten {
+ namespace internal {
+ // Implemented in JavaScript. Don't call these directly.
+ extern "C" {
+ typedef struct _EM_VAL* EM_VAL;
+
+ void _emval_incref(EM_VAL value);
+ void _emval_decref(EM_VAL value);
+ EM_VAL _emval_new_object();
+ EM_VAL _emval_new_long(long value);
+ EM_VAL _emval_new_cstring(const char* str);
+ EM_VAL _emval_get_property(EM_VAL object, const char* key);
+ EM_VAL _emval_get_property_by_long(EM_VAL object, long key);
+ EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key);
+ void _emval_set_property(EM_VAL object, const char* key, EM_VAL value);
+ void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value);
+ void _emval_as(EM_VAL value, emscripten::internal::TypeID returnType);
+ EM_VAL _emval_call(
+ EM_VAL value,
+ unsigned argCount,
+ internal::TypeID argTypes[]
+ /*, ... */);
+ EM_VAL _emval_call_method(
+ EM_VAL value,
+ const char* methodName,
+ unsigned argCount,
+ internal::TypeID argTypes[]
+ /*, ... */);
+ }
+ }
+
+ class val {
+ public:
+ static val object() {
+ return val(internal::_emval_new_object());
+ };
+
+ static val take_ownership(internal::EM_VAL e) {
+ return val(e);
+ }
+
+ explicit val(long l)
+ : handle(internal::_emval_new_long(l))
+ {}
+
+ explicit val(const char* str)
+ : handle(internal::_emval_new_cstring(str))
+ {}
+
+ val() = delete;
+
+ val(const val& v)
+ : handle(v.handle)
+ {
+ internal::_emval_incref(handle);
+ }
+
+ ~val() {
+ internal::_emval_decref(handle);
+ }
+
+ val& operator=(const val& v) {
+ internal::_emval_incref(v.handle);
+ internal::_emval_decref(handle);
+ handle = v.handle;
+ return *this;
+ }
+
+ val get(const char* key) const {
+ return val(internal::_emval_get_property(handle, key));
+ }
+
+ val get(int key) const {
+ return get(long(key));
+ }
+
+ val get(unsigned int key) const {
+ typedef unsigned long T;
+ return get(T(key));
+ }
+
+ val get(long key) const {
+ return val(internal::_emval_get_property_by_long(handle, key));
+ }
+
+ val get(unsigned long key) const {
+ return val(internal::_emval_get_property_by_unsigned_long(handle, key));
+ }
+
+ void set(const char* key, val v) {
+ internal::_emval_set_property(handle, key, v.handle);
+ }
+
+ void set(long key, val v) {
+ internal::_emval_set_property_by_int(handle, key, v.handle);
+ }
+
+ template<typename ...Args>
+ val operator()(Args... args) {
+ internal::ArgTypeList<Args...> argList;
+ typedef internal::EM_VAL (*TypedCall)(
+ internal::EM_VAL,
+ unsigned,
+ internal::TypeID argTypes[],
+ typename internal::BindingType<Args>::WireType...);
+ TypedCall typedCall = reinterpret_cast<TypedCall>(&internal::_emval_call);
+ return val(
+ typedCall(
+ handle,
+ argList.count,
+ argList.types,
+ internal::toWireType(args)...));
+ }
+
+ template<typename ...Args>
+ val call(const char* name, Args... args) {
+ internal::ArgTypeList<Args...> argList;
+ typedef internal::EM_VAL (*TypedCall)(
+ internal::EM_VAL,
+ const char* name,
+ unsigned,
+ internal::TypeID argTypes[],
+ typename internal::BindingType<Args>::WireType...);
+ TypedCall typedCall = reinterpret_cast<TypedCall>(&internal::_emval_call_method);
+ return val(
+ typedCall(
+ handle,
+ name,
+ argList.count,
+ argList.types,
+ internal::toWireType(args)...));
+ }
+
+ template<typename T>
+ T as() const {
+ typedef internal::BindingType<T> BT;
+
+ typedef typename BT::WireType (*TypedAs)(
+ internal::EM_VAL value,
+ emscripten::internal::TypeID returnType);
+ TypedAs typedAs = reinterpret_cast<TypedAs>(&internal::_emval_as);
+
+ typename BT::WireType wt = typedAs(handle, internal::getTypeID<T>());
+ internal::WireDeleter<T> deleter(wt);
+ return BT::fromWireType(wt);
+ }
+
+ private:
+ // takes ownership, assumes handle already incref'd
+ explicit val(internal::EM_VAL handle)
+ : handle(handle)
+ {}
+
+ internal::EM_VAL handle;
+
+ friend struct internal::BindingType<val>;
+ };
+
+ namespace internal {
+ template<>
+ struct BindingType<val> {
+ typedef internal::EM_VAL WireType;
+ static WireType toWireType(val v) {
+ _emval_incref(v.handle);
+ return v.handle;
+ }
+ static val fromWireType(WireType v) {
+ return val(v);
+ }
+ };
+ }
+}
diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h
new file mode 100644
index 00000000..722bf4b8
--- /dev/null
+++ b/system/include/emscripten/wire.h
@@ -0,0 +1,223 @@
+#pragma once
+
+// A value moving between JavaScript and C++ has three representations:
+// - The original JS value: a String
+// - The native on-the-wire value: a stack-allocated char*, say
+// - The C++ value: std::string
+//
+// We'll call the on-the-wire type WireType.
+
+namespace emscripten {
+ namespace internal {
+ typedef const struct _TypeID* TypeID;
+
+ // This implementation is technically not legal, as it's not
+ // required that two calls to typeid produce the same exact
+ // std::type_info instance. That said, it's likely to work.
+ // Should it not work in the future: replace TypeID with
+ // an int, and store all TypeInfo we see in a map, allocating
+ // new TypeIDs as we add new items to the map.
+ template<typename T>
+ inline TypeID getTypeID() {
+ return reinterpret_cast<TypeID>(&typeid(T));
+ }
+
+ // count<>
+
+ template<typename... Args>
+ struct count;
+
+ template<>
+ struct count<> {
+ enum { value = 0 };
+ };
+
+ template<typename T, typename... Args>
+ struct count<T, Args...> {
+ enum { value = 1 + count<Args...>::value };
+ };
+
+ // ArgTypeList<>
+
+ template<typename... Args>
+ struct ArgTypes;
+
+ template<>
+ struct ArgTypes<> {
+ static void fill(TypeID* argTypes) {
+ }
+ };
+
+ template<typename T, typename... Args>
+ struct ArgTypes<T, Args...> {
+ static void fill(TypeID* argTypes) {
+ *argTypes = getTypeID<T>();
+ return ArgTypes<Args...>::fill(argTypes + 1);
+ }
+ };
+
+ template<typename... Args>
+ struct ArgTypeList {
+ enum { args_count = count<Args...>::value };
+
+ ArgTypeList() {
+ count = args_count;
+ ArgTypes<Args...>::fill(types);
+ }
+
+ unsigned count;
+ TypeID types[args_count];
+ };
+
+ // BindingType<T>
+
+ template<typename T>
+ struct BindingType;
+
+#define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \
+ template<> \
+ struct BindingType<type> { \
+ typedef type WireType; \
+ \
+ constexpr static WireType toWireType(type v) { \
+ return v; \
+ } \
+ constexpr static type fromWireType(WireType v) { \
+ return v; \
+ } \
+ static void destroy(WireType) { \
+ } \
+ }
+
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(char);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(signed char);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(unsigned char);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(signed short);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(unsigned short);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(signed int);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(unsigned int);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(signed long);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(unsigned long);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(float);
+ EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(double);
+
+ template<>
+ struct BindingType<void> {
+ };
+
+ template<>
+ struct BindingType<bool> {
+ typedef bool WireType;
+ static WireType toWireType(bool b) {
+ return b;
+ }
+ static bool fromWireType(WireType wt) {
+ return wt;
+ }
+ static void destroy(WireType) {
+ }
+ };
+
+ template<>
+ struct BindingType<std::string> {
+ typedef char* WireType;
+ static WireType toWireType(std::string v) {
+ return strdup(v.c_str());
+ }
+ static std::string fromWireType(char* v) {
+ return std::string(v);
+ }
+ };
+
+ template<>
+ struct BindingType<const std::string&> {
+ typedef char* WireType;
+ static WireType toWireType(std::string v) {
+ return strdup(v.c_str());
+ }
+ static std::string fromWireType(char* v) {
+ return std::string(v);
+ }
+ };
+
+ template<typename Enum>
+ struct EnumBindingType {
+ typedef Enum WireType;
+
+ static WireType toWireType(Enum v) {
+ return v;
+ }
+ static Enum fromWireType(WireType v) {
+ return v;
+ }
+ };
+
+ template<typename T>
+ struct GenericBindingType {
+ typedef typename std::remove_reference<T>::type ActualT;
+ typedef ActualT* WireType;
+
+ struct Marshaller {
+ explicit Marshaller(WireType wt)
+ : wireType(wt)
+ {}
+
+ Marshaller(Marshaller&& wt)
+ : wireType(wt.wireType)
+ {
+ wt.wireType = 0;
+ }
+
+ operator ActualT&() const {
+ return *wireType;
+ }
+
+ private:
+ Marshaller() = delete;
+ Marshaller(const Marshaller&) = delete;
+ ActualT* wireType;
+ };
+
+ static WireType toWireType(T v) {
+ return new T(v);
+ }
+
+ static Marshaller fromWireType(WireType p) {
+ return Marshaller(p);
+ }
+
+ static void destroy(WireType p) {
+ delete p;
+ }
+ };
+
+ template<typename T>
+ struct WireDeleter {
+ typedef typename BindingType<T>::WireType WireType;
+
+ WireDeleter(WireType wt)
+ : wt(wt)
+ {}
+
+ ~WireDeleter() {
+ BindingType<T>::destroy(wt);
+ }
+
+ WireType wt;
+ };
+
+ // catch-all generic binding
+ template<typename T>
+ struct BindingType : std::conditional<
+ std::is_enum<T>::value,
+ EnumBindingType<T>,
+ GenericBindingType<T>>::type
+ {};
+
+ template<typename T>
+ auto toWireType(const T& v) -> typename BindingType<T>::WireType {
+ return BindingType<T>::toWireType(v);
+ }
+
+ }
+}