diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-02-10 15:16:14 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-02-10 15:16:14 -0800 |
commit | ed896c9c00edc7c7bdd4c4cfaca057509c3cd628 (patch) | |
tree | a4721bedbe82d57cff7f6a94dbd2ed8e5b8425dc | |
parent | 8eb52e34be029cd7f276871c830b02fdf53ed00c (diff) | |
parent | b5cf147e6ce7a8d3277342d87beec76290a578bf (diff) |
Merge pull request #2099 from waywardmonkeys/upstream-from-imvu
Upstream from imvu
-rwxr-xr-x | scons-tools/emscripten.py | 5 | ||||
-rw-r--r-- | src/embind/emval.js | 36 | ||||
-rw-r--r-- | system/include/emscripten/bind.h | 52 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 55 | ||||
-rw-r--r-- | system/include/emscripten/wire.h | 32 | ||||
-rw-r--r-- | tests/embind/embind.test.js | 72 | ||||
-rw-r--r-- | tests/embind/embind_test.cpp | 61 |
7 files changed, 235 insertions, 78 deletions
diff --git a/scons-tools/emscripten.py b/scons-tools/emscripten.py index b4912aaa..4c48083e 100755 --- a/scons-tools/emscripten.py +++ b/scons-tools/emscripten.py @@ -316,6 +316,11 @@ def generate(env): def depend_on_embedder(target, source, env):
env.Depends(target, env['JS_EMBEDDER'])
+ files = []
+ for src in source:
+ for dirpath, dirnames, filenames in os.walk(str(src.srcnode())):
+ files.extend(map(lambda p: os.path.join(dirpath, p), filenames))
+ env.Depends(target, env.Value(sorted(files)))
return target, source
def embed_files_in_js(target, source, env, for_signature):
diff --git a/src/embind/emval.js b/src/embind/emval.js index 0d075188..039f1d61 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -3,7 +3,7 @@ /*global new_*/ /*global createNamedFunction*/ /*global readLatin1String, writeStringToMemory*/ -/*global requireRegisteredType, throwBindingError*/ +/*global requireRegisteredType, throwBindingError, runDestructors*/ /*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */ var Module = Module || {}; @@ -79,6 +79,12 @@ function __emval_decref(handle) { } } +function __emval_run_destructors(handle) { + var destructors = _emval_handle_array[handle].value; + runDestructors(destructors); + __emval_decref(handle); +} + function __emval_new_array() { return __emval_register([]); } @@ -199,11 +205,12 @@ function __emval_set_property(handle, key, value) { _emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value; } -function __emval_as(handle, returnType) { +function __emval_as(handle, returnType, destructorsRef) { requireHandle(handle); returnType = requireRegisteredType(returnType, 'emval::as'); var destructors = []; - // caller owns destructing + var rd = __emval_register(destructors); + HEAP32[destructorsRef >> 2] = rd; return returnType['toWireType'](destructors, _emval_handle_array[handle].value); } @@ -242,14 +249,20 @@ function lookupTypes(argCount, argTypes, argWireTypes) { return a; } +function allocateDestructors(destructorsRef) { + var destructors = []; + HEAP32[destructorsRef >> 2] = __emval_register(destructors); + return destructors; +} + function __emval_get_method_caller(argCount, argTypes) { var types = lookupTypes(argCount, argTypes); var retType = types[0]; var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$"; - var args1 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType"]; - var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType]; + var args1 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType", "allocateDestructors"]; + var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType, allocateDestructors]; var argsList = ""; // 'arg0, arg1, arg2, ... , argN' var argsListWired = ""; // 'arg0Wired, ..., argNWired' @@ -261,16 +274,17 @@ function __emval_get_method_caller(argCount, argTypes) { } var invokerFnBody = - "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name" + argsListWired + ") {\n" + - "requireHandle(handle);\n" + - "name = getStringOrSymbol(name);\n"; + "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name, destructorsRef" + argsListWired + ") {\n" + + " requireHandle(handle);\n" + + " name = getStringOrSymbol(name);\n"; for (var i = 0; i < argCount - 1; ++i) { - invokerFnBody += "var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n"; + invokerFnBody += " var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n"; } invokerFnBody += - "var obj = _emval_handle_array[handle].value;\n" + - "return retType.toWireType(null, obj[name](" + argsList + "));\n" + + " var obj = _emval_handle_array[handle].value;\n" + + " var rv = obj[name](" + argsList + ");\n" + + " return retType.toWireType(allocateDestructors(destructorsRef), rv);\n" + "}));\n"; args1.push(invokerFnBody); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 403d8084..4d7547a1 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -533,6 +533,8 @@ namespace emscripten { template<typename ClassType> class value_array : public internal::noncopyable { public: + typedef ClassType class_type; + value_array(const char* name) { using namespace internal; _embind_register_value_array( @@ -605,6 +607,8 @@ namespace emscripten { template<typename ClassType> class value_object : public internal::noncopyable { public: + typedef ClassType class_type; + value_object(const char* name) { using namespace internal; _embind_register_value_object( @@ -689,6 +693,10 @@ namespace emscripten { static void* share(void* v) { return 0; // no sharing } + + static PointerType* construct_null() { + return new PointerType; + } }; // specialize if you have a different pointer type @@ -720,6 +728,10 @@ namespace emscripten { val_deleter(val::take_ownership(v))); } + static PointerType* construct_null() { + return new PointerType; + } + private: class val_deleter { public: @@ -745,6 +757,8 @@ namespace emscripten { template<typename T> class wrapper : public T { public: + typedef T class_type; + explicit wrapper(val&& wrapped) : wrapped(std::forward<val>(wrapped)) {} @@ -794,13 +808,14 @@ namespace emscripten { // NOTE: this returns the class type, not the pointer type template<typename T> inline TYPEID getActualType(T* ptr) { - assert(ptr); return reinterpret_cast<TYPEID>(&typeid(*ptr)); }; } template<typename BaseClass> struct base { + typedef BaseClass class_type; + template<typename ClassType> static void verify() { static_assert(!std::is_same<ClassType, BaseClass>::value, "Base must not have same type as class"); @@ -847,6 +862,9 @@ namespace emscripten { template<typename ClassType, typename BaseSpecifier = internal::NoBaseClass> class class_ { public: + typedef ClassType class_type; + typedef BaseSpecifier base_specifier; + class_() = delete; explicit class_(const char* name) { @@ -867,7 +885,7 @@ namespace emscripten { } template<typename PointerType> - class_& smart_ptr() { + const class_& smart_ptr() const { using namespace internal; typedef smart_ptr_trait<PointerType> PointerTrait; @@ -881,21 +899,21 @@ namespace emscripten { typeid(PointerType).name(), PointerTrait::get_sharing_policy(), reinterpret_cast<GenericFunction>(&PointerTrait::get), - reinterpret_cast<GenericFunction>(&operator_new<PointerType>), + reinterpret_cast<GenericFunction>(&PointerTrait::construct_null), reinterpret_cast<GenericFunction>(&PointerTrait::share), reinterpret_cast<GenericFunction>(&raw_destructor<PointerType>)); return *this; }; template<typename... ConstructorArgs, typename... Policies> - class_& constructor(Policies... policies) { + const class_& constructor(Policies... policies) const { return constructor( &internal::operator_new<ClassType, ConstructorArgs...>, policies...); } template<typename... Args, typename ReturnType, typename... Policies> - class_& constructor(ReturnType (*factory)(Args...), Policies...) { + const class_& constructor(ReturnType (*factory)(Args...), Policies...) const { using namespace internal; // TODO: allows all raw pointers... policies need a rethink @@ -910,7 +928,7 @@ namespace emscripten { } template<typename SmartPtr, typename... Args, typename... Policies> - class_& smart_ptr_constructor(SmartPtr (*factory)(Args...), Policies...) { + const class_& smart_ptr_constructor(SmartPtr (*factory)(Args...), Policies...) const { using namespace internal; smart_ptr<SmartPtr>(); @@ -926,7 +944,7 @@ namespace emscripten { } template<typename WrapperType, typename PointerType = WrapperType*> - class_& allow_subclass() { + const class_& allow_subclass() const { using namespace internal; auto cls = class_<WrapperType, base<ClassType>>(typeid(WrapperType).name()) @@ -940,7 +958,7 @@ namespace emscripten { } template<typename ReturnType, typename... Args, typename... Policies> - class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) { + const class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) const { using namespace internal; typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<ClassType>, Args...> args; @@ -955,7 +973,7 @@ namespace emscripten { } template<typename ReturnType, typename... Args, typename... Policies> - class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) { + const class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) const { using namespace internal; typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<const ClassType>, Args...> args; @@ -970,7 +988,7 @@ namespace emscripten { } template<typename ReturnType, typename ThisType, typename... Args, typename... Policies> - class_& function(const char* methodName, ReturnType (*function)(ThisType, Args...), Policies...) { + const class_& function(const char* methodName, ReturnType (*function)(ThisType, Args...), Policies...) const { using namespace internal; typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, ThisType, Args...> args; @@ -985,7 +1003,7 @@ namespace emscripten { } template<typename FieldType, typename = typename std::enable_if<!std::is_function<FieldType>::value>::type> - class_& property(const char* fieldName, const FieldType ClassType::*field) { + const class_& property(const char* fieldName, const FieldType ClassType::*field) const { using namespace internal; _embind_register_class_property( @@ -1001,7 +1019,7 @@ namespace emscripten { } template<typename FieldType, typename = typename std::enable_if<!std::is_function<FieldType>::value>::type> - class_& property(const char* fieldName, FieldType ClassType::*field) { + const class_& property(const char* fieldName, FieldType ClassType::*field) const { using namespace internal; _embind_register_class_property( @@ -1017,7 +1035,7 @@ namespace emscripten { } template<typename Getter> - class_& property(const char* fieldName, Getter getter) { + const class_& property(const char* fieldName, Getter getter) const { using namespace internal; typedef GetterPolicy<Getter> GP; _embind_register_class_property( @@ -1033,7 +1051,7 @@ namespace emscripten { } template<typename Getter, typename Setter> - class_& property(const char* fieldName, Getter getter, Setter setter) { + const class_& property(const char* fieldName, Getter getter, Setter setter) const { using namespace internal; typedef GetterPolicy<Getter> GP; typedef SetterPolicy<Setter> SP; @@ -1050,7 +1068,7 @@ namespace emscripten { } template<typename ReturnType, typename... Args, typename... Policies> - class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) { + const class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) const { using namespace internal; typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args; @@ -1157,6 +1175,8 @@ namespace emscripten { template<typename EnumType> class enum_ { public: + typedef EnumType enum_type; + enum_(const char* name) { _embind_register_enum( internal::TypeID<EnumType>::get(), @@ -1199,7 +1219,7 @@ namespace emscripten { _embind_register_constant( name, TypeID<const ConstantType&>::get(), - asGenericValue(BindingType<const ConstantType&>::toWireType(v))); + asGenericValue(BT::toWireType(v))); } } diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index b712d164..19b1beb1 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -11,10 +11,18 @@ namespace emscripten { void _emval_register_symbol(const char*); typedef struct _EM_VAL* EM_VAL; + typedef struct _EM_DESTRUCTORS* EM_DESTRUCTORS; + + // TODO: functions returning this are reinterpret_cast + // into the correct return type. this needs some thought + // for asm.js. + typedef void _POLYMORPHIC_RESULT; void _emval_incref(EM_VAL value); void _emval_decref(EM_VAL value); + void _emval_run_destructors(EM_DESTRUCTORS handle); + EM_VAL _emval_new_array(); EM_VAL _emval_new_object(); EM_VAL _emval_undefined(); @@ -32,7 +40,8 @@ namespace emscripten { EM_VAL _emval_get_module_property(const char* name); EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); - void _emval_as(EM_VAL value, TYPEID returnType); + _POLYMORPHIC_RESULT _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* runDestructors); + EM_VAL _emval_call( EM_VAL value, unsigned argCount, @@ -57,7 +66,11 @@ namespace emscripten { template<typename ReturnType, typename... Args> struct Signature { - typedef typename BindingType<ReturnType>::WireType (*MethodCaller)(EM_VAL value, const char* methodName, typename BindingType<Args>::WireType...); + typedef typename BindingType<ReturnType>::WireType (*MethodCaller)( + EM_VAL value, + const char* methodName, + EM_DESTRUCTORS* destructors, + typename BindingType<Args>::WireType...); static MethodCaller get_method_caller() { static MethodCaller fp = reinterpret_cast<MethodCaller>(init_method_caller()); @@ -71,15 +84,34 @@ namespace emscripten { } }; + struct DestructorsRunner { + public: + explicit DestructorsRunner(EM_DESTRUCTORS d) + : destructors(d) + {} + ~DestructorsRunner() { + _emval_run_destructors(destructors); + } + + DestructorsRunner(const DestructorsRunner&) = delete; + void operator=(const DestructorsRunner&) = delete; + + private: + EM_DESTRUCTORS destructors; + }; + template<typename ReturnType, typename... Args> struct MethodCaller { static ReturnType call(EM_VAL handle, const char* methodName, Args&&... args) { auto caller = Signature<ReturnType, Args...>::get_method_caller(); + + EM_DESTRUCTORS destructors; auto wireType = caller( handle, methodName, + &destructors, toWireType(std::forward<Args>(args))...); - WireDeleter<ReturnType> deleter(wireType); + DestructorsRunner rd(destructors); return BindingType<ReturnType>::fromWireType(wireType); } }; @@ -88,10 +120,15 @@ namespace emscripten { struct MethodCaller<void, Args...> { static void call(EM_VAL handle, const char* methodName, Args&&... args) { auto caller = Signature<void, Args...>::get_method_caller(); - return caller( + + EM_DESTRUCTORS destructors; + caller( handle, methodName, + &destructors, toWireType(std::forward<Args>(args))...); + DestructorsRunner rd(destructors); + // void requires no translation } }; } @@ -262,11 +299,13 @@ namespace emscripten { typedef typename BT::WireType (*TypedAs)( EM_VAL value, - TYPEID returnType); + TYPEID returnType, + EM_DESTRUCTORS* runDestructors); TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as); - typename BT::WireType wt = typedAs(handle, TypeID<T>::get()); - WireDeleter<T> deleter(wt); + EM_DESTRUCTORS destructors; + typename BT::WireType wt = typedAs(handle, TypeID<T>::get(), &destructors); + DestructorsRunner dr(destructors); return BT::fromWireType(wt); } @@ -292,8 +331,6 @@ namespace emscripten { static val fromWireType(WireType v) { return val::take_ownership(v); } - static void destroy(WireType v) { - } }; } diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index a5892216..c3ce8dd0 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -7,6 +7,7 @@ // // We'll call the on-the-wire type WireType. +#include <stdio.h> #include <cstdlib> #include <memory> #include <string> @@ -130,8 +131,6 @@ namespace emscripten { constexpr static type fromWireType(WireType v) { \ return v; \ } \ - static void destroy(WireType) { \ - } \ } EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(char); @@ -160,8 +159,6 @@ namespace emscripten { static bool fromWireType(WireType wt) { return wt; } - static void destroy(WireType) { - } }; template<> @@ -179,9 +176,6 @@ namespace emscripten { static std::string fromWireType(WireType v) { return std::string(v->data, v->length); } - static void destroy(WireType v) { - free(v); - } }; template<> @@ -199,9 +193,6 @@ namespace emscripten { static std::wstring fromWireType(WireType v) { return std::wstring(v->data, v->length); } - static void destroy(WireType v) { - free(v); - } }; template<typename T> @@ -254,10 +245,6 @@ namespace emscripten { static ActualT& fromWireType(WireType p) { return *p; } - - static void destroy(WireType p) { - delete p; - } }; // Is this necessary? @@ -280,8 +267,6 @@ namespace emscripten { static Enum fromWireType(WireType v) { return v; } - static void destroy(WireType) { - } }; // catch-all generic binding @@ -296,21 +281,6 @@ namespace emscripten { auto toWireType(T&& v) -> typename BindingType<T>::WireType { return BindingType<T>::toWireType(std::forward<T>(v)); } - - template<typename T> - struct WireDeleter { - typedef typename BindingType<T>::WireType WireType; - - WireDeleter(WireType wt) - : wt(wt) - {} - - ~WireDeleter() { - BindingType<T>::destroy(wt); - } - - WireType wt; - }; } struct memory_view { diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index da81a81e..5ca972be 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -55,7 +55,7 @@ module({ }); }); }); - + } BaseFixture.extend("access to base class members", function() { @@ -609,7 +609,7 @@ module({ assert.equal("0", cm.unsigned_int_to_string(0)); assert.equal("0", cm.long_to_string(0)); assert.equal("0", cm.unsigned_long_to_string(0)); - + // all types should have positive values. assert.equal("5", cm.char_to_string(5)); assert.equal("5", cm.signed_char_to_string(5)); @@ -650,7 +650,7 @@ module({ assert.equal("-32768", cm.short_to_string(-32768)); assert.equal("-2147483648", cm.int_to_string(-2147483648)); assert.equal("-2147483648", cm.long_to_string(-2147483648)); - + // passing out of range values should fail. assert.throws(TypeError, function() { cm.char_to_string(-129); }); assert.throws(TypeError, function() { cm.char_to_string(128); }); @@ -733,7 +733,7 @@ module({ test("overloading of derived class member functions", function() { var foo = new cm.MultipleOverloadsDerived(); - + // NOTE: In C++, default lookup rules will hide overloads from base class if derived class creates them. // In JS, we make the base class overloads implicitly available. In C++, they would need to be explicitly // invoked, like foo.MultipleOverloads::Func(10); @@ -748,7 +748,7 @@ module({ assert.equal(foo.WhichFuncCalled(), 4); foo.delete(); }); - + test("overloading of class static functions", function() { assert.equal(cm.MultipleOverloads.StaticFunc(10), 1); assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 1); @@ -1441,7 +1441,7 @@ module({ test("repr includes enum value", function() { assert.equal('<#Enum_ONE {}>', IMVU.repr(cm.Enum.ONE)); assert.equal('<#Enum_TWO {}>', IMVU.repr(cm.Enum.TWO)); - }); + }); } test("instanceof", function() { @@ -1591,7 +1591,7 @@ module({ test("returning a new shared pointer from interfaces implemented in JS code does not leak", function() { var impl = cm.AbstractClass.implement({ returnsSharedPtr: function() { - return cm.embind_test_return_smart_derived_ptr(); + return cm.embind_test_return_smart_derived_ptr().deleteLater(); } }); cm.callReturnsSharedPtrMethod(impl); @@ -1644,7 +1644,7 @@ module({ }); if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well! - + BaseFixture.extend("unbound types", function() { function assertMessage(fn, message) { var e = assert.throws(cm.UnboundTypeError, fn); @@ -1689,7 +1689,7 @@ module({ }, 'Cannot construct HasConstructorUsingUnboundArgumentAndUnboundBase due to unbound types: 18SecondUnboundClass'); }); - + test('class function with unbound argument', function() { var x = new cm.BoundClass; assertMessage( @@ -1719,12 +1719,12 @@ module({ }, 'Cannot access BoundClass.property due to unbound types: 12UnboundClass'); x.delete(); }); - + // todo: tuple elements // todo: tuple element accessors // todo: struct fields }); - + } BaseFixture.extend("noncopyable", function() { @@ -1743,6 +1743,10 @@ module({ BaseFixture.extend("constants", function() { assert.equal(10, cm.INT_CONSTANT); + + assert.equal(1, cm.STATIC_CONST_INTEGER_VALUE_1); + assert.equal(1000, cm.STATIC_CONST_INTEGER_VALUE_1000); + assert.equal("some string", cm.STRING_CONSTANT); assert.deepEqual([1, 2, 3, 4], cm.VALUE_ARRAY_CONSTANT); assert.deepEqual({x:1,y:2,z:3,w:4}, cm.VALUE_OBJECT_CONSTANT); @@ -1888,6 +1892,52 @@ module({ sh.delete(); }); }); + + BaseFixture.extend("val::as from pointer to value", function() { + test("calling as on pointer with value makes a copy", function() { + var sh1 = new cm.StringHolder("Hello world"); + var sh2 = cm.return_StringHolder_copy(sh1); + assert.equal("Hello world", sh1.get()); + assert.equal("Hello world", sh2.get()); + assert.false(sh1.isAliasOf(sh2)); + sh2.delete(); + sh1.delete(); + }); + + test("calling function that returns a StringHolder", function() { + var sh1 = new cm.StringHolder("Hello world"); + var sh2 = cm.call_StringHolder_func(function() { + return sh1; + }); + assert.equal("Hello world", sh1.get()); + assert.equal("Hello world", sh2.get()); + assert.false(sh1.isAliasOf(sh2)); + sh2.delete(); + sh1.delete(); + }); + }); + + BaseFixture.extend("mixin", function() { + test("can call mixin method", function() { + var a = new cm.DerivedWithMixin(); + assert.instanceof(a, cm.Base); + assert.equal(10, a.get10()); + a.delete(); + }); + }); + + test("returning a cached new shared pointer from interfaces implemented in JS code does not leak", function() { + var derived = cm.embind_test_return_smart_derived_ptr(); + var impl = cm.AbstractClass.implement({ + returnsSharedPtr: function() { + return derived; + } + }); + cm.callReturnsSharedPtrMethod(impl); + impl.delete(); + derived.delete(); + // Let the memory leak test superfixture check that no leaks occurred. + }); }); /* global run_all_tests */ diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index d6b27bce..4efc4bd8 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1283,6 +1283,7 @@ std::shared_ptr<HeldBySmartPtr> takesHeldBySmartPtrSharedPtr(std::shared_ptr<Hel namespace emscripten { template<typename T> struct smart_ptr_trait<CustomSmartPtr<T>> { + typedef CustomSmartPtr<T> pointer_type; typedef T element_type; static sharing_policy get_sharing_policy() { @@ -1297,6 +1298,10 @@ namespace emscripten { ++ptr->refcount; // implement an adopt API? return CustomSmartPtr<T>(ptr); } + + static pointer_type* construct_null() { + return new pointer_type; + } }; } @@ -2210,8 +2215,20 @@ EMSCRIPTEN_BINDINGS(read_only_properties) { ; } +struct StaticConstIntStruct { + static const int STATIC_CONST_INTEGER_VALUE_1; + static const int STATIC_CONST_INTEGER_VALUE_1000; +}; + +const int StaticConstIntStruct::STATIC_CONST_INTEGER_VALUE_1 = 1; +const int StaticConstIntStruct::STATIC_CONST_INTEGER_VALUE_1000 = 1000; + EMSCRIPTEN_BINDINGS(constants) { constant("INT_CONSTANT", 10); + + constant("STATIC_CONST_INTEGER_VALUE_1", StaticConstIntStruct::STATIC_CONST_INTEGER_VALUE_1); + constant("STATIC_CONST_INTEGER_VALUE_1000", StaticConstIntStruct::STATIC_CONST_INTEGER_VALUE_1000); + constant("STRING_CONSTANT", std::string("some string")); TupleVector tv(1, 2, 3, 4); @@ -2243,3 +2260,47 @@ void clear_StringHolder(StringHolder& sh) { EMSCRIPTEN_BINDINGS(references) { function("clear_StringHolder", &clear_StringHolder); } + +StringHolder return_StringHolder_copy(val func) { + return func.as<StringHolder>(); +} + +StringHolder call_StringHolder_func(val func) { + return func().as<StringHolder>(); +} + +EMSCRIPTEN_BINDINGS(return_values) { + function("return_StringHolder_copy", &return_StringHolder_copy); + function("call_StringHolder_func", &call_StringHolder_func); +} + + +struct Mixin { + int get10() const { + return 10; + } +}; + +template<typename ClassBinding> +const ClassBinding& registerMixin(const ClassBinding& binding) { + // need a wrapper for implicit conversion from DerivedWithMixin to Mixin + struct Local { + static int get10(const typename ClassBinding::class_type& self) { + return self.get10(); + } + }; + + return binding + .function("get10", &Local::get10) + ; +} + +class DerivedWithMixin : public Base, public Mixin { +}; + +EMSCRIPTEN_BINDINGS(mixins) { + registerMixin( + class_<DerivedWithMixin, base<Base>>("DerivedWithMixin") + .constructor<>() + ); +} |