Skip to content

Commit

Permalink
[jnigen] Refactor type classes (#1591)
Browse files Browse the repository at this point in the history
* Make all type class methods and fields internal
* Use better import prefixes
* Rename `castTo` to `as`
* Relax renaming keywords
* Rename to `MethodInvocation`
* Rename typeclass of `Foo` to `$Foo$Type`
* Make generic type parameters internal
  • Loading branch information
HosseinYousefi authored Sep 24, 2024
1 parent 82c0aac commit 117cc75
Show file tree
Hide file tree
Showing 52 changed files with 9,917 additions and 8,605 deletions.
13 changes: 6 additions & 7 deletions pkgs/jni/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ int randomUsingEnv(int n) => using((arena) {
double randomDouble() {
final math = JClass.forName("java/lang/Math");
final random =
math.staticMethodId("random", "()D").call(math, const jdoubleType(), []);
math.staticMethodId("random", "()D").call(math, jdouble.type, []);
math.release();
return random;
}
Expand All @@ -63,7 +63,7 @@ int uptime() {
return JClass.forName("android/os/SystemClock").use(
(systemClock) => systemClock
.staticMethodId("uptimeMillis", "()J")
.call(systemClock, const jlongType(), []),
.call(systemClock, jlong.type, []),
);
}

Expand All @@ -74,9 +74,8 @@ String backAndForth() {
}

void quit() {
JObject.fromReference(Jni.getCurrentActivity()).use((ac) => ac.jClass
.instanceMethodId("finish", "()V")
.call(ac, const jvoidType(), []));
JObject.fromReference(Jni.getCurrentActivity()).use((ac) =>
ac.jClass.instanceMethodId("finish", "()V").call(ac, jvoid.type, []));
}

void showToast(String text) {
Expand All @@ -94,14 +93,14 @@ void showToast(String text) {
'(Landroid/app/Activity;Landroid/content/Context;'
'Ljava/lang/CharSequence;I)'
'Lcom/github/dart_lang/jni_example/Toaster;');
final toaster = makeText.call(toasterClass, const JObjectType(), [
final toaster = makeText.call(toasterClass, JObject.type, [
Jni.getCurrentActivity(),
Jni.getCachedApplicationContext(),
'😀'.toJString(),
0,
]);
final show = toasterClass.instanceMethodId('show', '()V');
show(toaster, const jvoidType(), []);
show(toaster, jvoid.type, []);
}

void main() {
Expand Down
84 changes: 55 additions & 29 deletions pkgs/jni/lib/_internal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,68 @@
/// not to be used directly.
library;

import 'dart:ffi' as ffi;
import 'dart:ffi' as ffi show Int32;
import 'dart:ffi' hide Int32;

// Exporting all the necessary bits for the generated bindings.
export 'dart:ffi'
show
Double,
Int64,
NativeFunction,
NativeFunctionPointer,
NativePort,
Pointer,
VarArgs,
Void,
nullptr;
export 'dart:isolate' show RawReceivePort, ReceivePort;

export 'package:meta/meta.dart' show internal;

export 'src/accessors.dart';
export 'src/jni.dart' show ProtectedJniExtensions;
export 'src/jreference.dart';
export 'src/method_invocation.dart';
export 'src/types.dart' show referenceType;
export 'src/types.dart'
show
JAccessible,
JArrayElementType,
JCallable,
JConstructable,
JObjType,
JType,
lowestCommonSuperType,
referenceType;

/// Temporary fix for the macOS arm64 varargs problem.
///
/// This integer type is Int32 on all architectures, other than macOS arm64.
/// Where it is Int64.
@ffi.AbiSpecificIntegerMapping({
ffi.Abi.androidArm: ffi.Int32(),
ffi.Abi.androidArm64: ffi.Int32(),
ffi.Abi.androidIA32: ffi.Int32(),
ffi.Abi.androidX64: ffi.Int32(),
ffi.Abi.androidRiscv64: ffi.Int32(),
ffi.Abi.fuchsiaArm64: ffi.Int32(),
ffi.Abi.fuchsiaX64: ffi.Int32(),
ffi.Abi.fuchsiaRiscv64: ffi.Int32(),
ffi.Abi.iosArm: ffi.Int32(),
ffi.Abi.iosArm64: ffi.Int32(),
ffi.Abi.iosX64: ffi.Int32(),
ffi.Abi.linuxArm: ffi.Int32(),
ffi.Abi.linuxArm64: ffi.Int32(),
ffi.Abi.linuxIA32: ffi.Int32(),
ffi.Abi.linuxX64: ffi.Int32(),
ffi.Abi.linuxRiscv32: ffi.Int32(),
ffi.Abi.linuxRiscv64: ffi.Int32(),
ffi.Abi.macosArm64: ffi.Int64(), // <-- Only this is different.
ffi.Abi.macosX64: ffi.Int32(),
ffi.Abi.windowsArm64: ffi.Int32(),
ffi.Abi.windowsIA32: ffi.Int32(),
ffi.Abi.windowsX64: ffi.Int32(),
/// This integer type is `Int32` on all architectures, other than macOS arm64.
/// Where it is `Int64`.
@AbiSpecificIntegerMapping({
Abi.androidArm: ffi.Int32(),
Abi.androidArm64: ffi.Int32(),
Abi.androidIA32: ffi.Int32(),
Abi.androidX64: ffi.Int32(),
Abi.androidRiscv64: ffi.Int32(),
Abi.fuchsiaArm64: ffi.Int32(),
Abi.fuchsiaX64: ffi.Int32(),
Abi.fuchsiaRiscv64: ffi.Int32(),
Abi.iosArm: ffi.Int32(),
Abi.iosArm64: ffi.Int32(),
Abi.iosX64: ffi.Int32(),
Abi.linuxArm: ffi.Int32(),
Abi.linuxArm64: ffi.Int32(),
Abi.linuxIA32: ffi.Int32(),
Abi.linuxX64: ffi.Int32(),
Abi.linuxRiscv32: ffi.Int32(),
Abi.linuxRiscv64: ffi.Int32(),
Abi.macosArm64: Int64(), // <-- Only this is different.
Abi.macosX64: ffi.Int32(),
Abi.windowsArm64: ffi.Int32(),
Abi.windowsIA32: ffi.Int32(),
Abi.windowsX64: ffi.Int32(),
})
final class $Int32 extends ffi.AbiSpecificInteger {
const $Int32();
final class Int32 extends AbiSpecificInteger {
const Int32();
}
12 changes: 9 additions & 3 deletions pkgs/jni/lib/jni.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@
/// This library provides classes and functions for JNI interop from Dart.
library;

export 'dart:ffi' show nullptr;

export 'package:ffi/ffi.dart' show Arena, using;

export 'src/errors.dart';
Expand All @@ -74,5 +72,13 @@ export 'src/lang/lang.dart';
export 'src/nio/nio.dart';
export 'src/third_party/generated_bindings.dart'
hide JniBindings, JniEnv, JniEnv1, JniExceptionDetails;
export 'src/types.dart' hide referenceType;
export 'src/types.dart'
hide
JAccessible,
JArrayElementType,
JCallable,
JConstructable,
JObjType,
JType,
lowestCommonSuperType;
export 'src/util/util.dart';
6 changes: 5 additions & 1 deletion pkgs/jni/lib/src/accessors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import 'dart:ffi';

import 'package:meta/meta.dart' show internal;

import '../jni.dart';
import 'jni.dart';
import 'jobject.dart';
import 'jreference.dart';
import 'third_party/generated_bindings.dart';
import 'types.dart';

void _check(JThrowablePtr exception) {
if (exception != nullptr) {
Expand Down
15 changes: 12 additions & 3 deletions pkgs/jni/lib/src/jarray.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,26 @@
part of 'types.dart';

final class JArrayType<E> extends JObjType<JArray<E>> {
@internal
final JArrayElementType<E> elementType;

@internal
const JArrayType(this.elementType);

@internal
@override
String get signature => '[${elementType.signature}';

@internal
@override
JArray<E> fromReference(JReference reference) =>
JArray.fromReference(elementType, reference);

@internal
@override
JObjType get superType => const JObjectType();

@internal
@override
final int superCount = 1;

Expand All @@ -36,18 +42,21 @@ final class JArrayType<E> extends JObjType<JArray<E>> {
}

class JArray<E> extends JObject {
@internal
final JArrayElementType<E> elementType;

@internal
@override
late final JArrayType<E> $type = type(elementType) as JArrayType<E>;
final JArrayType<E> $type;

/// The type which includes information such as the signature of this class.
static JObjType<JArray<T>> type<T>(JArrayElementType<T> innerType) =>
static JArrayType<E> type<E>(JArrayElementType<E> innerType) =>
JArrayType(innerType);

/// Construct a new [JArray] with [reference] as its underlying reference.
JArray.fromReference(this.elementType, JReference reference)
: super.fromReference(reference);
: $type = type(elementType),
super.fromReference(reference);

/// Creates a [JArray] of the given length from the given [elementType].
///
Expand Down
6 changes: 4 additions & 2 deletions pkgs/jni/lib/src/jimplementer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import 'dart:ffi';
import 'dart:isolate';

import 'package:ffi/ffi.dart';
import 'package:meta/meta.dart';
import 'package:meta/meta.dart' show internal;

import '../_internal.dart';
import 'accessors.dart';
import 'jni.dart';
import 'jobject.dart';
import 'jreference.dart';
import 'lang/jstring.dart';
import 'third_party/generated_bindings.dart';
import 'types.dart';
Expand Down
7 changes: 5 additions & 2 deletions pkgs/jni/lib/src/jni.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import 'package:ffi/ffi.dart';
import 'package:meta/meta.dart' show internal;
import 'package:path/path.dart';

import '../_internal.dart';
import '../jni.dart';
import 'accessors.dart';
import 'errors.dart';
import 'jobject.dart';
import 'jreference.dart';
import 'third_party/generated_bindings.dart';
import 'types.dart';

String _getLibraryFileName(String base) {
if (Platform.isLinux || Platform.isAndroid) {
Expand Down
13 changes: 10 additions & 3 deletions pkgs/jni/lib/src/jobject.dart
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
// Copyright (c) 2022, 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 'package:ffi/ffi.dart';
import 'package:meta/meta.dart' show internal;

import 'jni.dart';
import 'jreference.dart';
import 'lang/jstring.dart';
import 'types.dart';

final class JObjectType extends JObjType<JObject> {
@internal
const JObjectType();

@internal
@override
String get signature => 'Ljava/lang/Object;';

@internal
@override
JObject fromReference(JReference reference) =>
JObject.fromReference(reference);

@internal
@override
JObjType get superType => const JObjectType();

// TODO(#70): Once interface implementation lands, other than [superType],
// we should have a list of implemented interfaces.

@internal
@override
final int superCount = 0;

Expand All @@ -43,9 +48,11 @@ final class JObjectType extends JObjType<JObject> {
///
/// This is the base class for classes generated by `jnigen`.
class JObject {
@internal
final JReference reference;

late final JObjType<JObject> $type = type;
@internal
final JObjType<JObject> $type = type;

/// The type which includes information such as the signature of this class.
static const JObjType<JObject> type = JObjectType();
Expand Down Expand Up @@ -77,7 +84,7 @@ class JObject {
/// Casts this object to another [type].
///
/// If [releaseOriginal] is `true`, the casted object will be released.
T castTo<T extends JObject>(
T as<T extends JObject>(
JObjType<T> type, {
bool releaseOriginal = false,
}) {
Expand Down
Loading

0 comments on commit 117cc75

Please sign in to comment.