-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
struct.dart
187 lines (175 loc) · 6.4 KB
/
struct.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// 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;
/// A memory range, represented by its starting address.
///
/// Shared supertype of the FFI compound [Struct], [Union], and [Array] types.
///
/// This class is not abstract because instances can be created as an anonymous
/// representation of a memory area, with no structure on top. (In particular,
/// during the transformation of `.address` in FFI leaf calls.)
@pragma("wasm:entry-point")
final class _Compound implements NativeType {
/// The underlying [TypedData] or [Pointer] that a subtype uses.
@pragma("vm:entry-point")
final Object _typedDataBase;
/// Offset in bytes into [_typedDataBase].
@pragma("vm:entry-point")
final int _offsetInBytes;
external _Compound._();
_Compound._fromTypedDataBase(
this._typedDataBase,
this._offsetInBytes,
);
/// Constructs a view on [typedData].
///
/// The length in bytes of [typedData] must at least be [sizeInBytes].
_Compound._fromTypedData(
TypedData typedData,
int offset,
int sizeInBytes,
) : _typedDataBase = typedData,
_offsetInBytes = typedData.elementSizeInBytes * offset {
if (typedData.lengthInBytes <
typedData.elementSizeInBytes * offset + sizeInBytes) {
throw RangeError.range(
typedData.lengthInBytes,
sizeInBytes + typedData.elementSizeInBytes * offset,
null,
'typedData.lengthInBytes',
'The typed list is not large enough',
);
}
}
}
/// The supertype of all FFI struct types.
///
/// FFI struct types should extend this class and declare fields corresponding
/// to the underlying native structure.
///
/// Field declarations in a [Struct] subclass declaration are automatically
/// given a setter and getter implementation which accesses the native struct's
/// field in memory.
///
/// All field declarations in a [Struct] subclass declaration must either have
/// type [int] or [double] and be annotated with a [NativeType] representing the
/// native type, or must be of type [Pointer], [Array] or a subtype of [Struct]
/// or [Union]. For example:
///
/// ```c
/// typedef struct {
/// int a;
/// float b;
/// void* c;
/// } my_struct;
/// ```
///
/// ```dart
/// final class MyStruct extends Struct {
/// @Int32()
/// external int a;
///
/// @Float()
/// external double b;
///
/// external Pointer<Void> c;
/// }
/// ```
///
/// The field declarations of a [Struct] subclass *must* be marked `external`. A
/// struct subclass points directly into a location of native memory ([Pointer])
/// or Dart memory ([TypedData]), and the external field's getter and setter
/// implementations directly read and write bytes at appropriate offsets from
/// that location. This does not allow for non-native fields to also exist.
///
/// An instance of a struct subclass cannot be created with a generative
/// constructor. Instead, an instance can be created by [StructPointer.ref],
/// [Struct.create], FFI call return values, FFI callback arguments,
/// [StructArray], and accessing [Struct] fields. To create an instance backed
/// by native memory, use [StructPointer.ref]. To create an instance backed by
/// Dart memory, use [Struct.create].
@Since('2.12')
abstract base class Struct extends _Compound implements SizedNativeType {
/// Construct a reference to the [nullptr].
///
/// Use [StructPointer]'s `.ref` to gain references to native memory backed
/// structs.
Struct() : super._();
/// Creates a struct view of bytes in [typedData].
///
/// The created instance of the struct subclass will then be backed by the
/// bytes at [TypedData.offsetInBytes] plus [offset] times
/// [TypedData.elementSizeInBytes]. That is, the getters and setters of the
/// external instance variables declared by the subclass, will read an write
/// their values from the bytes of the [TypedData.buffer] of [typedData],
/// starting at [TypedData.offsetInBytes] plus [offset] times
/// [TypedData.elementSizeInBytes]. The [TypedData.lengthInBytes] of
/// [typedData] *must* be sufficient to contain the [sizeOf] of the struct
/// subclass. _It doesn't matter whether the [typedData] is, for example, a
/// [Uint8List], a [Float64List], or any other [TypedData], it's only treated
/// as a view into a [ByteBuffer], through its [TypedData.buffer],
/// [TypedData.offsetInBytes] and [TypedData.lengthInBytes]._
///
/// If [typedData] is omitted, a fresh [ByteBuffer], with precisely enough
/// bytes for the [sizeOf] of the created struct, is allocated on the Dart
/// heap, and used as memory to store the struct fields.
///
/// If [offset] is provided, the indexing into [typedData] is offset by
/// [offset] times [TypedData.elementSizeInBytes].
///
/// Example:
///
/// ```dart import:typed_data
/// final class Point extends Struct {
/// @Double()
/// external double x;
///
/// @Double()
/// external double y;
///
/// /// Creates Dart managed memory to hold a `Point` and returns the
/// /// `Point` view on it.
/// factory Point(double x, double y) {
/// return Struct.create()
/// ..x = x
/// ..y = y;
/// }
///
/// /// Creates a [Point] view on [typedData].
/// factory Point.fromTypedData(TypedData typedData) {
/// return Struct.create(typedData);
/// }
/// }
/// ```
///
/// To create a struct object from a [Pointer], use [StructPointer.ref].
@Since('3.4')
external static T create<T extends Struct>([TypedData typedData, int offset]);
/// Creates a view on a [TypedData] or [Pointer].
///
/// Used in [StructPointer.ref], FFI calls, and FFI callbacks.
Struct._fromTypedDataBase(
super._typedDataBase,
super._offsetInBytes,
) : super._fromTypedDataBase();
/// Creates a view on [typedData].
///
/// The length in bytes of [typedData] must at least be [sizeInBytes].
///
/// Used in the `external` public constructor of [Struct].
Struct._fromTypedData(
super.typedData,
super.offset,
super.sizeInBytes,
) : super._fromTypedData();
}
/// Annotation to specify on `Struct` subtypes to indicate that its members
/// need to be packed.
///
/// Valid values for [memberAlignment] are 1, 2, 4, 8, and 16.
@Since('2.13')
final class Packed {
final int memberAlignment;
const Packed(this.memberAlignment);
}