diff options
author | Chad Austin <chad@chadaustin.me> | 2012-09-25 17:43:20 -0700 |
---|---|---|
committer | Chad Austin <chad@chadaustin.me> | 2012-09-25 18:14:22 -0700 |
commit | 86305a27d4552167f76dd9e19e0c8e45aa645caa (patch) | |
tree | 502d7b67bd9c2c3bf4e284dbe70d50ecf87cf0b8 /system/include | |
parent | c74da50989604747e3174429d0538f668b4ff7e7 (diff) |
Add embind headers
Diffstat (limited to 'system/include')
-rw-r--r-- | system/include/emscripten/bind.h | 602 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 177 | ||||
-rw-r--r-- | system/include/emscripten/wire.h | 223 |
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); + } + + } +} |