diff --git a/src/embind/embind.js b/src/embind/embind.js index cb4afca7cb1ef..84137302af403 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1941,7 +1941,8 @@ var LibraryEmbind = { rawInvoker, context, isPureVirtual, - isAsync) => { + isAsync, + isNonnullReturn) => { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = readLatin1String(methodName); methodName = getFunctionName(methodName); @@ -2077,7 +2078,8 @@ var LibraryEmbind = { invokerSignature, rawInvoker, fn, - isAsync) => { + isAsync, + isNonnullReturn) => { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = readLatin1String(methodName); methodName = getFunctionName(methodName); diff --git a/src/embind/embind_gen.js b/src/embind/embind_gen.js index a3cae99ea9e6d..6a0a9c811a816 100644 --- a/src/embind/embind_gen.js +++ b/src/embind/embind_gen.js @@ -44,13 +44,13 @@ var LibraryEmbind = { }, $FunctionDefinition__deps: ['$createJsInvoker', '$createJsInvokerSignature', '$emittedFunctions'], $FunctionDefinition: class { - constructor(name, returnType, argumentTypes, functionIndex, thisType = null, isConstructor = false, isAsync = false) { + constructor(name, returnType, argumentTypes, functionIndex, thisType = null, isNonnullReturn = false, isAsync = false) { this.name = name; this.returnType = returnType; this.argumentTypes = argumentTypes; this.functionIndex = functionIndex; this.thisType = thisType; - this.isConstructor = isConstructor; + this.isNonnullReturn = isNonnullReturn; this.isAsync = isAsync; } @@ -80,7 +80,7 @@ var LibraryEmbind = { // Constructors can return a pointer, but it will be a non-null pointer. // Change the return type to the class type so the TS output doesn't // have `| null`. - if (this.isConstructor && this.returnType instanceof PointerDefinition) { + if (this.isNonnullReturn && this.returnType instanceof PointerDefinition) { returnType = this.returnType.classType; } out.push(`): ${nameMap(returnType, true)}`); @@ -463,7 +463,7 @@ var LibraryEmbind = { registerType(id, new IntegerType(id)); }, $createFunctionDefinition__deps: ['$FunctionDefinition', '$heap32VectorToArray', '$readLatin1String', '$Argument', '$whenDependentTypesAreResolved', '$getFunctionName', '$getFunctionArgsName', '$PointerDefinition', '$ClassDefinition'], - $createFunctionDefinition: (name, argCount, rawArgTypesAddr, functionIndex, hasThis, isConstructor, isAsync, cb) => { + $createFunctionDefinition: (name, argCount, rawArgTypesAddr, functionIndex, hasThis, isNonnullReturn, isAsync, cb) => { const argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = typeof name === 'string' ? name : readLatin1String(name); @@ -493,7 +493,7 @@ var LibraryEmbind = { args.push(new Argument(`_${i - argStart}`, argTypes[i])); } } - const funcDef = new FunctionDefinition(name, returnType, args, functionIndex, thisType, isConstructor, isAsync); + const funcDef = new FunctionDefinition(name, returnType, args, functionIndex, thisType, isNonnullReturn, isAsync); cb(funcDef); return []; }); @@ -544,8 +544,8 @@ var LibraryEmbind = { // TODO }, _embind_register_function__deps: ['$moduleDefinitions', '$createFunctionDefinition'], - _embind_register_function: (name, argCount, rawArgTypesAddr, signature, rawInvoker, fn, isAsync) => { - createFunctionDefinition(name, argCount, rawArgTypesAddr, fn, false, false, isAsync, (funcDef) => { + _embind_register_function: (name, argCount, rawArgTypesAddr, signature, rawInvoker, fn, isAsync, isNonnullReturn) => { + createFunctionDefinition(name, argCount, rawArgTypesAddr, fn, false, isNonnullReturn, isAsync, (funcDef) => { moduleDefinitions.push(funcDef); }); }, @@ -605,8 +605,9 @@ var LibraryEmbind = { rawInvoker, context, isPureVirtual, - isAsync) { - createFunctionDefinition(methodName, argCount, rawArgTypesAddr, context, true, false, isAsync, (funcDef) => { + isAsync, + isNonnullReturn) { + createFunctionDefinition(methodName, argCount, rawArgTypesAddr, context, true, isNonnullReturn, isAsync, (funcDef) => { const classDef = funcDef.thisType; classDef.methods.push(funcDef); }); @@ -644,10 +645,11 @@ var LibraryEmbind = { invokerSignature, rawInvoker, fn, - isAsync) { + isAsync, + isNonnullReturn) { whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; - createFunctionDefinition(methodName, argCount, rawArgTypesAddr, fn, false, false, isAsync, (funcDef) => { + createFunctionDefinition(methodName, argCount, rawArgTypesAddr, fn, false, isNonnullReturn, isAsync, (funcDef) => { classType.staticMethods.push(funcDef); }); return []; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 829290901c3f8..b4eb3739e6ecf 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -105,7 +105,8 @@ void _embind_register_function( const char* signature, GenericFunction invoker, GenericFunction function, - bool isAsync); + bool isAsync, + bool isNonnullReturn); void _embind_register_value_array( TYPEID tupleType, @@ -182,7 +183,8 @@ void _embind_register_class_function( GenericFunction invoker, void* context, unsigned isPureVirtual, - bool isAsync); + bool isAsync, + bool isNonnullReturn); void _embind_register_class_property( TYPEID classType, @@ -204,7 +206,8 @@ void _embind_register_class_class_function( const char* invokerSignature, GenericFunction invoker, GenericFunction method, - bool isAsync); + bool isAsync, + bool isNonnullReturn); void _embind_register_class_class_property( TYPEID classType, @@ -338,6 +341,15 @@ struct pure_virtual { }; }; +template +struct nonnull { + static_assert(std::is_same::value, "Only nonnull return values are currently supported."); + template + struct Transform { + typedef InputType type; + }; +}; + namespace return_value_policy { struct take_ownership : public allow_raw_pointers {}; @@ -380,6 +392,11 @@ struct isPolicy { static constexpr bool value = true; }; +template +struct isPolicy, Rest...> { + static constexpr bool value = true; +}; + template struct isPolicy { static constexpr bool value = isPolicy::value; @@ -428,6 +445,24 @@ struct isAsync<> { static constexpr bool value = false; }; +template +struct isNonnullReturn; + +template +struct isNonnullReturn, Rest...> { + static constexpr bool value = true; +}; + +template +struct isNonnullReturn { + static constexpr bool value = isNonnullReturn::value; +}; + +template<> +struct isNonnullReturn<> { + static constexpr bool value = false; +}; + } //////////////////////////////////////////////////////////////////////////////// @@ -640,7 +675,8 @@ void function(const char* name, ReturnType (*fn)(Args...), Policies...) { getSignature(invoke), reinterpret_cast(invoke), reinterpret_cast(fn), - isAsync::value); + isAsync::value, + isNonnullReturn::value); } namespace internal { @@ -1516,7 +1552,8 @@ struct RegisterClassMethod { reinterpret_cast(invoke), getContext(memberFunction), isPureVirtual::value, - isAsync::value); + isAsync::value, + isNonnullReturn::value); } }; @@ -1545,7 +1582,8 @@ struct RegisterClassMethod { reinterpret_cast(invoke), getContext(memberFunction), isPureVirtual::value, - isAsync::value); + isAsync::value, + isNonnullReturn::value); } }; @@ -1573,7 +1611,8 @@ struct RegisterClassMethod { reinterpret_cast(invoke), getContext(function), false, - isAsync::value); + isAsync::value, + isNonnullReturn::value); } }; @@ -1601,7 +1640,8 @@ struct RegisterClassMethod> { reinterpret_cast(invoke), getContext(function), false, - isAsync::value); + isAsync::value, + isNonnullReturn::value); } }; @@ -1623,7 +1663,8 @@ struct RegisterClassMethod { reinterpret_cast(invoke), getContext(callable), false, - isAsync::value); + isAsync::value, + isNonnullReturn::value); } }; @@ -1752,7 +1793,7 @@ class class_ { class_function( "implement", &wrapped_new, - allow_raw_pointer()) + allow_raw_pointer(), nonnull()) .class_function( "extend", &wrapped_extend) @@ -1940,7 +1981,8 @@ class class_ { getSignature(invoke), reinterpret_cast(invoke), reinterpret_cast(classMethod), - isAsync::value); + isAsync::value, + isNonnullReturn::value); return *this; } diff --git a/test/other/embind_tsgen.cpp b/test/other/embind_tsgen.cpp index 435b9a7883dbc..38eebed2d37c2 100644 --- a/test/other/embind_tsgen.cpp +++ b/test/other/embind_tsgen.cpp @@ -91,6 +91,7 @@ int smart_ptr_function(std::shared_ptr) { struct Obj {}; Obj* get_pointer(Obj* ptr) { return ptr; } +Obj* get_nonnull_pointer() { return new Obj(); } int function_with_callback_param(CallbackType ct) { ct(val("hello")); @@ -127,6 +128,18 @@ class DerivedClass : public BaseClass { int fn2(int x) { return 2; } }; +struct Interface { + virtual void invoke(const std::string& str) = 0; + virtual ~Interface() {} +}; + +struct InterfaceWrapper : public wrapper { + EMSCRIPTEN_WRAPPER(InterfaceWrapper); + void invoke(const std::string& str) { + return call("invoke", str); + } +}; + EMSCRIPTEN_BINDINGS(Test) { class_("Test") .function("functionOne", &Test::function_one) @@ -151,6 +164,7 @@ EMSCRIPTEN_BINDINGS(Test) { &class_unique_ptr_returning_fn); class_("Obj"); function("getPointer", &get_pointer, allow_raw_pointers()); + function("getNonnullPointer", &get_nonnull_pointer, allow_raw_pointers(), nonnull()); constant("an_int", 5); constant("a_bool", false); @@ -225,6 +239,11 @@ EMSCRIPTEN_BINDINGS(Test) { class_>("DerivedClass") .function("fn2", &DerivedClass::fn2); + + class_("Interface") + .function("invoke", &Interface::invoke, pure_virtual()) + .allow_subclass("InterfaceWrapper") + ; } int Test::static_property = 42; diff --git a/test/other/embind_tsgen.d.ts b/test/other/embind_tsgen.d.ts index fc6dc767b2e9f..28e3aff37a871 100644 --- a/test/other/embind_tsgen.d.ts +++ b/test/other/embind_tsgen.d.ts @@ -95,6 +95,16 @@ export interface DerivedClass extends BaseClass { delete(): void; } +export interface Interface { + invoke(_0: EmbindString): void; + delete(): void; +} + +export interface InterfaceWrapper extends Interface { + notifyOnDestruction(): void; + delete(): void; +} + export type ValArr = [ number, number, number ]; export type ValObj = { @@ -117,6 +127,7 @@ interface EmbindModule { class_unique_ptr_returning_fn(): Test; Obj: {}; getPointer(_0: Obj | null): Obj | null; + getNonnullPointer(): Obj; a_class_instance: Test; an_enum: Bar; Bar: {valueOne: BarValue<0>, valueTwo: BarValue<1>, valueThree: BarValue<2>}; @@ -141,6 +152,11 @@ interface EmbindModule { }; BaseClass: {}; DerivedClass: {}; + Interface: { + implement(_0: any): InterfaceWrapper; + extend(_0: EmbindString, _1: any): any; + }; + InterfaceWrapper: {}; a_bool: boolean; an_int: number; optional_test(_0?: Foo): number | undefined; diff --git a/test/other/embind_tsgen_ignore_1.d.ts b/test/other/embind_tsgen_ignore_1.d.ts index fd9ddb04741cc..9c22a502344b1 100644 --- a/test/other/embind_tsgen_ignore_1.d.ts +++ b/test/other/embind_tsgen_ignore_1.d.ts @@ -104,6 +104,16 @@ export interface DerivedClass extends BaseClass { delete(): void; } +export interface Interface { + invoke(_0: EmbindString): void; + delete(): void; +} + +export interface InterfaceWrapper extends Interface { + notifyOnDestruction(): void; + delete(): void; +} + export type ValArr = [ number, number, number ]; export type ValObj = { @@ -126,6 +136,7 @@ interface EmbindModule { class_unique_ptr_returning_fn(): Test; Obj: {}; getPointer(_0: Obj | null): Obj | null; + getNonnullPointer(): Obj; a_class_instance: Test; an_enum: Bar; Bar: {valueOne: BarValue<0>, valueTwo: BarValue<1>, valueThree: BarValue<2>}; @@ -150,6 +161,11 @@ interface EmbindModule { }; BaseClass: {}; DerivedClass: {}; + Interface: { + implement(_0: any): InterfaceWrapper; + extend(_0: EmbindString, _1: any): any; + }; + InterfaceWrapper: {}; a_bool: boolean; an_int: number; optional_test(_0?: Foo): number | undefined; diff --git a/test/other/embind_tsgen_ignore_2.d.ts b/test/other/embind_tsgen_ignore_2.d.ts index e81e46aa0e85e..a6134689e1f70 100644 --- a/test/other/embind_tsgen_ignore_2.d.ts +++ b/test/other/embind_tsgen_ignore_2.d.ts @@ -81,6 +81,16 @@ export interface DerivedClass extends BaseClass { delete(): void; } +export interface Interface { + invoke(_0: EmbindString): void; + delete(): void; +} + +export interface InterfaceWrapper extends Interface { + notifyOnDestruction(): void; + delete(): void; +} + export type ValArr = [ number, number, number ]; export type ValObj = { @@ -103,6 +113,7 @@ interface EmbindModule { class_unique_ptr_returning_fn(): Test; Obj: {}; getPointer(_0: Obj | null): Obj | null; + getNonnullPointer(): Obj; a_class_instance: Test; an_enum: Bar; Bar: {valueOne: BarValue<0>, valueTwo: BarValue<1>, valueThree: BarValue<2>}; @@ -127,6 +138,11 @@ interface EmbindModule { }; BaseClass: {}; DerivedClass: {}; + Interface: { + implement(_0: any): InterfaceWrapper; + extend(_0: EmbindString, _1: any): any; + }; + InterfaceWrapper: {}; a_bool: boolean; an_int: number; optional_test(_0?: Foo): number | undefined; diff --git a/test/other/embind_tsgen_ignore_3.d.ts b/test/other/embind_tsgen_ignore_3.d.ts index fc6dc767b2e9f..28e3aff37a871 100644 --- a/test/other/embind_tsgen_ignore_3.d.ts +++ b/test/other/embind_tsgen_ignore_3.d.ts @@ -95,6 +95,16 @@ export interface DerivedClass extends BaseClass { delete(): void; } +export interface Interface { + invoke(_0: EmbindString): void; + delete(): void; +} + +export interface InterfaceWrapper extends Interface { + notifyOnDestruction(): void; + delete(): void; +} + export type ValArr = [ number, number, number ]; export type ValObj = { @@ -117,6 +127,7 @@ interface EmbindModule { class_unique_ptr_returning_fn(): Test; Obj: {}; getPointer(_0: Obj | null): Obj | null; + getNonnullPointer(): Obj; a_class_instance: Test; an_enum: Bar; Bar: {valueOne: BarValue<0>, valueTwo: BarValue<1>, valueThree: BarValue<2>}; @@ -141,6 +152,11 @@ interface EmbindModule { }; BaseClass: {}; DerivedClass: {}; + Interface: { + implement(_0: any): InterfaceWrapper; + extend(_0: EmbindString, _1: any): any; + }; + InterfaceWrapper: {}; a_bool: boolean; an_int: number; optional_test(_0?: Foo): number | undefined;