blob: f21382c78125660c0f034b941f740a662a032238 [file] [log] [blame]
// 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 'jobject.dart';
import 'third_party/generated_bindings.dart';
import 'jni.dart';
void _fillJValue(Pointer<JValue> pos, dynamic arg) {
if (arg is JObject) {
pos.ref.l = arg.reference.pointer;
return;
}
switch (arg.runtimeType) {
case int:
pos.ref.j = arg;
break;
case bool:
pos.ref.z = arg ? 1 : 0;
break;
case const (Pointer<Void>):
case const (Pointer<Never>): // for nullptr
pos.ref.l = arg;
break;
case double:
pos.ref.d = arg;
break;
case JValueFloat:
pos.ref.f = (arg as JValueFloat).value;
break;
case JValueInt:
pos.ref.i = (arg as JValueInt).value;
break;
case JValueShort:
pos.ref.s = (arg as JValueShort).value;
break;
case JValueChar:
pos.ref.c = (arg as JValueChar).value;
break;
case JValueByte:
pos.ref.b = (arg as JValueByte).value;
break;
default:
throw UnsupportedError("cannot convert ${arg.runtimeType} to jvalue");
}
}
/// Converts passed arguments to JValue array
/// for use in methods that take arguments.
///
/// int, bool, double and JObject types are converted out of the box.
/// wrap values in types such as [JValueLong]
/// to convert to other primitive types instead.
Pointer<JValue> toJValues(List<dynamic> args, {Allocator allocator = calloc}) {
final result = allocator<JValue>(args.length);
for (int i = 0; i < args.length; i++) {
final arg = args[i];
final pos = result + i;
_fillJValue(pos, arg);
}
return result;
}
/// Use this class as wrapper to convert an integer
/// to Java `int` in jvalues method.
final class JValueInt {
int value;
JValueInt(this.value);
}
/// Use this class as wrapper to convert an integer
/// to Java `short` in jvalues method.
final class JValueShort {
int value;
JValueShort(this.value);
}
/// Use this class as wrapper to convert an integer
/// to Java `byte` in jvalues method.
final class JValueByte {
int value;
JValueByte(this.value);
}
/// Use this class as wrapper to convert an double
/// to Java `float` in jvalues method.
final class JValueFloat {
double value;
JValueFloat(this.value);
}
/// Use this class as wrapper to convert an integer
/// to Java `char` in jvalues method.
final class JValueChar {
int value;
JValueChar(this.value);
JValueChar.fromString(String s) : value = 0 {
if (s.length != 1) {
throw "Expected string of length 1";
}
value = s.codeUnitAt(0).toInt();
}
}
/// class used to convert dart types passed to convenience methods
/// into their corresponding Java values.
///
/// Similar to Jni.jvalues, but instead of a pointer, an instance
/// with a dispose method is returned.
/// This allows us to take dart strings.
///
/// Returned value is allocated using provided allocator.
/// But default allocator may be used for string conversions.
final class JValueArgs {
late Pointer<JValue> values;
final List<JObjectPtr> createdRefs = [];
JValueArgs(List<dynamic> args, Arena arena) {
values = arena<JValue>(args.length);
for (int i = 0; i < args.length; i++) {
final arg = args[i];
final ptr = values + i;
if (arg is String) {
final jstr = Jni.env.toJStringPtr(arg);
ptr.ref.l = jstr;
createdRefs.add(jstr);
} else {
_fillJValue(ptr, arg);
}
arena.onReleaseAll(_dispose);
}
}
/// Deletes temporary references such as [JStringPtr]s.
void _dispose() {
for (var ref in createdRefs) {
Jni.env.DeleteGlobalRef(ref);
}
}
}