diff options
Diffstat (limited to 'system/include')
-rw-r--r-- | system/include/emscripten/bind.h | 646 | ||||
-rw-r--r-- | system/include/emscripten/emscripten.h | 65 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 177 | ||||
-rw-r--r-- | system/include/emscripten/wire.h | 223 | ||||
-rw-r--r-- | system/include/jansson.h | 305 | ||||
-rw-r--r-- | system/include/jansson_config.h | 54 |
6 files changed, 1466 insertions, 4 deletions
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h new file mode 100644 index 00000000..4a82eacb --- /dev/null +++ b/system/include/emscripten/bind.h @@ -0,0 +1,646 @@ +#pragma once + +#include <stddef.h> +#include <assert.h> +#include <string> +#include <type_traits> +#include <emscripten/val.h> +#include <emscripten/wire.h> + +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; + } + }; + + namespace internal { + template<typename T> + class optional { + public: + optional() + : initialized(false) + {} + + ~optional() { + if (initialized) { + get()->~T(); + } + } + + optional(const optional&) = delete; + + T& operator*() { + assert(initialized); + return *get(); + } + + explicit operator bool() const { + return initialized; + } + + optional& operator=(const T& v) { + if (initialized) { + get()->~T(); + } + new(get()) T(v); + initialized = true; + } + + private: + T* get() { + return reinterpret_cast<T*>(&data); + } + + bool initialized; + typename std::aligned_storage<sizeof(T)>::type data; + }; + } + + 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()); + } + } + + internal::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/emscripten.h b/system/include/emscripten/emscripten.h index 8c42a18a..ed078acd 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -11,6 +11,10 @@ extern "C" { #endif +#if !EMSCRIPTEN +#include <SDL/SDL.h> /* for SDL_Delay in async_call */ +#endif + /* * Forces LLVM to not dead-code-eliminate a function. Note that * closure may still eliminate it at the JS level, for which you @@ -42,11 +46,32 @@ extern void emscripten_async_run_script(const char *script, int millis); * code assumes that), so you can break the code up into * asynchronous callbacks, but you must pause the main * loop until they complete. + * + * @simulate_infinite_loop If true, this function will throw an + * exception in order to stop execution of the caller. This + * will lead to the main loop being entered instead of code + * after the call to emscripten_set_main_loop being run, which + * is the closest we can get to simulating an infinite loop + * (we do something similar in glutMainLoop in GLUT). If this + * parameter is false, then the behavior is the same as it + * was before this parameter was added to the API, which is + * that execution continues normally. Note that in both cases + * we do not run global destructors, atexit, etc., since we + * know the main loop will still be running, but if we do + * not simulate an infinite loop then the stack will be unwinded. + * That means that if simulate_infinite_loop is false, and + * you created an object on the stack, it will be cleaned up + * before the main loop will be called the first time. */ -extern void emscripten_set_main_loop(void (*func)(), int fps); +#if EMSCRIPTEN +extern void emscripten_set_main_loop(void (*func)(), int fps, int simulate_infinite_loop); extern void emscripten_pause_main_loop(); extern void emscripten_resume_main_loop(); extern void emscripten_cancel_main_loop(); +#else +#define emscripten_set_main_loop(func, fps, simulateInfiniteLoop) \ + while (1) func(); +#endif /* * Add a function to a queue of events that will execute @@ -148,14 +173,46 @@ float emscripten_random(); */ /* - * Load file from url in asynchronous way. - * When file is loaded then 'onload' callback will called. + * Load file from url in asynchronous way. In addition to + * fetching the URL from the network, the contents are + * prepared so that the data is usable in IMG_Load and + * so forth (we asynchronously do the work to make the + * browser decode the image or audio and so forth). + * When file is ready then 'onload' callback will called. * If any error occurred 'onerror' will called. * The callbacks are called with the file as their argument. - */ + */ void emscripten_async_wget(const char* url, const char* file, void (*onload)(const char*), void (*onerror)(const char*)); /* + * Prepare a file in asynchronous way. This does just the + * preparation part of emscripten_async_wget, that is, it + * works on file data already present, and asynchronously + * prepares it for use in IMG_Load, Mix_LoadWAV, etc. + * When file is loaded then 'onload' callback will called. + * If any error occurred 'onerror' will called. + * The callbacks are called with the file as their argument. + * @return 0 if successful, -1 if the file does not exist + */ +int emscripten_async_prepare(const char* file, void (*onload)(const char*), void (*onerror)(const char*)); + +/* + * Data version of emscripten_async_prepare, which receives + * raw data as input instead of a filename (this can prevent + * the need to write data to a file first). onload and + * onerror are called back with the given arg pointer as the + * first parameter. onload also receives a second + * parameter, which is a 'fake' filename which you can + * then pass into IMG_Load (it is not an actual file, + * but it identifies this image for IMG_Load to be able + * to process it). Note that the user of this API is + * responsible for free()ing the memory allocated for + * the fake filename. + * @suffix The file suffix, e.g. 'png' or 'jpg'. + */ +void emscripten_async_prepare_data(char* data, int size, const char *suffix, void *arg, void (*onload)(void*, const char*), void (*onerror)(void*)); + +/* * Profiling tools. * INIT must be called first, with the maximum identifier that * will be used. BEGIN will add some code that marks 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); + } |