dart-sdk/sdk/lib/ffi/native_type.dart
Daco Harkes ac5e3d38c3 [vm/ffi] Introduce SizedNativeType
Both `sizeOf` and `AllocatorAlloc.call` use the new type as bound.
This prevents runtime errors on trying to call these two static
methods with unsized native types. All tests testing for these runtime
errors have been deleted.

The `NativeTypes` implementing `SizedNativeType` are as follows:
* The native integer types, `Float`, and `Double`.
* `AbiSpecificInteger` and it's subtypes.
* `Struct` and `Union` and their subtypes. The

The `NativeTypes` not implementing `SizedNativeType` are as follows:
* `Void` has no size.
* `Opaque` and subtypes have unknown size.
* `Handle` is considered opaque. Cannot be used as field in compounds.
* `Array` does not carry a size in its type. Can be used as fields in
  compounds with an annotation specifying the size.
* `NativeFunction` is considered opaque. Would have variable size.
* `VarArgs` is only a marker in function signatures.

`Struct`s and `Union`s can have only `SizedNativeType`s and `Array`s
as fields. Documentation for these is in flux in another CL, so we
should update it there.

This CL also replaces a bunch of `extends NativeType` with
`implements` clauses and made `NativeType` itself `abstract`.

TEST=Dart SDK build
TEST=ffi test suite

Bug: https://github.com/dart-lang/sdk/issues/54542
CoreLibraryReviewExempt: VM and dart2wasm feature only.
Change-Id: Ib4f6b58f7204bd063ace20133162798d8c9483e8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/345221
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
2024-01-12 10:13:39 +00:00

