dart-sdk/sdk/lib/ffi/ffi.dart
Daco Harkes 4b66657b98 [vm/ffi] address of operator for FFI leaf calls
During FFI leaf calls, the Dart GC will not run. This means that we
can pass pointers into `TypedData` to FFI calls that take `Pointer`
arguments.

After this CL, we have three types of arguments that can flow into
`Pointer` argument in an FFI call:
* `Pointer`.
* `TypedData`: Any typed data including views.
* `_Compound`: A TypedData/Pointer and an offset in bytes.

The is only possible for `@Native external` functions, `asFunction`
does not support passing in `TypedData`. (See related GitHub issues
for discussion. TLDR: FFIgen should generate bindings without config.)

`.address` expressions on `TypedData` and `Array` elements do _not_
introduce bounds checks, even though `TypedData` and `Array` have
bounds information. E.g. `ffiNative(Uint8List(10)[20].address)` does
not throw.

Implementation details:

The CFE analyzes call-sites to `@Native external` functions. If the
arguments are `.address` expressions, it transforms the call site to
pass the compound or `TypedData`. If an additional offset needs to be
applied, the CFE constructs a new `_Compound` with the correct offset
in bytes.

The CFE then also creates a new `@Native external` function which have
`TypedData`s and `_Compound`s parameters. To avoid name clashes, these
functions are postfixed with `#` and `P`, `T`, or `C` for each Pointer
parameter.

TEST=pkg/vm/testcases/transformations/ffi/address_of_*

In the VM, `TypedData` arguments are passed as tagged values, and the
address is loaded inside the `FfiCallInstr`. `_Compound` arguments
turn into two IL definitions, one for the `TypedDataBase` (tagged),
and one for the offset in bytes (unboxed). The address is then loaded
inside the `FfiCallInstr` and the offset in bytes is applied.

Adding the offset in bytes required an extra temp register for ia32.
Also, it uncovered that the temp register in arm32 was conflicting
with the argument registers. However, TMP should suffice instead.

TEST=tests/ffi/address_of_array_generated_test.dart
TEST=tests/ffi/address_of_struct_generated_test.dart
TEST=tests/ffi/address_of_typeddata_generated_test.dart

Closes: https://github.com/dart-lang/sdk/issues/44589
Closes: https://github.com/dart-lang/sdk/issues/54771

CoreLibraryReviewExempt: VM only, unsupported in dart2wasm
Change-Id: I01fb428cfd6f9096a34689c2819c124a8003cb6b
Cq-Include-Trybots: dart/try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360882
Reviewed-by: Jens Johansen <jensj@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
2024-04-25 10:06:16 +00:00

2377 lines
87 KiB
Dart

