// 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: /// /// ```dart /// final implementer = JImplementer(); /// Foo.implementIn(implementer, fooImpl); /// Bar.implementIn(implementer, barImpl); /// final foobar = implementer.implement(); // Or Bar. /// ``` 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, JMethodIDPtr, VarArgs<(Int64, Int64)>)>>('globalEnv_NewObject') .asFunction, 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, JMethodIDPtr, VarArgs<(Pointer, Int64, Int64, Pointer)>)>>( 'globalEnv_CallVoidMethod') .asFunction< JThrowablePtr Function(Pointer, JMethodIDPtr, Pointer, int, int, Pointer)>(); /// Should not be used directly. /// /// Use `implementIn` from the generated interface instead. @internal void add( String binaryName, RawReceivePort port, Pointer> pointer, List 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, JMethodIDPtr, )>>('globalEnv_CallObjectMethod') .asFunction< JniResult Function( Pointer, JMethodIDPtr, )>(); /// Builds a proxy object with the specified type `` that implements all /// the added interfaces with the given implementations. /// /// Releases this implementer. T implement() { return _build(reference.pointer, _buildId.pointer).object(); } }