| // Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'dart:ffi'; | |
| import 'dart:isolate'; | |
| import 'package:ffi/ffi.dart'; | |
| import 'package:meta/meta.dart' show internal; | |
| import 'accessors.dart'; | |
| import 'jni.dart'; | |
| import 'jobject.dart'; | |
| import 'lang/jstring.dart'; | |
| import 'third_party/generated_bindings.dart'; | |
| import 'types.dart'; | |
| import 'util/jlist.dart'; | |
| /// A builder that builds proxy objects that implement one or more interfaces. | |
| /// | |
| /// Example: | |
| /// <!-- file://./../../example/api/jimplementer_snippet.dart --> | |
| /// ```dart | |
| /// final implementer = JImplementer(); | |
| /// Foo.implementIn(implementer, fooImpl); | |
| /// Bar.implementIn(implementer, barImpl); | |
| /// final foobar = implementer.build(Foo.type); // Or `Bar.type`. | |
| /// ``` | |
| class JImplementer extends JObject { | |
| JImplementer.fromReference(super.reference) : super.fromReference(); | |
| static final _class = | |
| JClass.forName(r'com/github/dart_lang/jni/PortProxyBuilder'); | |
| static final _newId = _class.constructorId(r'(JJ)V'); | |
| static final _new = ProtectedJniExtensions.lookup< | |
| NativeFunction< | |
| JniResult Function(Pointer<Void>, JMethodIDPtr, | |
| VarArgs<(Int64, Int64)>)>>('globalEnv_NewObject') | |
| .asFunction<JniResult Function(Pointer<Void>, JMethodIDPtr, int, int)>(); | |
| factory JImplementer() { | |
| ProtectedJniExtensions.ensureInitialized(); | |
| return JImplementer.fromReference(_new( | |
| _class.reference.pointer, | |
| _newId.pointer, | |
| ProtectedJniExtensions.getCurrentIsolateId(), | |
| ProtectedJniExtensions.getMainPortId()) | |
| .reference); | |
| } | |
| static final _addImplementationId = _class.instanceMethodId( | |
| r'addImplementation', | |
| r'(Ljava/lang/String;JJLjava/util/List;)V', | |
| ); | |
| static final _addImplementation = ProtectedJniExtensions.lookup< | |
| NativeFunction< | |
| JThrowablePtr Function(Pointer<Void>, JMethodIDPtr, | |
| VarArgs<(Pointer<Void>, Int64, Int64, Pointer<Void>)>)>>( | |
| 'globalEnv_CallVoidMethod') | |
| .asFunction< | |
| JThrowablePtr Function(Pointer<Void>, JMethodIDPtr, Pointer<Void>, | |
| int, int, Pointer<Void>)>(); | |
| /// Should not be used directly. | |
| /// | |
| /// Use `implementIn` from the generated interface instead. | |
| @internal | |
| void add( | |
| String binaryName, | |
| RawReceivePort port, | |
| Pointer<NativeFunction<JObjectPtr Function(Int64, JObjectPtr, JObjectPtr)>> | |
| pointer, | |
| List<String> asyncMethods, | |
| ) { | |
| using((arena) { | |
| final binaryNameRef = | |
| (binaryName.toJString()..releasedBy(arena)).reference; | |
| _addImplementation( | |
| reference.pointer, | |
| _addImplementationId.pointer, | |
| binaryNameRef.pointer, | |
| port.sendPort.nativePort, | |
| pointer.address, | |
| (asyncMethods.map((m) => m.toJString()..releasedBy(arena)).toJList() | |
| ..releasedBy(arena)) | |
| .reference | |
| .pointer, | |
| ).check(); | |
| }); | |
| } | |
| static final _buildId = _class.instanceMethodId( | |
| r'build', | |
| r'()Ljava/lang/Object;', | |
| ); | |
| static final _build = ProtectedJniExtensions.lookup< | |
| NativeFunction< | |
| JniResult Function( | |
| Pointer<Void>, | |
| JMethodIDPtr, | |
| )>>('globalEnv_CallObjectMethod') | |
| .asFunction< | |
| JniResult Function( | |
| Pointer<Void>, | |
| JMethodIDPtr, | |
| )>(); | |
| /// Builds an proxy object with the specified [type] that implements all the | |
| /// added interfaces with the given implementations. | |
| /// | |
| /// Releases this implementer. | |
| T implement<T extends JObject>() { | |
| return _build(reference.pointer, _buildId.pointer).object<T>(); | |
| } | |
| } |