// Copyright (c) 2025, 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. // Generates lib/src/primitive_jarrays.dart. import 'dart:io'; import 'package:dart_style/dart_style.dart'; class PrimitiveType { final String name; final String signature; final String dartType; final int size; final bool isUnsigned; const PrimitiveType( this.name, this.signature, { required this.dartType, required this.size, this.isUnsigned = false, }); String get nativeDartListType { if (dartType == 'double') { return 'Float${size}List'; } return '${isUnsigned ? 'Uint' : 'Int'}${size}List'; } String get nativeDartType { if (dartType == 'double') { return size == 32 ? 'Float' : 'Double'; } return '${isUnsigned ? 'Uint' : 'Int'}$size'; } String get sizeInDoc => size == 8 ? 'eight' : '$size'; int get lowestInRange { if (isUnsigned) { return 0; } return -(1 << (size - 1)); } int get highestInRange { if (isUnsigned) { return (1 << size) - 1; } return (1 << (size - 1)) - 1; } } void main() { final outputUri = Platform.script.resolve('../lib/src/primitive_jarrays.dart'); final outputFile = File.fromUri(outputUri); final s = StringBuffer(); s.writeln(''' // AUTO GENERATED. DO NOT EDIT! // // To regenerate, run `dart run tool/generate_primtive_arrays.dart` part of 'jarray.dart'; '''); const primitiveTypes = [ PrimitiveType('Boolean', 'Z', dartType: 'bool', size: 8, isUnsigned: true), PrimitiveType('Byte', 'B', dartType: 'int', size: 8), PrimitiveType('Char', 'C', dartType: 'int', size: 16, isUnsigned: true), PrimitiveType('Short', 'S', dartType: 'int', size: 16), PrimitiveType('Int', 'I', dartType: 'int', size: 32), PrimitiveType('Long', 'J', dartType: 'int', size: 64), PrimitiveType('Float', 'F', dartType: 'double', size: 32), PrimitiveType('Double', 'D', dartType: 'double', size: 64), ]; for (final type in primitiveTypes) { final typeName = type.name; final arrayName = 'J${typeName}Array'; s.write(''' final class _\$$arrayName\$Type\$ extends JType<$arrayName> { const _\$$arrayName\$Type\$(); @override String get signature => '[${type.signature}'; } /// A fixed-length array of Java $typeName. /// '''); if (type.dartType == 'int') { s.write(''' /// Integers stored in the list are truncated to their low ${type.sizeInDoc} bits '''); if (type.isUnsigned) { s.write(''' /// interpreted as an unsigned ${type.size}-bit integer with values in the /// range ${type.lowestInRange} to +${type.highestInRange}. /// '''); } else { s.write(''' /// interpreted as a signed ${type.size}-bit two's complement integer with values in the /// range ${type.lowestInRange} to +${type.highestInRange}. /// '''); } } s.write(''' /// Java equivalent of [${type.nativeDartListType}]. extension type $arrayName._(JObject _\$this) implements JObject { /// The type which includes information such as the signature of this class. static const JType<$arrayName> type = _\$$arrayName\$Type\$(); /// Creates a [$arrayName] of the given [length]. /// /// The [length] must be a non-negative integer. factory $arrayName(int length) { RangeError.checkNotNegative(length); return JObject.fromReference( JGlobalReference(Jni.env.New${typeName}Array(length)), ) as $arrayName; } /// Creates a [$arrayName] from `elements`. static $arrayName of(Iterable<${type.dartType}> elements) { final len = elements.length; return $arrayName(len)..setRange(0, len, elements); } /// The number of elements in this array. int get length => Jni.env.GetArrayLength(reference.pointer); ${type.dartType} operator [](int index) { RangeError.checkValueInInterval(index, 0, length - 1); return Jni.env.Get${typeName}ArrayElement(reference.pointer, index); } void operator []=(int index, ${type.dartType} value) { RangeError.checkValueInInterval(index, 0, length - 1); Jni.env.Set${typeName}ArrayElement(reference.pointer, index, value); } ${type.nativeDartListType} getRange(int start, int end, {Allocator allocator = malloc}) { RangeError.checkValidRange(start, end, length); final rangeLength = end - start; final buffer = allocator<${type.nativeDartType}>(rangeLength); Jni.env .Get${typeName}ArrayRegion(reference.pointer, start, rangeLength, buffer); return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree); } void setRange(int start, int end, Iterable<${type.dartType}> iterable, [int skipCount = 0]) { RangeError.checkValidRange(start, end, length); final rangeLength = end - start; _allocate<${type.nativeDartType}>(sizeOf<${type.nativeDartType}>() * rangeLength, (ptr) { ptr .asTypedList(rangeLength) .setRange(0, rangeLength, iterable${typeName == 'Boolean' ? '.map((e) => e ? 1 : 0)' : ''}, skipCount); Jni.env.Set${typeName}ArrayRegion(reference.pointer, start, rangeLength, ptr); }); } } final class _${arrayName}ListView with ListMixin<${type.dartType}>, NonGrowableListMixin<${type.dartType}> { final $arrayName _jarray; _${arrayName}ListView(this._jarray); @override int get length => _jarray.length; @override ${type.dartType} operator [](int index) { return _jarray[index]; } @override void operator []=(int index, ${type.dartType} value) { _jarray[index] = value; } } extension ${arrayName}ToList on $arrayName { /// Returns a [List] view into this array. /// /// Any changes to this list will reflect in the original array as well. List<${type.dartType}> asDart() => _${arrayName}ListView(this); } '''); final formatter = DartFormatter( languageVersion: DartFormatter.latestShortStyleLanguageVersion); outputFile.writeAsStringSync(formatter.format(s.toString())); } }