// Copyright (c) 2019, 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
/// Foreign Function Interface for interoperability with the C programming language.
///
/// For further details, please see: https://dart.dev/server/c-interop.
///
/// {@category VM}
@Since('2.6')
library dart.ffi;
import 'dart:_internal' show Since;
import 'dart:isolate';
import 'dart:typed_data';
part 'abi.dart';
part 'abi_specific.dart';
part 'native_type.dart';
part 'native_finalizer.dart';
part 'allocation.dart';
part 'annotations.dart';
part 'c_type.dart';
part 'dynamic_library.dart';
part 'struct.dart';
part 'union.dart';
/// Number of bytes used by native type T.
///
/// Includes padding and alignment of structs.
///
/// This function must be invoked with a compile-time constant [T].
external int sizeOf<T extends SizedNativeType>();
/// Represents a pointer into the native C memory corresponding to 'NULL', e.g.
/// a pointer with address 0.
final Pointer<Never> nullptr = Pointer.fromAddress(0);
/// Represents a pointer into the native C memory. Cannot be extended.
@pragma('vm:entry-point')
@pragma("wasm:entry-point")
final class Pointer<T extends NativeType> implements SizedNativeType {
/// Construction from raw integer.
external factory Pointer.fromAddress(int ptr);
/// Convert Dart function to a C function pointer, automatically marshalling
/// the arguments and return value
///
/// If an exception is thrown while calling `f()`, the native function will
/// return `exceptionalReturn`, which must be assignable to return type of `f`.
///
/// The returned function address can only be invoked on the mutator (main)
/// thread of the current isolate. It will abort the process if invoked on any
/// other thread. Use [NativeCallable.listener] to create callbacks that can
/// be invoked from any thread.
///
/// The pointer returned will remain alive for the duration of the current
/// isolate's lifetime. After the isolate it was created in is terminated,
/// invoking it from native code will cause undefined behavior.
///
/// [Pointer.fromFunction] only accepts static or top level functions. Use
/// [NativeCallable.isolateLocal] to create callbacks from any Dart function
/// or closure.
external static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
@DartRepresentationOf('T') Function f,
[Object? exceptionalReturn]);
/// Access to the raw pointer value.
/// On 32-bit systems, the upper 32-bits of the result are 0.
external int get address;
/// Cast Pointer<T> to a Pointer<U>.
external Pointer<U> cast<U extends NativeType>();
/// Equality for Pointers only depends on their address.
bool operator ==(Object other) {
if (other is! Pointer) return false;
Pointer otherPointer = other;
return address == otherPointer.address;
}
/// The hash code for a Pointer only depends on its address.
int get hashCode {
return address.hashCode;
}
}
/// A fixed-sized array of [T]s.
@Since('2.13')
final class Array<T extends NativeType> extends _Compound {
/// Const constructor to specify [Array] dimensions in [Struct]s.
///
/// ```dart
/// final class MyStruct extends Struct {
/// @Array(8)
/// external Array<Uint8> inlineArray;
///
/// @Array(2, 2, 2)
/// external Array<Array<Array<Uint8>>> threeDimensionalInlineArray;
/// }
/// ```
///
/// Do not invoke in normal code.
const factory Array(int dimension1,
[int dimension2,
int dimension3,
int dimension4,
int dimension5]) = _ArraySize<T>;
/// Const constructor to specify [Array] dimensions in [Struct]s.
///
/// ```dart
/// final class MyStruct extends Struct {
/// @Array.multi([2, 2, 2])
/// external Array<Array<Array<Uint8>>> threeDimensionalInlineArray;
///
/// @Array.multi([2, 2, 2, 2, 2, 2, 2, 2])
/// external Array<Array<Array<Array<Array<Array<Array<Array<Uint8>>>>>>>> eightDimensionalInlineArray;
/// }
/// ```
///
/// Do not invoke in normal code.
const factory Array.multi(List<int> dimensions) = _ArraySize<T>.multi;
}
final class _ArraySize<T extends NativeType> implements Array<T> {
final int? dimension1;
final int? dimension2;
final int? dimension3;
final int? dimension4;
final int? dimension5;
final List<int>? dimensions;
const _ArraySize(this.dimension1,
[this.dimension2, this.dimension3, this.dimension4, this.dimension5])
: dimensions = null;
const _ArraySize.multi(this.dimensions)
: dimension1 = null,
dimension2 = null,
dimension3 = null,
dimension4 = null,
dimension5 = null;
}
/// Extension on [Pointer] specialized for the type argument [NativeFunction].
extension NativeFunctionPointer<NF extends Function>
on Pointer<NativeFunction<NF>> {
/// Convert to Dart function, automatically marshalling the arguments and
/// return value.
///
/// [isLeaf] specifies whether the function is a leaf function. Leaf functions
/// are small, short-running, non-blocking functions which are not allowed to
/// call back into Dart or use any Dart VM APIs. Leaf functions are invoked
/// bypassing some of the heavier parts of the standard Dart-to-Native calling
/// sequence which reduces the invocation overhead, making leaf calls faster
/// than non-leaf calls. However, this implies that a thread executing a leaf
/// function can't cooperate with the Dart runtime. A long running or blocking
/// leaf function will delay any operation which requires synchronization
/// between all threads associated with an isolate group until after the leaf
/// function returns. For example, if one isolate in a group is trying to
/// perform a GC and a second isolate is blocked in a leaf call, then the
/// first isolate will have to pause and wait until this leaf call returns.
external DF asFunction<@DartRepresentationOf('NF') DF extends Function>(
{bool isLeaf = false});
}
/// A native callable which listens for calls to a native function.
///
/// Creates a native function linked to a Dart function, so that calling the
/// native function will call the Dart function in some way, with the arguments
/// converted to Dart values.
@Since('3.1')
abstract final class NativeCallable<T extends Function> {
/// Constructs a [NativeCallable] that must be invoked from the same thread
/// that created it.
///
/// If an exception is thrown by the [callback], the native function will
/// return the `exceptionalReturn`, which must be assignable to the return
/// type of the [callback].
///
/// The returned function address can only be invoked on the mutator (main)
/// thread of the current isolate. It will abort the process if invoked on any
/// other thread. Use [NativeCallable.listener] to create callbacks that can
/// be invoked from any thread.
///
/// Unlike [Pointer.fromFunction], [NativeCallable]s can be constructed from
/// any Dart function or closure, not just static or top level functions.
///
/// This callback must be [close]d when it is no longer needed. The [Isolate]
/// that created the callback will be kept alive until [close] is called.
/// After [NativeCallable.close] is called, invoking the [nativeFunction] from
/// native code will cause undefined behavior.
factory NativeCallable.isolateLocal(
@DartRepresentationOf("T") Function callback,
{Object? exceptionalReturn}) {
throw UnsupportedError("NativeCallable cannot be constructed dynamically.");
}
/// Constructs a [NativeCallable] that can be invoked from any thread.
///
/// When the native code invokes the function [nativeFunction], the arguments
/// will be sent over a [SendPort] to the [Isolate] that created the
/// [NativeCallable], and the callback will be invoked.
///
/// The native code does not wait for a response from the callback, so only
/// functions returning void are supported.
///
/// The callback will be invoked at some time in the future. The native caller
/// cannot assume the callback will be run immediately. Resources passed to
/// the callback (such as pointers to malloc'd memory, or output parameters)
/// must be valid until the call completes.
///
/// This callback must be [close]d when it is no longer needed. The [Isolate]
/// that created the callback will be kept alive until [close] is called.
/// After [NativeCallable.close] is called, invoking the [nativeFunction] from
/// native code will cause undefined behavior.
///
/// For example:
///
/// ```dart
/// import 'dart:async';
/// import 'dart:ffi';
/// import 'package:ffi/ffi.dart';
///
/// // Processes a simple HTTP GET request using a native HTTP library that
/// // processes the request on a background thread.
/// Future<String> httpGet(String uri) async {
/// final uriPointer = uri.toNativeUtf8();
///
/// // Create the NativeCallable.listener.
/// final completer = Completer<String>();
/// late final NativeCallable<NativeHttpCallback> callback;
/// void onResponse(Pointer<Utf8> responsePointer) {
/// completer.complete(responsePointer.toDartString());
/// calloc.free(responsePointer);
/// calloc.free(uriPointer);
///
/// // Remember to close the NativeCallable once the native API is
/// // finished with it, otherwise this isolate will stay alive
/// // indefinitely.
/// callback.close();
/// }
/// callback = NativeCallable<NativeHttpCallback>.listener(onResponse);
///
/// // Invoke the native HTTP API. Our example HTTP library processes our
/// // request on a background thread, and calls the callback on that same
/// // thread when it receives the response.
/// nativeHttpGet(uriPointer, callback.nativeFunction);
///
/// return completer.future;
/// }
///
/// // Load the native functions from a DynamicLibrary.
/// final DynamicLibrary dylib = DynamicLibrary.process();
/// typedef NativeHttpCallback = Void Function(Pointer<Utf8>);
///
/// typedef HttpGetFunction = void Function(
/// Pointer<Utf8>, Pointer<NativeFunction<NativeHttpCallback>>);
/// typedef HttpGetNativeFunction = Void Function(
/// Pointer<Utf8>, Pointer<NativeFunction<NativeHttpCallback>>);
/// final nativeHttpGet =
/// dylib.lookupFunction<HttpGetNativeFunction, HttpGetFunction>(
/// 'http_get');
/// ```
factory NativeCallable.listener(
@DartRepresentationOf("T") Function callback) {
throw UnsupportedError("NativeCallable cannot be constructed dynamically.");
}
/// The native function pointer which can be used to invoke the `callback`
/// passed to the constructor.
///
/// This pointer must not be read after the callable has been [close]d.
Pointer<NativeFunction<T>> get nativeFunction;
/// Closes this callback and releases its resources.
///
/// Further calls to existing [nativeFunction]s will result in undefined
/// behavior.
///
/// Subsequent calls to [close] will be ignored.
///
/// It is safe to call [close] inside the [callback].
void close();
/// Whether this [NativeCallable] keeps its [Isolate] alive.
///
/// By default, [NativeCallable]s keep the [Isolate] that created them alive
/// until [close] is called. If [keepIsolateAlive] is set to `false`, the
/// isolate may exit even if the [NativeCallable] isn't closed.
external bool keepIsolateAlive;
}
//
// The following code is generated, do not edit by hand.
//
// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
//
/// Extension on [Pointer] specialized for the type argument [Int8].
extension Int8Pointer on Pointer<Int8> {
/// The 8-bit two's complement integer at [address].
///
/// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
/// being stored, and the 8-bit value is sign-extended when it is loaded.
external int get value;
external void set value(int value);
/// The 8-bit two's complement integer at `address + sizeOf<Int8>() * index`.
///
/// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
/// being stored, and the 8-bit value is sign-extended when it is loaded.
external int operator [](int index);
/// The 8-bit two's complement integer at `address + sizeOf<Int8>() * index`.
///
/// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
/// being stored, and the 8-bit value is sign-extended when it is loaded.
external void operator []=(int index, int value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Int8> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Int8>() * index);
/// A pointer to the [offset]th [Int8] after this one.
///
/// Returns a pointer to the [Int8] whose address is
/// [offset] times the size of `Int8` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Int8>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Int8> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Int8>() * offset);
/// A pointer to the [offset]th [Int8] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Int8] whose address is
/// [offset] times the size of `Int8` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Int8>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Int8> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Int8>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Int8>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
external Int8List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Int16].
extension Int16Pointer on Pointer<Int16> {
/// The 16-bit two's complement integer at [address].
///
/// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
/// being stored, and the 16-bit value is sign-extended when it is loaded.
///
/// The [address] must be 2-byte aligned.
external int get value;
external void set value(int value);
/// The 16-bit two's complement integer at `address + sizeOf<Int16>() * index`.
///
/// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
/// being stored, and the 16-bit value is sign-extended when it is loaded.
///
/// The [address] must be 2-byte aligned.
external int operator [](int index);
/// The 16-bit two's complement integer at `address + sizeOf<Int16>() * index`.
///
/// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
/// being stored, and the 16-bit value is sign-extended when it is loaded.
///
/// The [address] must be 2-byte aligned.
external void operator []=(int index, int value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Int16> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Int16>() * index);
/// A pointer to the [offset]th [Int16] after this one.
///
/// Returns a pointer to the [Int16] whose address is
/// [offset] times the size of `Int16` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Int16>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Int16> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Int16>() * offset);
/// A pointer to the [offset]th [Int16] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Int16] whose address is
/// [offset] times the size of `Int16` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Int16>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Int16> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Int16>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Int16>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
///
/// The [address] must be 2-byte aligned.
external Int16List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Int32].
extension Int32Pointer on Pointer<Int32> {
/// The 32-bit two's complement integer at [address].
///
/// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
/// being stored, and the 32-bit value is sign-extended when it is loaded.
///
/// The [address] must be 4-byte aligned.
external int get value;
external void set value(int value);
/// The 32-bit two's complement integer at `address + sizeOf<Int32>() * index`.
///
/// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
/// being stored, and the 32-bit value is sign-extended when it is loaded.
///
/// The [address] must be 4-byte aligned.
external int operator [](int index);
/// The 32-bit two's complement integer at `address + sizeOf<Int32>() * index`.
///
/// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
/// being stored, and the 32-bit value is sign-extended when it is loaded.
///
/// The [address] must be 4-byte aligned.
external void operator []=(int index, int value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Int32> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Int32>() * index);
/// A pointer to the [offset]th [Int32] after this one.
///
/// Returns a pointer to the [Int32] whose address is
/// [offset] times the size of `Int32` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Int32>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Int32> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Int32>() * offset);
/// A pointer to the [offset]th [Int32] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Int32] whose address is
/// [offset] times the size of `Int32` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Int32>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Int32> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Int32>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Int32>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
///
/// The [address] must be 4-byte aligned.
external Int32List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Int64].
extension Int64Pointer on Pointer<Int64> {
/// The 64-bit two's complement integer at [address].
///
/// The [address] must be 8-byte aligned.
external int get value;
external void set value(int value);
/// The 64-bit two's complement integer at `address + sizeOf<Int64>() * index`.
///
/// The [address] must be 8-byte aligned.
external int operator [](int index);
/// The 64-bit two's complement integer at `address + sizeOf<Int64>() * index`.
///
/// The [address] must be 8-byte aligned.
external void operator []=(int index, int value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Int64> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Int64>() * index);
/// A pointer to the [offset]th [Int64] after this one.
///
/// Returns a pointer to the [Int64] whose address is
/// [offset] times the size of `Int64` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Int64>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Int64> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Int64>() * offset);
/// A pointer to the [offset]th [Int64] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Int64] whose address is
/// [offset] times the size of `Int64` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Int64>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Int64> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Int64>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Int64>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
///
/// The [address] must be 8-byte aligned.
external Int64List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Uint8].
extension Uint8Pointer on Pointer<Uint8> {
/// The 8-bit unsigned integer at [address].
///
/// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
/// being stored, and the 8-bit value is zero-extended when it is loaded.
external int get value;
external void set value(int value);
/// The 8-bit unsigned integer at `address + sizeOf<Uint8>() * index`.
///
/// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
/// being stored, and the 8-bit value is zero-extended when it is loaded.
external int operator [](int index);
/// The 8-bit unsigned integer at `address + sizeOf<Uint8>() * index`.
///
/// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
/// being stored, and the 8-bit value is zero-extended when it is loaded.
external void operator []=(int index, int value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Uint8> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Uint8>() * index);
/// A pointer to the [offset]th [Uint8] after this one.
///
/// Returns a pointer to the [Uint8] whose address is
/// [offset] times the size of `Uint8` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Uint8>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Uint8> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Uint8>() * offset);
/// A pointer to the [offset]th [Uint8] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Uint8] whose address is
/// [offset] times the size of `Uint8` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Uint8>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Uint8> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Uint8>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Uint8>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
external Uint8List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Uint16].
extension Uint16Pointer on Pointer<Uint16> {
/// The 16-bit unsigned integer at [address].
///
/// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
/// being stored, and the 16-bit value is zero-extended when it is loaded.
///
/// The [address] must be 2-byte aligned.
external int get value;
external void set value(int value);
/// The 16-bit unsigned integer at `address + sizeOf<Uint16>() * index`.
///
/// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
/// being stored, and the 16-bit value is zero-extended when it is loaded.
///
/// The [address] must be 2-byte aligned.
external int operator [](int index);
/// The 16-bit unsigned integer at `address + sizeOf<Uint16>() * index`.
///
/// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
/// being stored, and the 16-bit value is zero-extended when it is loaded.
///
/// The [address] must be 2-byte aligned.
external void operator []=(int index, int value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Uint16> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Uint16>() * index);
/// A pointer to the [offset]th [Uint16] after this one.
///
/// Returns a pointer to the [Uint16] whose address is
/// [offset] times the size of `Uint16` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Uint16>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Uint16> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Uint16>() * offset);
/// A pointer to the [offset]th [Uint16] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Uint16] whose address is
/// [offset] times the size of `Uint16` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Uint16>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Uint16> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Uint16>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Uint16>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
///
/// The [address] must be 2-byte aligned.
external Uint16List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Uint32].
extension Uint32Pointer on Pointer<Uint32> {
/// The 32-bit unsigned integer at [address].
///
/// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
/// being stored, and the 32-bit value is zero-extended when it is loaded.
///
/// The [address] must be 4-byte aligned.
external int get value;
external void set value(int value);
/// The 32-bit unsigned integer at `address + sizeOf<Uint32>() * index`.
///
/// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
/// being stored, and the 32-bit value is zero-extended when it is loaded.
///
/// The [address] must be 4-byte aligned.
external int operator [](int index);
/// The 32-bit unsigned integer at `address + sizeOf<Uint32>() * index`.
///
/// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
/// being stored, and the 32-bit value is zero-extended when it is loaded.
///
/// The [address] must be 4-byte aligned.
external void operator []=(int index, int value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Uint32> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Uint32>() * index);
/// A pointer to the [offset]th [Uint32] after this one.
///
/// Returns a pointer to the [Uint32] whose address is
/// [offset] times the size of `Uint32` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Uint32>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Uint32> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Uint32>() * offset);
/// A pointer to the [offset]th [Uint32] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Uint32] whose address is
/// [offset] times the size of `Uint32` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Uint32>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Uint32> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Uint32>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Uint32>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
///
/// The [address] must be 4-byte aligned.
external Uint32List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Uint64].
extension Uint64Pointer on Pointer<Uint64> {
/// The 64-bit unsigned integer at [address].
///
/// The [address] must be 8-byte aligned.
external int get value;
external void set value(int value);
/// The 64-bit unsigned integer at `address + sizeOf<Uint64>() * index`.
///
/// The [address] must be 8-byte aligned.
external int operator [](int index);
/// The 64-bit unsigned integer at `address + sizeOf<Uint64>() * index`.
///
/// The [address] must be 8-byte aligned.
external void operator []=(int index, int value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Uint64> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Uint64>() * index);
/// A pointer to the [offset]th [Uint64] after this one.
///
/// Returns a pointer to the [Uint64] whose address is
/// [offset] times the size of `Uint64` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Uint64>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Uint64> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Uint64>() * offset);
/// A pointer to the [offset]th [Uint64] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Uint64] whose address is
/// [offset] times the size of `Uint64` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Uint64>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Uint64> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Uint64>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Uint64>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
///
/// The [address] must be 8-byte aligned.
external Uint64List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Float].
extension FloatPointer on Pointer<Float> {
/// The float at [address].
///
/// A Dart double loses precision before being stored, and the float value is
/// converted to a double when it is loaded.
///
/// The [address] must be 4-byte aligned.
external double get value;
external void set value(double value);
/// The float at `address + sizeOf<Float>() * index`.
///
/// A Dart double loses precision before being stored, and the float value is
/// converted to a double when it is loaded.
///
/// The [address] must be 4-byte aligned.
external double operator [](int index);
/// The float at `address + sizeOf<Float>() * index`.
///
/// A Dart double loses precision before being stored, and the float value is
/// converted to a double when it is loaded.
///
/// The [address] must be 4-byte aligned.
external void operator []=(int index, double value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Float> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Float>() * index);
/// A pointer to the [offset]th [Float] after this one.
///
/// Returns a pointer to the [Float] whose address is
/// [offset] times the size of `Float` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Float>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Float> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Float>() * offset);
/// A pointer to the [offset]th [Float] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Float] whose address is
/// [offset] times the size of `Float` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Float>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Float> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Float>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Float>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
///
/// The [address] must be 4-byte aligned.
external Float32List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Double].
extension DoublePointer on Pointer<Double> {
/// The double at [address].
///
/// The [address] must be 8-byte aligned.
external double get value;
external void set value(double value);
/// The double at `address + sizeOf<Double>() * index`.
///
/// The [address] must be 8-byte aligned.
external double operator [](int index);
/// The double at `address + sizeOf<Double>() * index`.
///
/// The [address] must be 8-byte aligned.
external void operator []=(int index, double value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Double> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Double>() * index);
/// A pointer to the [offset]th [Double] after this one.
///
/// Returns a pointer to the [Double] whose address is
/// [offset] times the size of `Double` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Double>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Double> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Double>() * offset);
/// A pointer to the [offset]th [Double] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Double] whose address is
/// [offset] times the size of `Double` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Double>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Double> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Double>() * offset);
/// Creates a typed list view backed by memory in the address space.
///
/// The returned view will allow access to the memory range from [address]
/// to `address + sizeOf<Double>() * length`.
///
/// The user has to ensure the memory range is accessible while using the
/// returned list.
///
/// If provided, [finalizer] will be run on the pointer once the typed list
/// is GCed. If provided, [token] will be passed to [finalizer], otherwise
/// the this pointer itself will be passed.
///
/// The [address] must be 8-byte aligned.
external Float64List asTypedList(
int length, {
@Since('3.1') Pointer<NativeFinalizerFunction>? finalizer,
@Since('3.1') Pointer<Void>? token,
});
}
/// Extension on [Pointer] specialized for the type argument [Bool].
@Since('2.15')
extension BoolPointer on Pointer<Bool> {
/// The bool at [address].
external bool get value;
external void set value(bool value);
/// The bool at `address + sizeOf<Bool>() * index`.
external bool operator [](int index);
/// The bool at `address + sizeOf<Bool>() * index`.
external void operator []=(int index, bool value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
Pointer<Bool> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<Bool>() * index);
/// A pointer to the [offset]th [Bool] after this one.
///
/// Returns a pointer to the [Bool] whose address is
/// [offset] times the size of `Bool` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Bool>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Bool> operator +(int offset) =>
Pointer.fromAddress(address + sizeOf<Bool>() * offset);
/// A pointer to the [offset]th [Bool] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Bool] whose address is
/// [offset] times the size of `Bool` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Bool>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
@Since('3.3')
@pragma("vm:prefer-inline")
Pointer<Bool> operator -(int offset) =>
Pointer.fromAddress(address - sizeOf<Bool>() * offset);
}
/// Bounds checking indexing methods on [Array]s of [Int8].
@Since('2.13')
extension Int8Array on Array<Int8> {
external int operator [](int index);
external void operator []=(int index, int value);
}
/// Bounds checking indexing methods on [Array]s of [Int16].
@Since('2.13')
extension Int16Array on Array<Int16> {
external int operator [](int index);
external void operator []=(int index, int value);
}
/// Bounds checking indexing methods on [Array]s of [Int32].
@Since('2.13')
extension Int32Array on Array<Int32> {
external int operator [](int index);
external void operator []=(int index, int value);
}
/// Bounds checking indexing methods on [Array]s of [Int64].
@Since('2.13')
extension Int64Array on Array<Int64> {
external int operator [](int index);
external void operator []=(int index, int value);
}
/// Bounds checking indexing methods on [Array]s of [Uint8].
@Since('2.13')
extension Uint8Array on Array<Uint8> {
external int operator [](int index);
external void operator []=(int index, int value);
}
/// Bounds checking indexing methods on [Array]s of [Uint16].
@Since('2.13')
extension Uint16Array on Array<Uint16> {
external int operator [](int index);
external void operator []=(int index, int value);
}
/// Bounds checking indexing methods on [Array]s of [Uint32].
@Since('2.13')
extension Uint32Array on Array<Uint32> {
external int operator [](int index);
external void operator []=(int index, int value);
}
/// Bounds checking indexing methods on [Array]s of [Uint64].
@Since('2.13')
extension Uint64Array on Array<Uint64> {
external int operator [](int index);
external void operator []=(int index, int value);
}
/// Bounds checking indexing methods on [Array]s of [Float].
@Since('2.13')
extension FloatArray on Array<Float> {
external double operator [](int index);
external void operator []=(int index, double value);
}
/// Bounds checking indexing methods on [Array]s of [Double].
@Since('2.13')
extension DoubleArray on Array<Double> {
external double operator [](int index);
external void operator []=(int index, double value);
}
/// Bounds checking indexing methods on [Array]s of [Bool].
@Since('2.15')
extension BoolArray on Array<Bool> {
external bool operator [](int index);
external void operator []=(int index, bool value);
}
@Since('3.5')
extension Int8ListAddress on Int8List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Int8>)>(isLeaf: true)
/// external void myFunction(Pointer<Int8> pointer);
///
/// void main() {
/// final list = Int8List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Int8> get address;
}
@Since('3.5')
extension Int16ListAddress on Int16List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Int16>)>(isLeaf: true)
/// external void myFunction(Pointer<Int16> pointer);
///
/// void main() {
/// final list = Int16List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Int16> get address;
}
@Since('3.5')
extension Int32ListAddress on Int32List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Int32>)>(isLeaf: true)
/// external void myFunction(Pointer<Int32> pointer);
///
/// void main() {
/// final list = Int32List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Int32> get address;
}
@Since('3.5')
extension Int64ListAddress on Int64List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Int64>)>(isLeaf: true)
/// external void myFunction(Pointer<Int64> pointer);
///
/// void main() {
/// final list = Int64List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Int64> get address;
}
@Since('3.5')
extension Uint8ListAddress on Uint8List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Uint8>)>(isLeaf: true)
/// external void myFunction(Pointer<Uint8> pointer);
///
/// void main() {
/// final list = Uint8List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Uint8> get address;
}
@Since('3.5')
extension Uint16ListAddress on Uint16List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Uint16>)>(isLeaf: true)
/// external void myFunction(Pointer<Uint16> pointer);
///
/// void main() {
/// final list = Uint16List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Uint16> get address;
}
@Since('3.5')
extension Uint32ListAddress on Uint32List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Uint32>)>(isLeaf: true)
/// external void myFunction(Pointer<Uint32> pointer);
///
/// void main() {
/// final list = Uint32List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Uint32> get address;
}
@Since('3.5')
extension Uint64ListAddress on Uint64List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Uint64>)>(isLeaf: true)
/// external void myFunction(Pointer<Uint64> pointer);
///
/// void main() {
/// final list = Uint64List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Uint64> get address;
}
@Since('3.5')
extension Float32ListAddress on Float32List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Float>)>(isLeaf: true)
/// external void myFunction(Pointer<Float> pointer);
///
/// void main() {
/// final list = Float32List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Float> get address;
}
@Since('3.5')
extension Float64ListAddress on Float64List {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address`
/// can only occurr as an entire argument expression in the invocation of
/// a leaf [Native] external function.
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Double>)>(isLeaf: true)
/// external void myFunction(Pointer<Double> pointer);
///
/// void main() {
/// final list = Float64List(10);
/// myFunction(list.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Double> get address;
}
//
// End of generated code.
//
/// Extension on [Pointer] specialized for the type argument [Pointer].
extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
/// The pointer at [address].
///
/// A [Pointer] is unboxed before being stored (as if by `.address`), and the
/// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
///
/// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
/// platforms the [address] must be 8-byte aligned.
external Pointer<T> get value;
external void set value(Pointer<T> value);
/// Load a Dart value from this location offset by [index].
///
/// A [Pointer] is unboxed before being stored (as if by `.address`), and the
/// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
///
/// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
/// platforms the [address] must be 8-byte aligned.
external Pointer<T> operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// A [Pointer] is unboxed before being stored (as if by `.address`), and the
/// pointer is boxed (as if by [Pointer.fromAddress]) when loaded.
///
/// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
/// platforms the [address] must be 8-byte aligned.
external void operator []=(int index, Pointer<T> value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
external Pointer<Pointer<T>> elementAt(int index);
/// A pointer to the [offset]th [Pointer<T>] after this one.
///
/// Returns a pointer to the [Pointer<T>] whose address is
/// [offset] times the size of `Pointer<T>` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<Pointer<T>>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
external Pointer<Pointer<T>> operator +(int offset);
/// A pointer to the [offset]th [Pointer<T>] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [Pointer<T>] whose address is
/// [offset] times the size of `Pointer<T>` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<Pointer<T>>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
external Pointer<Pointer<T>> operator -(int offset);
}
/// Extension on [Pointer] specialized for the type argument [Struct].
@Since('2.12')
extension StructPointer<T extends Struct> on Pointer<T> {
/// A Dart view of the struct referenced by this pointer.
///
/// Reading [ref] creates a reference accessing the fields of this struct
/// backed by native memory at [address].
/// The [address] must be aligned according to the struct alignment rules of
/// the platform.
///
/// Assigning to [ref] copies contents of the struct into the native memory
/// starting at [address].
///
/// This extension method must be invoked on a receiver of type `Pointer<T>`
/// where `T` is a compile-time constant type.
external T get ref;
external set ref(T value);
/// Creates a reference to access the fields of this struct backed by native
/// memory at `address + sizeOf<T>() * index`.
///
/// The [address] must be aligned according to the struct alignment rules of
/// the platform.
///
/// This extension method must be invoked on a receiver of type `Pointer<T>`
/// where `T` is a compile-time constant type.
external T operator [](int index);
/// Copies the [value] struct into native memory, starting at
/// `address * sizeOf<T>() * index`.
///
/// This extension method must be invoked on a receiver of type `Pointer<T>`
/// where `T` is a compile-time constant type.
external void operator []=(int index, T value);
/// Pointer arithmetic (takes element size into account)
@Deprecated('Use operator + instead')
external Pointer<T> elementAt(int index);
/// A pointer to the [offset]th [T] after this one.
///
/// Returns a pointer to the [T] whose address is
/// [offset] times the size of `T` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<T>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
external Pointer<T> operator +(int offset);
/// A pointer to the [offset]th [T] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [T] whose address is
/// [offset] times the size of `T` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<T>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
external Pointer<T> operator -(int offset);
}
/// Extension on [Pointer] specialized for the type argument [Union].
@Since('2.14')
extension UnionPointer<T extends Union> on Pointer<T> {
/// A Dart view of the union referenced by this pointer.
///
/// Reading [ref] creates a reference accessing the fields of this union
/// backed by native memory at [address].
/// The [address] must be aligned according to the union alignment rules of
/// the platform.
///
/// Assigning to [ref] copies contents of the union into the native memory
/// starting at [address].
///
/// This extension method must be invoked on a receiver of type `Pointer<T>`
/// where `T` is a compile-time constant type.
external T get ref;
external set ref(T value);
/// Creates a reference to access the fields of this union backed by native
/// memory at `address + sizeOf<T>() * index`.
///
/// The [address] must be aligned according to the union alignment rules of
/// the platform.
///
/// This extension method must be invoked on a receiver of type `Pointer<T>`
/// where `T` is a compile-time constant type.
external T operator [](int index);
/// Copies the [value] union into native memory, starting at
/// `address * sizeOf<T>() * index`.
///
/// This extension method must be invoked on a receiver of type `Pointer<T>`
/// where `T` is a compile-time constant type.
external void operator []=(int index, T value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
external Pointer<T> elementAt(int index);
/// A pointer to the [offset]th [T] after this one.
///
/// Returns a pointer to the [T] whose address is
/// [offset] times the size of `T` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<T>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
external Pointer<T> operator +(int offset);
/// A pointer to the [offset]th [T] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [T] whose address is
/// [offset] times the size of `T` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<T>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
external Pointer<T> operator -(int offset);
}
/// Extension on [Pointer] specialized for the type argument
/// [AbiSpecificInteger].
@Since('2.16')
extension AbiSpecificIntegerPointer<T extends AbiSpecificInteger>
on Pointer<T> {
/// The integer at [address].
external int get value;
external void set value(int value);
/// The integer at `address + sizeOf<T>() * index`.
external int operator [](int index);
/// The integer at `address + sizeOf<T>() * index`.
external void operator []=(int index, int value);
/// Pointer arithmetic (takes element size into account).
@Deprecated('Use operator + instead')
external Pointer<T> elementAt(int index);
/// A pointer to the [offset]th [T] after this one.
///
/// Returns a pointer to the [T] whose address is
/// [offset] times the size of `T` after the address of this pointer.
/// That is `(this + offset).address == this.address + offset * sizeOf<T>()`.
///
/// Also `(this + offset).value` is equivalent to `this[offset]`,
/// and similarly for setting.
external Pointer<T> operator +(int offset);
/// A pointer to the [offset]th [T] before this one.
///
/// Equivalent to `this + (-offset)`.
///
/// Returns a pointer to the [T] whose address is
/// [offset] times the size of `T` before the address of this pointer.
/// That is, `(this - offset).address == this.address - offset * sizeOf<T>()`.
///
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
/// and similarly for setting,
external Pointer<T> operator -(int offset);
}
/// Bounds checking indexing methods on [Array]s of [Pointer].
@Since('2.13')
extension PointerArray<T extends NativeType> on Array<Pointer<T>> {
external Pointer<T> operator [](int index);
external void operator []=(int index, Pointer<T> value);
}
/// Bounds checking indexing methods on [Array]s of [Struct].
@Since('2.13')
extension StructArray<T extends Struct> on Array<T> {
/// This extension method must be invoked on a receiver of type `Pointer<T>`
/// where `T` is a compile-time constant type.
external T operator [](int index);
}
/// Bounds checking indexing methods on [Array]s of [Union].
@Since('2.14')
extension UnionArray<T extends Union> on Array<T> {
/// This extension method must be invoked on a receiver of type `Pointer<T>`
/// where `T` is a compile-time constant type.
external T operator [](int index);
}
/// Bounds checking indexing methods on [Array]s of [Array].
@Since('2.13')
extension ArrayArray<T extends NativeType> on Array<Array<T>> {
external Array<T> operator [](int index);
external void operator []=(int index, Array<T> value);
}
/// Bounds checking indexing methods on [Array]s of [AbiSpecificInteger].
@Since('2.16')
extension AbiSpecificIntegerArray<T extends AbiSpecificInteger> on Array<T> {
external int operator [](int index);
external void operator []=(int index, int value);
}
@Since('3.5')
extension ArrayAddress<T extends NativeType> on Array<T> {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address` can
/// only occurr as an entire argument expression in the invocation of a leaf
/// [Native] external function.
///
/// Example:
///
/// ```dart
/// @Native<Void Function(Pointer<Int8>)>(isLeaf: true)
/// external void myFunction(Pointer<Int8> pointer);
///
/// final class MyStruct extends Struct {
/// @Array(10)
/// external Array<Int8> array;
/// }
///
/// void main() {
/// final array = Struct.create<MyStruct>().array;
/// myFunction(array.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<T> get address;
}
@Since('3.5')
extension StructAddress<T extends Struct> on T {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address` can
/// only occurr as an entire argument expression in the invocation of a leaf
/// [Native] external function.
///
/// Example:
///
/// ```dart
/// @Native<Void Function(Pointer<MyStruct>)>(isLeaf: true)
/// external void myFunction(Pointer<MyStruct> pointer);
///
/// final class MyStruct extends Struct {
/// @Int8()
/// external int x;
/// }
///
/// void main() {
/// final myStruct = Struct.create<MyStruct>();
/// myFunction(myStruct.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<T> get address;
}
@Since('3.5')
extension UnionAddress<T extends Union> on T {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address` can
/// only occurr as an entire argument expression in the invocation of a leaf
/// [Native] external function.
///
/// Example:
///
/// ```dart
/// @Native<Void Function(Pointer<MyUnion>)>(isLeaf: true)
/// external void myFunction(Pointer<MyUnion> pointer);
///
/// final class MyUnion extends Union {
/// @Int8()
/// external int x;
/// }
///
/// void main() {
/// final myUnion = Union.create<MyUnion>();
/// myFunction(myUnion.address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<T> get address;
}
@Since('3.5')
extension IntAddress on int {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address` can
/// only occurr as an entire argument expression in the invocation of a leaf
/// [Native] external function.
///
/// Can only be used on fields of [Struct] subtypes, fields of [Union]
/// subtypes, [Array] elements, or [TypedData] elements. In other words, the
/// number whose address is being accessed must itself be acccessed through a
/// [Struct], [Union], [Array], or [TypedData].
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Int8>)>(isLeaf: true)
/// external void myFunction(Pointer<Int8> pointer);
///
/// final class MyStruct extends Struct {
/// @Int8()
/// external int x;
///
/// @Int8()
/// external int y;
///
/// @Array(10)
/// external Array<Int8> array;
/// }
///
/// void main() {
/// final myStruct = Struct.create<MyStruct>();
/// myFunction(myStruct.y.address);
/// myFunction(myStruct.array[5].address);
///
/// final list = Int8List(10);
/// myFunction(list[5].address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Never> address;
}
@Since('3.5')
extension DoubleAddress on double {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address` can
/// only occurr as an entire argument expression in the invocation of a leaf
/// [Native] external function.
///
/// Can only be used on fields of [Struct] subtypes, fields of [Union]
/// subtypes, [Array] elements, or [TypedData] elements. In other words, the
/// number whose address is being accessed must itself be acccessed through a
/// [Struct], [Union], [Array], or [TypedData].
///
/// Example:
///
/// ```dart import:typed_data
/// @Native<Void Function(Pointer<Float>)>(isLeaf: true)
/// external void myFunction(Pointer<Float> pointer);
///
/// final class MyStruct extends Struct {
/// @Float()
/// external double x;
///
/// @Float()
/// external double y;
///
/// @Array(10)
/// external Array<Float> array;
/// }
///
/// void main() {
/// final myStruct = Struct.create<MyStruct>();
/// myFunction(myStruct.y.address);
/// myFunction(myStruct.array[5].address);
///
/// final list = Float32List(10);
/// myFunction(list[5].address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Never> address;
}
@Since('3.5')
extension BoolAddress on bool {
/// The memory address of the underlying data.
///
/// An expression of the form `expression.address` denoting this `address` can
/// only occurr as an entire argument expression in the invocation of a leaf
/// [Native] external function.
///
/// Can only be used on fields of [Struct] subtypes, fields of [Union]
/// subtypes, or [Array] elements. In other words, the boolean whose address
/// is being accessed must itself be acccessed through a [Struct], [Union] or
/// [Array].
///
/// Example:
///
/// ```dart
/// @Native<Void Function(Pointer<Int8>)>(isLeaf: true)
/// external void myFunction(Pointer<Int8> pointer);
///
/// final class MyStruct extends Struct {
/// @Bool()
/// external bool x;
///
/// @Bool()
/// external bool y;
///
/// @Array(10)
/// external Array<Bool> array;
/// }
///
/// void main() {
/// final myStruct = Struct.create<MyStruct>();
/// myFunction(myStruct.y.address);
/// myFunction(myStruct.array[5].address);
/// }
/// ```
///
/// The expression before `.address` is evaluated like the left-hand-side of
/// an assignment, to something that gives access to the storage behind the
/// expression, which can be used both for reading and writing. The `.address`
/// then gives a native pointer to that storage.
///
/// The `.address` is evaluated just before calling into native code when
/// invoking a leaf [Native] external function. This ensures the Dart garbage
/// collector will not move the object that the address points in to.
external Pointer<Never> address;
}
/// Extension to retrieve the native `Dart_Port` from a [SendPort].
@Since('2.7')
extension NativePort on SendPort {
/// The native port of this [SendPort].
///
/// The returned native port can for example be used by C code to post
/// messages to the connected [ReceivePort] via `Dart_PostCObject()` - see
/// `dart_native_api.h`.
///
/// Only the send ports from the platform classes [ReceivePort] and
/// [RawReceivePort] are supported. User-defined implementations of
/// [SendPort] are not supported.
external int get nativePort;
}
/// Opaque, not exposing it's members.
@Since('2.8')
final class Dart_CObject extends Opaque {}
typedef Dart_NativeMessageHandler = Void Function(Int64, Pointer<Dart_CObject>);
/// Utilities for accessing the Dart VM API from Dart code or
/// from C code via `dart_api_dl.h`.
@Since('2.8')
abstract final class NativeApi {
/// On breaking changes the major version is increased.
///
/// The versioning covers the API surface in `dart_api_dl.h`.
@Since('2.9')
external static int get majorVersion;
/// On backwards compatible changes the minor version is increased.
///
/// The versioning covers the API surface in `dart_api_dl.h`.
@Since('2.9')
external static int get minorVersion;
/// A function pointer to
/// `bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message)`
/// in `dart_native_api.h`.
external static Pointer<
NativeFunction<Int8 Function(Int64, Pointer<Dart_CObject>)>>
get postCObject;
/// A function pointer to
/// ```c
/// Dart_Port Dart_NewNativePort(const char* name,
/// Dart_NativeMessageHandler handler,
/// bool handle_concurrently)
/// ```
/// in `dart_native_api.h`.
external static Pointer<
NativeFunction<
Int64 Function(
Pointer<Uint8>,
Pointer<NativeFunction<Dart_NativeMessageHandler>>,
Int8)>> get newNativePort;
/// A function pointer to
/// `bool Dart_CloseNativePort(Dart_Port native_port_id)`
/// in `dart_native_api.h`.
external static Pointer<NativeFunction<Int8 Function(Int64)>>
get closeNativePort;
/// Pass this to `Dart_InitializeApiDL` in your native code to enable using the
/// symbols in `dart_api_dl.h`.
@Since('2.9')
external static Pointer<Void> get initializeApiDLData;
}
/// Annotation binding an external declaration to its native implementation.
///
/// Can only be applied to `external` declarations of static and top-level
/// functions and variables.
///
/// A [Native]-annotated `external` function is implemented by native code.
/// The implementation is found in the native library denoted by [assetId].
/// Similarly, a [Native]-annotated `external` variable is implemented by
/// reading from or writing to native memory.
///
/// The compiler and/or runtime provides a binding from [assetId] to native
/// library, which depends on the target platform.
/// The compiler/runtime can then resolve/lookup symbols (identifiers)
/// against the native library, to find a native function or a native global
/// variable, and bind an `external` Dart function or variable declaration to
/// that native declaration.
/// By default, the runtime expects a native symbol with the same name as the
/// annotated function or variable in Dart. This can be overridden with the
/// [symbol] parameter on the annotation.
///
/// If this annotation is used on a function, then the type argument [T] to the
/// [Native] annotation must be a function type representing the native
/// function's parameter and return types. The parameter and return types must
/// be subtypes of [NativeType].
///
/// If this annotation is used on an external variable, then the type argument
/// [T] must be a compatible native type. For example, an [int] field can be
/// annotated with [Int32].
/// If the type argument to `@Native` is omitted, it defaults to the Dart type
/// of the annotated declaration, which *must* then be a native type too.
/// This will never work for function declarations, but can apply to variables
/// whose type is some of the types of this library, such as [Pointer].
/// For native global variables that cannot be re-assigned, a final variable in
/// Dart or a getter can be used to prevent assignments to the native field.
///
/// Example:
///
/// ```dart template:top
/// @Native<Int64 Function(Int64, Int64)>()
/// external int sum(int a, int b);
///
/// @Native<Int64>()
/// external int aGlobalInt;
///
/// @Native()
/// external final Pointer<Char> aGlobalString;
/// ```
///
/// Calling a `@Native` function, as well as reading or writing to a `@Native`
/// variable, will try to resolve the [symbol] in (in the order):
/// 1. the provided or default [assetId],
/// 2. the native resolver set with `Dart_SetFfiNativeResolver` in
/// `dart_api.h`, and
/// 3. the current process.
///
/// At least one of those three *must* provide a binding for the symbol,
/// otherwise the method call or the variable access fails.
///
/// NOTE: This is an experimental feature and may change in the future.
@Since('2.19')
final class Native<T> {
// Implementation note: VM hardcodes the layout of this class (number and
// order of its fields), so adding/removing/changing fields requires
// updating the VM code (see Function::GetNativeAnnotation()).
/// The native symbol to be resolved, if not using the default.
///
/// If not specified, the default symbol used for native function lookup
/// is the annotated function's name.
///
/// Example:
///
/// ```dart template:top
/// @Native<Int64 Function(Int64, Int64)>()
/// external int sum(int a, int b);
/// ```
///
/// Example 2:
///
/// ```dart template:top
/// @Native<Int64 Function(Int64, Int64)>(symbol: 'sum')
/// external int sum(int a, int b);
/// ```
///
/// The above two examples are equivalent.
///
/// Prefer omitting the [symbol] when possible.
final String? symbol;
/// The ID of the asset in which [symbol] is resolved, if not using the
/// default.
///
/// If no asset name is specified, the default is to use an asset ID
/// specified using an [DefaultAsset] annotation on the current library's
/// `library` declaration, and if there is no [DefaultAsset] annotation on
/// the current library, the library's URI (as a string) is used instead.
///
/// Example (file `package:a/a.dart`):
///
/// ```dart template:top
/// @Native<Int64 Function(Int64, Int64)>()
/// external int sum(int a, int b);
/// ```
///
/// Example 2 (file `package:a/a.dart`):
///
/// ```dart template:none
/// @DefaultAsset('package:a/a.dart')
/// library a;
///
/// import 'dart:ffi';
///
/// @Native<Int64 Function(Int64, Int64)>()
/// external int sum(int a, int b);
/// ```
///
/// Example 3 (file `package:a/a.dart`):
///
/// ```dart template:top
/// @Native<Int64 Function(Int64, Int64)>(assetId: 'package:a/a.dart')
/// external int sum(int a, int b);
/// ```
///
/// The above three examples are all equivalent.
///
/// Prefer using the library URI as an asset name over specifying it.
/// Prefer using an [DefaultAsset] on the `library` declaration
/// over specifying the asset name in a [Native] annotation.
final String? assetId;
/// Whether the function is a leaf function.
///
/// Leaf functions are small, short-running, non-blocking functions which are
/// not allowed to call back into Dart or use any Dart VM APIs. Leaf functions
/// are invoked bypassing some of the heavier parts of the standard
/// Dart-to-Native calling sequence which reduces the invocation overhead,
/// making leaf calls faster than non-leaf calls. However, this implies that a
/// thread executing a leaf function can't cooperate with the Dart runtime. A
/// long running or blocking leaf function will delay any operation which
/// requires synchronization between all threads associated with an isolate
/// group until after the leaf function returns. For example, if one isolate
/// in a group is trying to perform a GC and a second isolate is blocked in a
/// leaf call, then the first isolate will have to pause and wait until this
/// leaf call returns.
///
/// This value has no meaning for native fields.
final bool isLeaf;
const Native({
this.assetId,
this.isLeaf = false,
this.symbol,
});
/// The native address of the implementation of [native].
///
/// When calling this function, the argument for [native] must be an
/// expression denoting a variable or function declaration which is annotated
/// with [Native].
/// For a variable declaration, the type [T] must be the same native type
/// as the type argument to that `@Native` annotation.
/// For a function declaration, the type [T] must be `NativeFunction<F>`
/// where `F` was the type argument to that `@Native` annotation.
///
/// For example, for a native C library exposing a function:
///
/// ```C
/// #include <stdint.h>
/// int64_t sum(int64_t a, int64_t b) { return a + b; }
/// ```
///
/// The following code binds `sum` to a Dart function declaration, and
/// extracts the address of the native `sum` implementation:
///
/// ```dart
/// import 'dart:ffi';
///
/// typedef NativeAdd = Int64 Function(Int64, Int64);
///
/// @Native<NativeAdd>()
/// external int sum(int a, int b);
///
/// void main() {
/// Pointer<NativeFunction<NativeAdd>> addressSum = Native.addressOf(sum);
/// }
/// ```
///
/// Similarly, for a native C library exposing a global variable:
///
/// ```C
/// const char* myString;
/// ```
///
/// The following code binds `myString` to a top-level variable in Dart, and
/// extracts the address of the underlying native field:
///
/// ```dart
/// import 'dart:ffi';
///
/// @Native()
/// external Pointer<Char> myString;
///
/// void main() {
/// // This pointer points to the memory location where the loader has
/// // placed the `myString` global itself. To get the string value, read
/// // the myString field directly.
/// Pointer<Pointer<Char>> addressMyString = Native.addressOf(myString);
/// }
/// ```
@Since('3.3')
external static Pointer<T> addressOf<T extends NativeType>(
@DartRepresentationOf('T') Object native);
}
/// Annotation specifying the default asset ID for the current library.
///
/// The annotation applies only to `library` declarations.
///
/// The compiler and/or runtime provides a binding from _asset ID_ to native
/// library, which depends on the target platform and architecture.
/// The compiler/runtime can resolve identifiers (symbols)
/// against the native library, looking up native function implementations
/// which are then used as the implementation of `external` Dart function
/// declarations.
///
/// If used as annotation on a `library` declaration, all [Native]-annotated
/// external functions in this library will use the specified asset [id]
/// for native function resolution (unless overridden by [Native.assetId]).
///
/// If no [DefaultAsset] annotation is provided, the current library's URI
/// is the default asset ID for [Native]-annotated external functions.
///
/// Example (file `package:a/a.dart`):
///
/// ```dart template:top
/// @Native<Int64 Function(Int64, Int64)>()
/// external int sum(int a, int b);
/// ```
///
/// Example 2 (file `package:a/a.dart`):
///
/// ```dart template:none
/// @DefaultAsset('package:a/a.dart')
/// library a;
///
/// import 'dart:ffi';
///
/// @Native<Int64 Function(Int64, Int64)>()
/// external int sum(int a, int b);
/// ```
///
/// The above two examples are equivalent.
///
/// Prefer using the library URI as asset name when possible.
///
/// NOTE: This is an experimental feature and may change in the future.
@Since('2.19')
final class DefaultAsset {
/// The default asset name for [Native] external functions in this library.
final String id;
const DefaultAsset(
this.id,
);
}