From afca6bd61e54a09671ef78d2b1bb3903677638f3 Mon Sep 17 00:00:00 2001 From: Hossein Yousefi Date: Fri, 11 Aug 2023 17:15:23 +0200 Subject: [PATCH] use impl classes for implementing interfaces --- jnigen/lib/src/bindings/dart_generator.dart | 221 ++++++++++++------ .../c_based/dart_bindings/simple_package.dart | 100 +++++--- .../dart_bindings/simple_package.dart | 100 +++++--- .../runtime_test_registrant.dart | 45 ++-- 4 files changed, 313 insertions(+), 153 deletions(-) diff --git a/jnigen/lib/src/bindings/dart_generator.dart b/jnigen/lib/src/bindings/dart_generator.dart index c78a3b25..9dda1265 100644 --- a/jnigen/lib/src/bindings/dart_generator.dart +++ b/jnigen/lib/src/bindings/dart_generator.dart @@ -46,6 +46,7 @@ const _deleteInstruction = ' /// The returned object must be deleted after use, ' 'by calling the `delete` method.'; +// Helper methods extension on Iterable { /// Similar to [join] but adds the [separator] to the end as well. String delimited([String separator = '']) { @@ -309,6 +310,7 @@ class _ClassGenerator extends Visitor { // Class definition final name = node.finalName; final superName = node.superclass!.accept(_TypeGenerator(resolver)); + final implClassName = '\$${name}Impl'; final typeParamsDef = _encloseIfNotEmpty( '<', node.allTypeParams @@ -328,7 +330,7 @@ class _ClassGenerator extends Visitor { typeParams.join(', '), ')', ); - final typeClassDefinitions = typeParams + final typeClassesDef = typeParams .map((typeParam) => 'final $_jType<$_typeParamPrefix$typeParam> $typeParam;') .join(_newLine(depth: 1)); @@ -347,7 +349,7 @@ class $name$typeParamsDef extends $superName { @override late final $_jType<$name$typeParamsCall> $instanceTypeGetter = $staticTypeGetter$staticTypeGetterCallArgs; - $typeClassDefinitions + $typeClassesDef $name.fromRef( $ctorTypeClassesDef @@ -407,24 +409,19 @@ class $name$typeParamsDef extends $superName { (config.experiments?.contains(Experiment.interfaceImplementation) ?? false)) { s.write(''' - /// Maps a specific port to the implemented methods. - static final Map> _\$methods = {}; - - /// Maps a specific port to the type parameters. - static final Map> _\$types = {}; + /// Maps a specific port to the implemented interface. + static final Map _\$impls = {}; ReceivePort? _\$p; static final Finalizer _\$finalizer = Finalizer((\$p) { - _\$methods.remove(\$p.sendPort.nativePort); - _\$types.remove(\$p.sendPort.nativePort); + _\$impls.remove(\$p.sendPort.nativePort); \$p.close(); }); @override void delete() { - _\$methods.remove(_\$p?.sendPort.nativePort); - _\$types.remove(_\$p?.sendPort.nativePort); + _\$impls.remove(_\$p?.sendPort.nativePort); _\$p?.close(); _\$finalizer.detach(this); super.delete(); @@ -467,21 +464,13 @@ class $name$typeParamsDef extends $superName { } factory $name.implement( + $implClassName$typeParamsCall \$impl, + ) { '''); - final typeClassesCall = - typeParams.map((typeParam) => '$typeParam,').join(_newLine(depth: 3)); - s.write(_encloseIfNotEmpty( - '{', - [ - ...typeParams - .map((typeParam) => 'required $_jType<\$$typeParam> $typeParam,'), - ...node.methods.accept(_InterfaceImplementArg(resolver)) - ].join(_newLine(depth: 2)), - '}', - )); - + final typeClassesCall = typeParams + .map((typeParam) => '\$impl.$typeParam,') + .join(_newLine(depth: 3)); s.write(''' - ) { final \$p = ReceivePort(); final \$x = $name.fromRef( $typeClassesCall @@ -492,17 +481,8 @@ class $name$typeParamsDef extends $superName { ), ).._\$p = \$p; final \$a = \$p.sendPort.nativePort; - _\$types[\$a] = {}; - _\$methods[\$a] = {}; + _\$impls[\$a] = \$impl; '''); - final typeFiller = _InterfaceTypesFiller(s); - for (final typeParam in node.allTypeParams) { - typeParam.accept(typeFiller); - } - final methodFiller = _InterfaceMethodsFiller(s); - for (final method in node.methods) { - method.accept(methodFiller); - } s.write(''' _\$finalizer.attach(\$x, \$p, detach: \$x); \$p.listen((\$m) { @@ -518,6 +498,83 @@ class $name$typeParamsDef extends $superName { // End of Class definition s.writeln('}'); + // Experimental: Interface implementation + // Abstract and concrete Impl class definition. + // Used for interface implementation. + if (node.declKind == DeclKind.interfaceKind && + (config.experiments?.contains(Experiment.interfaceImplementation) ?? + false)) { + // Abstract Impl class + final typeClassGetters = typeParams + .map((typeParam) => + '$_jType<$_typeParamPrefix$typeParam> get $typeParam;') + .join(_newLine(depth: 1)); + final abstractFactoryArgs = _encloseIfNotEmpty( + '{', + [ + ...typeParams + .map((typeParam) => 'required $_jType<\$$typeParam> $typeParam,'), + ...node.methods.accept(_ConcreteImplClosureCtorArg(resolver)), + ].join(_newLine(depth: 2)), + '}', + ); + s.write(''' +abstract class $implClassName$typeParamsDef { + factory $implClassName( + $abstractFactoryArgs + ) = _$implClassName; + + $typeClassGetters + +'''); + final abstractImplMethod = _AbstractImplMethod(resolver, s); + for (final method in node.methods) { + method.accept(abstractImplMethod); + } + s.writeln('}'); + + // Concrete Impl class + // This is for passing closures instead of implementing the class. + final concreteCtorArgs = _encloseIfNotEmpty( + '{', + [ + ...typeParams.map((typeParam) => 'required this.$typeParam,'), + ...node.methods.accept(_ConcreteImplClosureCtorArg(resolver)), + ].join(_newLine(depth: 2)), + '}', + ); + final setClosures = _encloseIfNotEmpty( + ' : ', + node.methods + .map((method) => '_${method.finalName} = ${method.finalName}') + .join(', '), + '', + ); + final typeClassesDef = typeParams.map((typeParam) => ''' +@override +final $_jType<\$$typeParam> $typeParam; +''').join(_newLine(depth: 1)); + s.write(''' + +class _$implClassName$typeParamsDef implements $implClassName$typeParamsCall { + _$implClassName( + $concreteCtorArgs + )$setClosures; + + $typeClassesDef + +'''); + final concreteClosureDef = _ConcreteImplClosureDef(resolver, s); + for (final method in node.methods) { + method.accept(concreteClosureDef); + } + s.writeln(); + final concreteMethodDef = _ConcreteImplMethod(resolver, s); + for (final method in node.methods) { + method.accept(concreteMethodDef); + } + s.writeln('}'); + } // TypeClass definition final typeClassesCall = typeParams.map((typeParam) => '$typeParam,').join(_newLine(depth: 2)); @@ -532,7 +589,7 @@ class $name$typeParamsDef extends $superName { : 'Object.hash($typeClassName, $hashCodeTypeClasses)'; s.write(''' class $typeClassName$typeParamsDef extends $_jType<$name$typeParamsCall> { - $typeClassDefinitions + $typeClassesDef const $typeClassName( $ctorTypeClassesDef @@ -773,7 +830,7 @@ class _TypeClassGenerator extends TypeVisitor<_TypeClass> { @override _TypeClass visitTypeVar(TypeVar node) { if (typeVarFromMap) { - return _TypeClass('_\$types[\$p]!["${node.name}"]!', false); + return _TypeClass('_\$impls[\$p]!.${node.name}', false); } return _TypeClass(node.name, false); } @@ -1510,11 +1567,44 @@ class _TypeVarLocator extends TypeVisitor>> { } } -/// The argument for .implement method of interfaces. -class _InterfaceImplementArg extends Visitor { +/// Method defintion for Impl abstract class used for interface implementation. +class _AbstractImplMethod extends Visitor { final Resolver resolver; + final StringSink s; - _InterfaceImplementArg(this.resolver); + _AbstractImplMethod(this.resolver, this.s); + + @override + void visit(Method node) { + final returnType = node.returnType.accept(_TypeGenerator(resolver)); + final name = node.finalName; + final args = node.params.accept(_ParamDef(resolver)).join(', '); + s.writeln(' $returnType $name($args);'); + } +} + +/// Closure defintion for concrete Impl class used for interface implementation. +class _ConcreteImplClosureDef extends Visitor { + final Resolver resolver; + final StringSink s; + + _ConcreteImplClosureDef(this.resolver, this.s); + + @override + void visit(Method node) { + final returnType = node.returnType.accept(_TypeGenerator(resolver)); + final name = node.finalName; + final args = node.params.accept(_ParamDef(resolver)).join(', '); + s.writeln(' final $returnType Function($args) _$name;'); + } +} + +/// Closure argument for concrete Impl class constructor. +/// Used for interface implementation. +class _ConcreteImplClosureCtorArg extends Visitor { + final Resolver resolver; + + _ConcreteImplClosureCtorArg(this.resolver); @override String visit(Method node) { @@ -1525,6 +1615,26 @@ class _InterfaceImplementArg extends Visitor { } } +/// Method defintion for concrete Impl class used for interface implementation. +class _ConcreteImplMethod extends Visitor { + final Resolver resolver; + final StringSink s; + + _ConcreteImplMethod(this.resolver, this.s); + + @override + void visit(Method node) { + final returnType = node.returnType.accept(_TypeGenerator(resolver)); + final name = node.finalName; + final argsDef = node.params.accept(_ParamDef(resolver)).join(', '); + final argsCall = node.params.map((param) => param.finalName).join(', '); + s.write(''' + $returnType $name($argsDef) { + return _$name($argsCall); + }'''); + } +} + /// The if statement to check which method has been called from the proxy class. class _InterfaceMethodIf extends Visitor { final Resolver resolver; @@ -1537,9 +1647,10 @@ class _InterfaceMethodIf extends Visitor { final isVoid = node.returnType.name == 'void'; final signature = node.javaSig; final saveResult = isVoid ? '' : 'final \$r = '; + final name = node.finalName; s.write(''' if (\$d == r"$signature") { - ${saveResult}_\$methods[\$p]![\$d]!( + ${saveResult}_\$impls[\$p]!.$name( '''); for (var i = 0; i < node.params.length; ++i) { node.params[i].accept(_InterfaceParamCast(resolver, s, paramIndex: i)); @@ -1618,33 +1729,3 @@ class _InterfaceReturnBox extends TypeVisitor { return '($_jni.J${node.boxedName}(\$r)..setAsDeleted()).reference'; } } - -/// Fills the static _$types map with the correct type classes for the given -/// port. -class _InterfaceTypesFiller extends Visitor { - final StringSink s; - - _InterfaceTypesFiller(this.s); - - @override - void visit(TypeParam node) { - s.write(''' - _\$types[\$a]!["${node.name}"] = ${node.name}; -'''); - } -} - -/// Fills the static _$method map with the correct callbacks for the given -/// port. -class _InterfaceMethodsFiller extends Visitor { - final StringSink s; - - _InterfaceMethodsFiller(this.s); - - @override - void visit(Method node) { - s.write(''' - _\$methods[\$a]![r"${node.javaSig}"] = ${node.finalName}; -'''); - } -} diff --git a/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart b/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart index 11e873e5..27f39621 100644 --- a/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart +++ b/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart @@ -2919,24 +2919,19 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { return _manyPrimitives(reference, a, b ? 1 : 0, c, d).long; } - /// Maps a specific port to the implemented methods. - static final Map> _$methods = {}; - - /// Maps a specific port to the type parameters. - static final Map> _$types = {}; + /// Maps a specific port to the implemented interface. + static final Map _$impls = {}; ReceivePort? _$p; static final Finalizer _$finalizer = Finalizer(($p) { - _$methods.remove($p.sendPort.nativePort); - _$types.remove($p.sendPort.nativePort); + _$impls.remove($p.sendPort.nativePort); $p.close(); }); @override void delete() { - _$methods.remove(_$p?.sendPort.nativePort); - _$types.remove(_$p?.sendPort.nativePort); + _$impls.remove(_$p?.sendPort.nativePort); _$p?.close(); _$finalizer.detach(this); super.delete(); @@ -2970,13 +2965,13 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); final $a = $i.args; if ($d == r"voidCallback(Ljava/lang/String;)V") { - _$methods[$p]![$d]!( + _$impls[$p]!.voidCallback( $a[0].castTo(const jni.JStringType(), deleteOriginal: true), ); return jni.nullptr; } if ($d == r"stringCallback(Ljava/lang/String;)Ljava/lang/String;") { - final $r = _$methods[$p]![$d]!( + final $r = _$impls[$p]!.stringCallback( $a[0].castTo(const jni.JStringType(), deleteOriginal: true), ); return (($r as jni.JObject).castTo(const jni.JObjectType()) @@ -2984,15 +2979,15 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { .reference; } if ($d == r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;") { - final $r = _$methods[$p]![$d]!( - $a[0].castTo(_$types[$p]!["T"]!, deleteOriginal: true), + final $r = _$impls[$p]!.varCallback( + $a[0].castTo(_$impls[$p]!.T, deleteOriginal: true), ); return (($r as jni.JObject).castTo(const jni.JObjectType()) ..setAsDeleted()) .reference; } if ($d == r"manyPrimitives(IZCD)J") { - final $r = _$methods[$p]![$d]!( + final $r = _$impls[$p]!.manyPrimitives( $a[0] .castTo(const jni.JIntegerType(), deleteOriginal: true) .intValue(deleteOriginal: true), @@ -3011,16 +3006,12 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { return jni.nullptr; } - factory MyInterface.implement({ - required jni.JObjType<$T> T, - required void Function(jni.JString s) voidCallback, - required jni.JString Function(jni.JString s) stringCallback, - required $T Function($T t) varCallback, - required int Function(int a, bool b, int c, double d) manyPrimitives, - }) { + factory MyInterface.implement( + $MyInterfaceImpl<$T> $impl, + ) { final $p = ReceivePort(); final $x = MyInterface.fromRef( - T, + $impl.T, ProtectedJniExtensions.newPortProxy( r"com.github.dart_lang.jnigen.interfaces.MyInterface", $p, @@ -3028,15 +3019,7 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { ), ).._$p = $p; final $a = $p.sendPort.nativePort; - _$types[$a] = {}; - _$methods[$a] = {}; - _$types[$a]!["T"] = T; - _$methods[$a]![r"voidCallback(Ljava/lang/String;)V"] = voidCallback; - _$methods[$a]![r"stringCallback(Ljava/lang/String;)Ljava/lang/String;"] = - stringCallback; - _$methods[$a]![r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;"] = - varCallback; - _$methods[$a]![r"manyPrimitives(IZCD)J"] = manyPrimitives; + _$impls[$a] = $impl; _$finalizer.attach($x, $p, detach: $x); $p.listen(($m) { final $i = $MethodInvocation.fromMessage($m); @@ -3047,6 +3030,61 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { } } +abstract class $MyInterfaceImpl<$T extends jni.JObject> { + factory $MyInterfaceImpl({ + required jni.JObjType<$T> T, + required void Function(jni.JString s) voidCallback, + required jni.JString Function(jni.JString s) stringCallback, + required $T Function($T t) varCallback, + required int Function(int a, bool b, int c, double d) manyPrimitives, + }) = _$MyInterfaceImpl; + + jni.JObjType<$T> get T; + + void voidCallback(jni.JString s); + jni.JString stringCallback(jni.JString s); + $T varCallback($T t); + int manyPrimitives(int a, bool b, int c, double d); +} + +class _$MyInterfaceImpl<$T extends jni.JObject> + implements $MyInterfaceImpl<$T> { + _$MyInterfaceImpl({ + required this.T, + required void Function(jni.JString s) voidCallback, + required jni.JString Function(jni.JString s) stringCallback, + required $T Function($T t) varCallback, + required int Function(int a, bool b, int c, double d) manyPrimitives, + }) : _voidCallback = voidCallback, + _stringCallback = stringCallback, + _varCallback = varCallback, + _manyPrimitives = manyPrimitives; + + @override + final jni.JObjType<$T> T; + + final void Function(jni.JString s) _voidCallback; + final jni.JString Function(jni.JString s) _stringCallback; + final $T Function($T t) _varCallback; + final int Function(int a, bool b, int c, double d) _manyPrimitives; + + void voidCallback(jni.JString s) { + return _voidCallback(s); + } + + jni.JString stringCallback(jni.JString s) { + return _stringCallback(s); + } + + $T varCallback($T t) { + return _varCallback(t); + } + + int manyPrimitives(int a, bool b, int c, double d) { + return _manyPrimitives(a, b, c, d); + } +} + class $MyInterfaceType<$T extends jni.JObject> extends jni.JObjType> { final jni.JObjType<$T> T; diff --git a/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart b/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart index ef24ce3e..9d016f7f 100644 --- a/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart +++ b/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart @@ -2758,24 +2758,19 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { [jni.JValueInt(a), b ? 1 : 0, jni.JValueChar(c), d]).long; } - /// Maps a specific port to the implemented methods. - static final Map> _$methods = {}; - - /// Maps a specific port to the type parameters. - static final Map> _$types = {}; + /// Maps a specific port to the implemented interface. + static final Map _$impls = {}; ReceivePort? _$p; static final Finalizer _$finalizer = Finalizer(($p) { - _$methods.remove($p.sendPort.nativePort); - _$types.remove($p.sendPort.nativePort); + _$impls.remove($p.sendPort.nativePort); $p.close(); }); @override void delete() { - _$methods.remove(_$p?.sendPort.nativePort); - _$types.remove(_$p?.sendPort.nativePort); + _$impls.remove(_$p?.sendPort.nativePort); _$p?.close(); _$finalizer.detach(this); super.delete(); @@ -2809,13 +2804,13 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); final $a = $i.args; if ($d == r"voidCallback(Ljava/lang/String;)V") { - _$methods[$p]![$d]!( + _$impls[$p]!.voidCallback( $a[0].castTo(const jni.JStringType(), deleteOriginal: true), ); return jni.nullptr; } if ($d == r"stringCallback(Ljava/lang/String;)Ljava/lang/String;") { - final $r = _$methods[$p]![$d]!( + final $r = _$impls[$p]!.stringCallback( $a[0].castTo(const jni.JStringType(), deleteOriginal: true), ); return (($r as jni.JObject).castTo(const jni.JObjectType()) @@ -2823,15 +2818,15 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { .reference; } if ($d == r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;") { - final $r = _$methods[$p]![$d]!( - $a[0].castTo(_$types[$p]!["T"]!, deleteOriginal: true), + final $r = _$impls[$p]!.varCallback( + $a[0].castTo(_$impls[$p]!.T, deleteOriginal: true), ); return (($r as jni.JObject).castTo(const jni.JObjectType()) ..setAsDeleted()) .reference; } if ($d == r"manyPrimitives(IZCD)J") { - final $r = _$methods[$p]![$d]!( + final $r = _$impls[$p]!.manyPrimitives( $a[0] .castTo(const jni.JIntegerType(), deleteOriginal: true) .intValue(deleteOriginal: true), @@ -2850,16 +2845,12 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { return jni.nullptr; } - factory MyInterface.implement({ - required jni.JObjType<$T> T, - required void Function(jni.JString s) voidCallback, - required jni.JString Function(jni.JString s) stringCallback, - required $T Function($T t) varCallback, - required int Function(int a, bool b, int c, double d) manyPrimitives, - }) { + factory MyInterface.implement( + $MyInterfaceImpl<$T> $impl, + ) { final $p = ReceivePort(); final $x = MyInterface.fromRef( - T, + $impl.T, ProtectedJniExtensions.newPortProxy( r"com.github.dart_lang.jnigen.interfaces.MyInterface", $p, @@ -2867,15 +2858,7 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { ), ).._$p = $p; final $a = $p.sendPort.nativePort; - _$types[$a] = {}; - _$methods[$a] = {}; - _$types[$a]!["T"] = T; - _$methods[$a]![r"voidCallback(Ljava/lang/String;)V"] = voidCallback; - _$methods[$a]![r"stringCallback(Ljava/lang/String;)Ljava/lang/String;"] = - stringCallback; - _$methods[$a]![r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;"] = - varCallback; - _$methods[$a]![r"manyPrimitives(IZCD)J"] = manyPrimitives; + _$impls[$a] = $impl; _$finalizer.attach($x, $p, detach: $x); $p.listen(($m) { final $i = $MethodInvocation.fromMessage($m); @@ -2886,6 +2869,61 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { } } +abstract class $MyInterfaceImpl<$T extends jni.JObject> { + factory $MyInterfaceImpl({ + required jni.JObjType<$T> T, + required void Function(jni.JString s) voidCallback, + required jni.JString Function(jni.JString s) stringCallback, + required $T Function($T t) varCallback, + required int Function(int a, bool b, int c, double d) manyPrimitives, + }) = _$MyInterfaceImpl; + + jni.JObjType<$T> get T; + + void voidCallback(jni.JString s); + jni.JString stringCallback(jni.JString s); + $T varCallback($T t); + int manyPrimitives(int a, bool b, int c, double d); +} + +class _$MyInterfaceImpl<$T extends jni.JObject> + implements $MyInterfaceImpl<$T> { + _$MyInterfaceImpl({ + required this.T, + required void Function(jni.JString s) voidCallback, + required jni.JString Function(jni.JString s) stringCallback, + required $T Function($T t) varCallback, + required int Function(int a, bool b, int c, double d) manyPrimitives, + }) : _voidCallback = voidCallback, + _stringCallback = stringCallback, + _varCallback = varCallback, + _manyPrimitives = manyPrimitives; + + @override + final jni.JObjType<$T> T; + + final void Function(jni.JString s) _voidCallback; + final jni.JString Function(jni.JString s) _stringCallback; + final $T Function($T t) _varCallback; + final int Function(int a, bool b, int c, double d) _manyPrimitives; + + void voidCallback(jni.JString s) { + return _voidCallback(s); + } + + jni.JString stringCallback(jni.JString s) { + return _stringCallback(s); + } + + $T varCallback($T t) { + return _varCallback(t); + } + + int manyPrimitives(int a, bool b, int c, double d) { + return _manyPrimitives(a, b, c, d); + } +} + class $MyInterfaceType<$T extends jni.JObject> extends jni.JObjType> { final jni.JObjType<$T> T; diff --git a/jnigen/test/simple_package_test/runtime_test_registrant.dart b/jnigen/test/simple_package_test/runtime_test_registrant.dart index cd6f9997..1c407688 100644 --- a/jnigen/test/simple_package_test/runtime_test_registrant.dart +++ b/jnigen/test/simple_package_test/runtime_test_registrant.dart @@ -543,28 +543,31 @@ void registerTests(String groupName, TestRunnerCallback test) { // or `self` argument for each one of the callbacks. late final MyInterface myInterface; myInterface = MyInterface.implement( - voidCallback: (s) { - voidCallbackResult.complete(s); - }, - stringCallback: (s) { - return (s.toDartString(deleteOriginal: true) * 2).toJString(); - }, - varCallback: (JInteger t) { - final result = (t.intValue(deleteOriginal: true) * 2).toJInteger(); - varCallbackResult.complete(result); - return result; - }, - manyPrimitives: (a, b, c, d) { - if (b) { - final result = a + c + d.toInt(); - manyPrimitivesResult.complete(result); + $MyInterfaceImpl( + voidCallback: (s) { + voidCallbackResult.complete(s); + }, + stringCallback: (s) { + return (s.toDartString(deleteOriginal: true) * 2).toJString(); + }, + varCallback: (JInteger t) { + final result = + (t.intValue(deleteOriginal: true) * 2).toJInteger(); + varCallbackResult.complete(result); return result; - } else { - // Call self, add to [a] when [b] is false and change b to true. - return myInterface.manyPrimitives(a + 1, true, c, d); - } - }, - T: JInteger.type, + }, + manyPrimitives: (a, b, c, d) { + if (b) { + final result = a + c + d.toInt(); + manyPrimitivesResult.complete(result); + return result; + } else { + // Call self, add to [a] when [b] is false and change b to true. + return myInterface.manyPrimitives(a + 1, true, c, d); + } + }, + T: JInteger.type, + ), ); // [stringCallback] is going to be called first using [s]. // The result of it is going to be used as the argument for