219 lines
7 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.
part of dart.ffi;
/// [NativeType]'s subtypes represent a native type in C.
///
/// Not all [NativeType]'s subtypes are constructible in the Dart code. The
/// non-constructable subtypes serve purely as markers in type signatures.
abstract final class NativeType {}
/// A [NativeType] with a known size.
///
/// Sized native types can be used in [sizeOf] and [AllocatorAlloc.call].
@Since('3.4')
abstract final class SizedNativeType implements NativeType {}
/// [Opaque]'s subtypes represent opaque types in C.
///
/// [Opaque]'s subtypes are not constructible in the Dart code and serve purely
/// as markers in type signatures.
@Since('2.12')
abstract base class Opaque implements NativeType {}
/// [_NativeInteger]'s subtypes represent a native integer in C.
///
/// [_NativeInteger]'s subtypes are not constructible in the Dart code and serve
/// purely as markers in type signatures.
abstract final class _NativeInteger implements SizedNativeType {}
/// [_NativeDouble]'s subtypes represent a native float or double in C.
///
/// [_NativeDouble]'s subtypes are not constructible in the Dart code and serve
/// purely as markers in type signatures.
abstract final class _NativeDouble implements SizedNativeType {}
/// Represents a native signed 8 bit integer in C.
///
/// [Int8] is not constructible in the Dart code and serves purely as marker in
/// type signatures.
final class Int8 implements _NativeInteger {
const Int8();
}
/// Represents a native signed 16 bit integer in C.
///
/// [Int16] is not constructible in the Dart code and serves purely as marker in
/// type signatures.
final class Int16 implements _NativeInteger {
const Int16();
}
/// Represents a native signed 32 bit integer in C.
///
/// [Int32] is not constructible in the Dart code and serves purely as marker in
/// type signatures.
final class Int32 implements _NativeInteger {
const Int32();
}
/// Represents a native signed 64 bit integer in C.
///
/// [Int64] is not constructible in the Dart code and serves purely as marker in
/// type signatures.
final class Int64 implements _NativeInteger {
const Int64();
}
/// Represents a native unsigned 8 bit integer in C.
///
/// [Uint8] is not constructible in the Dart code and serves purely as marker in
/// type signatures.
final class Uint8 implements _NativeInteger {
const Uint8();
}
/// Represents a native unsigned 16 bit integer in C.
///
/// [Uint16] is not constructible in the Dart code and serves purely as marker
/// in type signatures.
final class Uint16 implements _NativeInteger {
const Uint16();
}
/// Represents a native unsigned 32 bit integer in C.
///
/// [Uint32] is not constructible in the Dart code and serves purely as marker
/// in type signatures.
final class Uint32 implements _NativeInteger {
const Uint32();
}
/// Represents a native unsigned 64 bit integer in C.
///
/// [Uint64] is not constructible in the Dart code and serves purely as marker
/// in type signatures.
final class Uint64 implements _NativeInteger {
const Uint64();
}
/// Represents a native 32 bit float in C.
///
/// [Float] is not constructible in the Dart code and serves purely as marker
/// in type signatures.
final class Float implements _NativeDouble {
const Float();
}
/// Represents a native 64 bit double in C.
///
/// [Double] is not constructible in the Dart code and serves purely as marker
/// in type signatures.
final class Double implements _NativeDouble {
const Double();
}
/// Represents a native bool in C.
///
/// [Bool] is not constructible in the Dart code and serves purely as marker
/// in type signatures.
@Since('2.15')
final class Bool implements SizedNativeType {
const Bool();
}
/// Represents a void type in C.
///
/// [Void] is not constructible in the Dart code and serves purely as marker in
/// type signatures.
abstract final class Void implements NativeType {}
/// Represents `Dart_Handle` from `dart_api.h` in C.
///
/// [Handle] is not constructible in the Dart code and serves purely as marker
/// in type signatures.
///
/// If [Handle] is part of the native signature of a [Native] external function
/// or [NativeFunctionPointer.asFunction], an API handle scope is created for
/// the duration of the FFI call. For more information on API scopes, refer to
/// the documentation on `Dart_EnterScope` in `dart_api.h`.
@Since('2.9')
abstract final class Handle implements NativeType {}
/// Represents a function type in C.
///
/// The return type and argument types in [T] must be a subtype of [NativeType].
///
/// [NativeFunction] is not constructible in the Dart code and serves purely as
/// marker in type signatures.
abstract final class NativeFunction<T extends Function> implements NativeType {}
/// The types of variadic arguments passed in C.
///
/// The signatures in [NativeFunction] need to specify the exact types of each
/// actual argument used in FFI calls.
///
/// For example take calling `printf` in C.
///
/// ```c
/// int printf(const char *format, ...);
///
/// void call_printf() {
/// int a = 4;
/// double b = 5.5;
/// const char* format = "...";
/// printf(format, a, b);
/// }
/// ```
///
/// To call `printf` directly from Dart with those two argument types, define
/// the native type as follows:
///
/// ```dart
/// /// `int printf(const char *format, ...)` with `int` and `double` as
/// /// varargs.
/// typedef NativePrintfIntDouble =
/// Int Function(Pointer<Char>, VarArgs<(Int, Double)>);
/// ```
///
/// Note the record type inside the `VarArgs` type argument.
///
/// If only a single variadic argument is passed, the record type must
/// contain a trailing comma:
///
/// ```dart continued
/// /// `int printf(const char *format, ...)` with only `int` as varargs.
/// typedef NativePrintfInt = Int Function(Pointer<Char>, VarArgs<(Int,)>);
/// ```
///
/// When a variadic function is called with different variadic argument types,
/// multiple bindings need to be created.
/// To avoid doing multiple [DynamicLibrary.lookup]s for the same symbol, the
/// pointer to the symbol can be cast:
///
/// ```dart continued
/// final dylib = DynamicLibrary.executable();
/// final printfPointer = dylib.lookup('printf');
/// final void Function(Pointer<Char>, int, double) printfIntDouble =
/// printfPointer.cast<NativeFunction<NativePrintfIntDouble>>().asFunction();
/// final void Function(Pointer<Char>, int) printfInt =
/// printfPointer.cast<NativeFunction<NativePrintfInt>>().asFunction();
/// ```
///
/// If no variadic argument is passed, the `VarArgs` must be passed with an
/// empty record type:
///
/// ```dart
/// /// `int printf(const char *format, ...)` with no varargs.
/// typedef NativePrintfNoVarArgs = Int Function(Pointer<Char>, VarArgs<()>);
/// ```
///
/// [VarArgs] must be the last parameter.
///
/// [VarArgs] is not constructible in the Dart code and serves purely as marker
/// in type signatures.
@Since('3.0')
abstract final class VarArgs<T extends Record> implements NativeType {}