diff options
-rw-r--r-- | src/embind/embind.js | 619 | ||||
-rw-r--r-- | src/embind/emval.js | 111 | ||||
-rw-r--r-- | system/include/emscripten/bind.h | 645 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 177 | ||||
-rw-r--r-- | system/include/emscripten/wire.h | 223 | ||||
-rwxr-xr-x | system/lib/embind/bind.cpp | 34 | ||||
-rw-r--r-- | tests/embind/embind_test.cpp | 335 | ||||
-rw-r--r-- | tests/embind/embind_test.js | 341 |
8 files changed, 2485 insertions, 0 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js new file mode 100644 index 00000000..fff19d86 --- /dev/null +++ b/src/embind/embind.js @@ -0,0 +1,619 @@ +/*global Module*/ +/*global _malloc, _free, _memcpy*/ +/*global FUNCTION_TABLE, HEAP32*/ +/*global Pointer_stringify, writeStringToMemory*/ +/*global __emval_register, _emval_handle_array, __emval_decref*/ + +function createNamedFunction(name, body) { + /*jshint evil:true*/ + return new Function( + "body", + "return function " + name + "() {\n" + + " return body.apply(this, arguments);\n" + + "};\n" + )(body); +} + +function _embind_repr(v) { + var t = typeof v; + if (t === 'object' || t === 'array' || t === 'function') { + return v.toString(); + } else { + return '' + v; + } +} + +var typeRegistry = {}; + +function validateType(type, name) { + if (!type) { + throw new BindingError('type "' + name + '" must have a positive integer typeid pointer'); + } + if (undefined !== typeRegistry[type]) { + throw new BindingError('cannot register type "' + name + '" twice'); + } +} + +function __embind_register_void(voidType, name) { + name = Pointer_stringify(name); + validateType(voidType, name); + typeRegistry[voidType] = { + name: name, + fromWireType: function() { + return undefined; + } + }; +} + +function __embind_register_bool(boolType, name, trueValue, falseValue) { + name = Pointer_stringify(name); + validateType(boolType, name); + typeRegistry[boolType] = { + name: name, + toWireType: function(destructors, o) { + return o ? trueValue : falseValue; + }, + fromWireType: function(wt) { + return wt === trueValue; + }, + }; +} + +function __embind_register_integer(primitiveType, name) { + name = Pointer_stringify(name); + validateType(primitiveType, name); + typeRegistry[primitiveType] = { + name: name, + toWireType: function(destructors, value) { + if (typeof value !== "number") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + name); + } + return value | 0; + }, + fromWireType: function(value) { + return value; + } + }; +} + +function __embind_register_float(primitiveType, name) { + name = Pointer_stringify(name); + validateType(primitiveType, name); + typeRegistry[primitiveType] = { + name: name, + toWireType: function(destructors, value) { + if (typeof value !== "number") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + name); + } + return value; + }, + fromWireType: function(value) { + return value; + } + }; +} + +function __embind_register_cstring(stringType, name) { + name = Pointer_stringify(name); + validateType(stringType, name); + typeRegistry[stringType] = { + name: name, + toWireType: function(destructors, value) { + var ptr = _malloc(value.length + 1); + writeStringToMemory(value, ptr); + destructors.push(_free); + destructors.push(ptr); + return ptr; + }, + fromWireType: function(value) { + var rv = Pointer_stringify(value); + _free(value); + return rv; + } + }; +} + +function __embind_register_emval(emvalType, name) { + name = Pointer_stringify(name); + validateType(emvalType, name); + typeRegistry[emvalType] = { + name: name, + toWireType: function(destructors, value) { + return __emval_register(value); + }, + fromWireType: function(handle) { + var rv = _emval_handle_array[handle].value; + __emval_decref(handle); + return rv; + } + }; +} + +var BindingError = Error; +/** @expose */ +Module.BindingError = BindingError; + +function typeName(typeID) { + // could use our carnal knowledge of RTTI but for now just return the pointer... + return typeID; +} + +function requireRegisteredType(type, humanName) { + var impl = typeRegistry[type]; + if (undefined === impl) { + throw new BindingError(humanName + " has unknown type: " + typeName(type)); + } + return impl; +} + +function requireArgumentTypes(argCount, argTypes, name) { + var argTypeImpls = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + var argType = HEAP32[(argTypes >> 2) + i]; + argTypeImpls[i] = requireRegisteredType(argType, name + " parameter " + i); + } + return argTypeImpls; +} + +function runDestructors(destructors) { + while (destructors.length) { + var ptr = destructors.pop(); + var del = destructors.pop(); + del(ptr); + } +} + +function __embind_register_function(name, returnType, argCount, argTypes, invoker, fn) { + name = Pointer_stringify(name); + returnType = requireRegisteredType(returnType, "Function " + name + " return value"); + invoker = FUNCTION_TABLE[invoker]; + argTypes = requireArgumentTypes(argCount, argTypes, name); + + Module[name] = function() { + if (arguments.length !== argCount) { + throw new BindingError('emscripten binding function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + var destructors = []; + var args = new Array(argCount + 1); + args[0] = fn; + for (var i = 0; i < argCount; ++i) { + args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]); + } + var rv = returnType.fromWireType(invoker.apply(null, args)); + runDestructors(destructors); + return rv; + }; +} + +function __embind_register_tuple(tupleType, name, constructor, destructor) { + name = Pointer_stringify(name); + constructor = FUNCTION_TABLE[constructor]; + destructor = FUNCTION_TABLE[destructor]; + + var elements = []; + + typeRegistry[tupleType] = { + name: name, + elements: elements, + fromWireType: function(ptr) { + var len = elements.length; + var rv = new Array(len); + for (var i = 0; i < len; ++i) { + rv[i] = elements[i].read(ptr); + } + destructor(ptr); + return rv; + }, + toWireType: function(destructors, o) { + var len = elements.length; + if (len !== o.length) { + throw new TypeError("Incorrect number of tuple elements"); + } + var ptr = constructor(); + for (var i = 0; i < len; ++i) { + elements[i].write(ptr, o[i]); + } + destructors.push(destructor); + destructors.push(ptr); + return ptr; + } + }; +} + +function copyMemberPointer(memberPointer, memberPointerSize) { + var copy = _malloc(memberPointerSize); + if (!copy) { + throw new Error('Failed to allocate member pointer copy'); + } + _memcpy(copy, memberPointer, memberPointerSize); + return copy; +} + +function __embind_register_tuple_element( + tupleType, + elementType, + getter, + setter, + memberPointerSize, + memberPointer +) { + tupleType = requireRegisteredType(tupleType, 'tuple'); + elementType = requireRegisteredType(elementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + getter = FUNCTION_TABLE[getter]; + setter = FUNCTION_TABLE[setter]; + memberPointer = copyMemberPointer(memberPointer, memberPointerSize); + + tupleType.elements.push({ + read: function(ptr) { + return elementType.fromWireType(getter(ptr, memberPointer)); + }, + write: function(ptr, o) { + var destructors = []; + setter(ptr, memberPointer, elementType.toWireType(destructors, o)); + runDestructors(destructors); + } + }); +} + +function __embind_register_tuple_element_accessor( + tupleType, + elementType, + staticGetter, + getterSize, + getter, + staticSetter, + setterSize, + setter +) { + tupleType = requireRegisteredType(tupleType, 'tuple'); + elementType = requireRegisteredType(elementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + staticGetter = FUNCTION_TABLE[staticGetter]; + getter = copyMemberPointer(getter, getterSize); + staticSetter = FUNCTION_TABLE[staticSetter]; + setter = copyMemberPointer(setter, setterSize); + + tupleType.elements.push({ + read: function(ptr) { + return elementType.fromWireType(staticGetter(ptr, HEAP32[getter >> 2])); + }, + write: function(ptr, o) { + var destructors = []; + staticSetter( + ptr, + HEAP32[setter >> 2], + elementType.toWireType(destructors, o)); + runDestructors(destructors); + } + }); +} + +function __embind_register_struct( + structType, + name, + constructor, + destructor +) { + name = Pointer_stringify(name); + constructor = FUNCTION_TABLE[constructor]; + destructor = FUNCTION_TABLE[destructor]; + + typeRegistry[structType] = { + fields: {}, + fromWireType: function(ptr) { + var fields = this.fields; + var rv = {}; + for (var i in fields) { + rv[i] = fields[i].read(ptr); + } + destructor(ptr); + return rv; + }, + toWireType: function(destructors, o) { + var fields = this.fields; + for (var fieldName in fields) { + if (!(fieldName in o)) { + throw new TypeError('Missing field'); + } + } + var ptr = constructor(); + for (var fieldName in fields) { + fields[fieldName].write(ptr, o[fieldName]); + } + destructors.push(destructor); + destructors.push(ptr); + return ptr; + } + }; +} + +function __embind_register_struct_field( + structType, + fieldName, + fieldType, + getter, + setter, + memberPointerSize, + memberPointer +) { + structType = requireRegisteredType(structType, 'struct'); + fieldName = Pointer_stringify(fieldName); + fieldType = requireRegisteredType(fieldType, 'field "' + structType.name + '.' + fieldName + '"'); + getter = FUNCTION_TABLE[getter]; + setter = FUNCTION_TABLE[setter]; + memberPointer = copyMemberPointer(memberPointer, memberPointerSize); + + structType.fields[fieldName] = { + read: function(ptr) { + return fieldType.fromWireType(getter(ptr, memberPointer)); + }, + write: function(ptr, o) { + var destructors = []; + setter(ptr, memberPointer, fieldType.toWireType(destructors, o)); + runDestructors(destructors); + } + }; +} + +function __embind_register_class( + classType, + name, + destructor +) { + name = Pointer_stringify(name); + destructor = FUNCTION_TABLE[destructor]; + + var Handle = createNamedFunction(name, function(ptr) { + this.count = {value: 1}; + this.ptr = ptr; + }); + + Handle.prototype.clone = function() { + if (!this.ptr) { + throw new BindingError(classType.name + ' instance already deleted'); + } + + var clone = Object.create(Handle.prototype); + clone.count = this.count; + clone.ptr = this.ptr; + + clone.count.value += 1; + return clone; + }; + + Handle.prototype.move = function() { + var rv = this.clone(); + this.delete(); + return rv; + }; + + Handle.prototype['delete'] = function() { + if (!this.ptr) { + throw new BindingError(classType.name + ' instance already deleted'); + } + + this.count.value -= 1; + if (0 === this.count.value) { + destructor(this.ptr); + } + this.ptr = undefined; + }; + + var constructor = createNamedFunction(name, function() { + var body = constructor.body; + body.apply(this, arguments); + }); + constructor.prototype = Object.create(Handle.prototype); + + typeRegistry[classType] = { + name: name, + constructor: constructor, + Handle: Handle, + fromWireType: function(ptr) { + return new Handle(ptr); + }, + toWireType: function(destructors, o) { + return o.ptr; + } + }; + + Module[name] = constructor; +} + +function __embind_register_class_constructor( + classType, + argCount, + argTypes, + constructor +) { + classType = requireRegisteredType(classType, 'class'); + var humanName = 'constructor ' + classType.name; + argTypes = requireArgumentTypes(argCount, argTypes, humanName); + constructor = FUNCTION_TABLE[constructor]; + + classType.constructor.body = function() { + if (arguments.length !== argCount) { + throw new BindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + var destructors = []; + var args = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i]); + } + + var ptr = constructor.apply(null, args); + runDestructors(destructors); + classType.Handle.call(this, ptr); + }; +} + +function __embind_register_class_method( + classType, + methodName, + returnType, + argCount, + argTypes, + invoker, + memberFunctionSize, + memberFunction +) { + classType = requireRegisteredType(classType, 'class'); + methodName = Pointer_stringify(methodName); + var humanName = classType.name + '.' + methodName; + returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); + argTypes = requireArgumentTypes(argCount, argTypes, 'method ' + humanName); + invoker = FUNCTION_TABLE[invoker]; + memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); + + classType.Handle.prototype[methodName] = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== argCount) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + + var destructors = []; + var args = new Array(argCount + 2); + args[0] = this.ptr; + args[1] = memberFunction; + for (var i = 0; i < argCount; ++i) { + args[i + 2] = argTypes[i].toWireType(destructors, arguments[i]); + } + + var rv = returnType.fromWireType(invoker.apply(null, args)); + runDestructors(destructors); + return rv; + }; +} + +function __embind_register_class_classmethod( + classType, + methodName, + returnType, + argCount, + argTypes, + method +) { + classType = requireRegisteredType(classType, 'class'); + methodName = Pointer_stringify(methodName); + var humanName = classType.name + '.' + methodName; + returnType = requireRegisteredType(returnType, 'classmethod ' + humanName + ' return value'); + argTypes = requireArgumentTypes(argCount, argTypes, 'classmethod ' + humanName); + method = FUNCTION_TABLE[method]; + + classType.constructor[methodName] = function() { + if (arguments.length !== argCount) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + + var destructors = []; + var args = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i]); + } + + var rv = returnType.fromWireType(method.apply(null, args)); + runDestructors(destructors); + return rv; + }; +} + +function __embind_register_class_field( + classType, + fieldName, + fieldType, + getter, + setter, + memberPointerSize, + memberPointer +) { + classType = requireRegisteredType(classType, 'class'); + fieldName = Pointer_stringify(fieldName); + var humanName = classType.name + '.' + fieldName; + fieldType = requireRegisteredType(fieldType, 'field ' + humanName); + getter = FUNCTION_TABLE[getter]; + setter = FUNCTION_TABLE[setter]; + memberPointer = copyMemberPointer(memberPointer, memberPointerSize); + + Object.defineProperty(classType.Handle.prototype, fieldName, { + get: function() { + if (!this.ptr) { + throw new BindingError('cannot access emscripten binding field ' + humanName + ' on deleted object'); + } + return fieldType.fromWireType(getter(this.ptr, memberPointer)); + }, + set: function(v) { + if (!this.ptr) { + throw new BindingError('cannot modify emscripten binding field ' + humanName + ' on deleted object'); + } + var destructors = []; + setter(this.ptr, memberPointer, fieldType.toWireType(destructors, v)); + runDestructors(destructors); + }, + enumerable: true + }); +} + +function __embind_register_enum( + enumType, + name +) { + name = Pointer_stringify(name); + + function Enum() { + } + Enum.values = {}; + + typeRegistry[enumType] = { + name: name, + constructor: Enum, + toWireType: function(destructors, c) { + return c.value; + }, + fromWireType: function(c) { + return Enum.values[c]; + }, + }; + + Module[name] = Enum; +} + +function __embind_register_enum_value( + enumType, + name, + enumValue +) { + enumType = requireRegisteredType(enumType, 'enum'); + name = Pointer_stringify(name); + + var Enum = enumType.constructor; + + var Value = Object.create(enumType.constructor.prototype, { + value: {value: enumValue}, + constructor: {value: createNamedFunction(enumType.name + '_' + name, function() {})}, + }); + Enum.values[enumValue] = Value; + Enum[name] = Value; +} + +function __embind_register_interface( + interfaceType, + name, + constructor, + destructor +) { + name = Pointer_stringify(name); + constructor = FUNCTION_TABLE[constructor]; + destructor = FUNCTION_TABLE[destructor]; + + typeRegistry[interfaceType] = { + name: name, + toWireType: function(destructors, o) { + var handle = __emval_register(o); + var ptr = constructor(handle); + destructors.push(destructor); + destructors.push(ptr); + return ptr; + }, + }; +} diff --git a/src/embind/emval.js b/src/embind/emval.js new file mode 100644 index 00000000..9574ab37 --- /dev/null +++ b/src/embind/emval.js @@ -0,0 +1,111 @@ +/*global Module*/ +/*global HEAP32*/ +/*global Pointer_stringify, writeStringToMemory*/ +/*global requireRegisteredType*/ + +var _emval_handle_array = []; +var _emval_free_list = []; + +// Public JS API + +/** @expose */ +Module.count_emval_handles = function() { + return _emval_handle_array.length; +}; + +// Private C++ API + +function __emval_register(value) { + var handle = _emval_free_list.length ? + _emval_free_list.pop() : + _emval_handle_array.length; + _emval_handle_array[handle] = {refcount: 1, value: value}; + return handle; +} + +function __emval_incref(handle) { + _emval_handle_array[handle].refcount += 1; +} + +function __emval_decref(handle) { + if (0 === --_emval_handle_array[handle].refcount) { + delete _emval_handle_array[handle]; + _emval_free_list.push(handle); + + var actual_length = _emval_handle_array.length; + while (actual_length > 0 && _emval_handle_array[actual_length - 1] === undefined) { + --actual_length; + } + _emval_handle_array.length = actual_length; + } +} + +function __emval_new_object() { + return __emval_register({}); +} + +function __emval_new_long(value) { + return __emval_register(value); +} + +function __emval_new_cstring(str) { + return __emval_register(Pointer_stringify(str)); +} + +function __emval_get_property(handle, k) { + k = Pointer_stringify(k); + return __emval_register(_emval_handle_array[handle].value[k]); +} + +function __emval_get_property_by_long(handle, k) { + return __emval_register(_emval_handle_array[handle].value[k]); +} + +function __emval_get_property_by_unsigned_long(handle, k) { + return __emval_register(_emval_handle_array[handle].value[k]); +} + +function __emval_set_property(handle, k, value) { + k = Pointer_stringify(k); + _emval_handle_array[handle].value[k] = _emval_handle_array[value].value; +} + +function __emval_set_property_by_int(handle, k, value) { + _emval_handle_array[handle].value[k] = _emval_handle_array[value].value; +} + +function __emval_as(handle, returnType) { + returnType = requireRegisteredType(returnType, 'emval::as'); + var destructors = []; + // caller owns destructing + return returnType.toWireType(destructors, _emval_handle_array[handle].value); +} + +function __emval_call(handle, argCount, argTypes) { + var args = Array.prototype.slice.call(arguments, 3); + var fn = _emval_handle_array[handle].value; + var a = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + var argType = requireRegisteredType( + HEAP32[(argTypes >> 2) + i], + "parameter " + i); + a[i] = argType.fromWireType(args[i]); + } + var rv = fn.apply(undefined, a); + return __emval_register(rv); +} + +function __emval_call_method(handle, name, argCount, argTypes) { + name = Pointer_stringify(name); + var args = Array.prototype.slice.call(arguments, 4); + var obj = _emval_handle_array[handle].value; + var a = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + var argType = requireRegisteredType( + HEAP32[(argTypes >> 2) + i], + "parameter " + i); + a[i] = argType.fromWireType(args[i]); + } + var rv = obj[name].apply(obj, a); + return __emval_register(rv); +} diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h new file mode 100644 index 00000000..8f56ff87 --- /dev/null +++ b/system/include/emscripten/bind.h @@ -0,0 +1,645 @@ +#pragma once + +#include <stddef.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_constructo |