[vm/ffi] Migrate tests/samples/benchmarks to extension methods

I used the regex replaces documented on the `load` and `store` deprecated methods.
I manually replaced some `.val` to `.ref` when a regex could not detect whether something was a primitive value or a struct.

Issue: https://github.com/dart-lang/sdk/issues/37773

Change-Id: I3534b6dd00d9ac45fa1a11fe75c80fb3cccc07dc
Cq-Include-Trybots: luci.dart.try:vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,app-kernel-linux-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-dartkb-linux-debug-simarm64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-dartkb-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-dartkb-linux-release-x64-abi-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-mac-debug-simdbc64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-reload-mac-release-simdbc64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-precomp-mac-release-simarm_x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/118993
Reviewed-by: Samir Jindel <sjindel@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
Daco Harkes 2019-10-08 16:49:41 +00:00 committed by commit-bot@chromium.org
parent 597cd06aec
commit ee0b1df4a6
20 changed files with 653 additions and 682 deletions

View file

@ -29,7 +29,7 @@ Uint8List toUint8List(Bytes bytes, int length) {
final result = Uint8List(length); final result = Uint8List(length);
final uint8bytes = bytes.asUint8Pointer(); final uint8bytes = bytes.asUint8Pointer();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
result[i] = uint8bytes.elementAt(i).load<int>(); result[i] = uint8bytes[i];
} }
return result; return result;
} }
@ -38,7 +38,7 @@ void copyFromUint8ListToTarget(Uint8List source, Data target) {
final int length = source.length; final int length = source.length;
final uint8target = target.asUint8Pointer(); final uint8target = target.asUint8Pointer();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
uint8target.offsetBy(i).store(source[i]); uint8target[i] = source[i];
} }
} }
@ -51,7 +51,7 @@ String hash(Pointer<Data> data, int length, Pointer<EVP_MD> hashAlgorithm) {
Pointer<Uint8>.allocate(count: resultSize).cast(); Pointer<Uint8>.allocate(count: resultSize).cast();
EVP_DigestFinal(context, result, nullptr.cast()); EVP_DigestFinal(context, result, nullptr.cast());
EVP_MD_CTX_free(context); EVP_MD_CTX_free(context);
final String hash = base64Encode(toUint8List(result.load(), resultSize)); final String hash = base64Encode(toUint8List(result.ref, resultSize));
result.free(); result.free();
return hash; return hash;
} }
@ -86,7 +86,7 @@ class DigestCMemory extends BenchmarkBase {
void setup() { void setup() {
data = Pointer<Uint8>.allocate(count: L).cast(); data = Pointer<Uint8>.allocate(count: L).cast();
copyFromUint8ListToTarget(inventData(L), data.load()); copyFromUint8ListToTarget(inventData(L), data.ref);
hash(data, L, hashAlgorithm); hash(data, L, hashAlgorithm);
} }
@ -113,7 +113,7 @@ class DigestDartMemory extends BenchmarkBase {
void setup() { void setup() {
data = inventData(L); data = inventData(L);
final Pointer<Data> dataInC = Pointer<Uint8>.allocate(count: L).cast(); final Pointer<Data> dataInC = Pointer<Uint8>.allocate(count: L).cast();
copyFromUint8ListToTarget(data, dataInC.load()); copyFromUint8ListToTarget(data, dataInC.ref);
hash(dataInC, L, hashAlgorithm); hash(dataInC, L, hashAlgorithm);
dataInC.free(); dataInC.free();
} }
@ -122,7 +122,7 @@ class DigestDartMemory extends BenchmarkBase {
void run() { void run() {
final Pointer<Data> dataInC = Pointer<Uint8>.allocate(count: L).cast(); final Pointer<Data> dataInC = Pointer<Uint8>.allocate(count: L).cast();
copyFromUint8ListToTarget(data, dataInC.load()); copyFromUint8ListToTarget(data, dataInC.ref);
final String result = hash(dataInC, L, hashAlgorithm); final String result = hash(dataInC, L, hashAlgorithm);
dataInC.free(); dataInC.free();
if (result != expectedHash) { if (result != expectedHash) {

View file

@ -12,14 +12,14 @@ class EVP_MD_CTX extends Struct<EVP_MD_CTX> {}
/// Type for `void*` used to represent opaque data. /// Type for `void*` used to represent opaque data.
class Data extends Struct<Data> { class Data extends Struct<Data> {
static Data fromUint8Pointer(Pointer<Uint8> p) => p.cast<Data>().load(); static Data fromUint8Pointer(Pointer<Uint8> p) => p.cast<Data>().ref;
Pointer<Uint8> asUint8Pointer() => this.addressOf.cast(); Pointer<Uint8> asUint8Pointer() => this.addressOf.cast();
} }
/// Type for `uint8_t*` used to represent byte data. /// Type for `uint8_t*` used to represent byte data.
class Bytes extends Struct<Bytes> { class Bytes extends Struct<Bytes> {
static Data fromUint8Pointer(Pointer<Uint8> p) => p.cast<Data>().load(); static Data fromUint8Pointer(Pointer<Uint8> p) => p.cast<Data>().ref;
Pointer<Uint8> asUint8Pointer() => this.addressOf.cast(); Pointer<Uint8> asUint8Pointer() => this.addressOf.cast();
} }

View file

@ -19,74 +19,74 @@ import 'package:benchmark_harness/benchmark_harness.dart';
void doStoreInt8(Pointer<Int8> pointer, int length) { void doStoreInt8(Pointer<Int8> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1); pointer[i] = 1;
} }
} }
void doStoreUint8(Pointer<Uint8> pointer, int length) { void doStoreUint8(Pointer<Uint8> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1); pointer[i] = 1;
} }
} }
void doStoreInt16(Pointer<Int16> pointer, int length) { void doStoreInt16(Pointer<Int16> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1); pointer[i] = 1;
} }
} }
void doStoreUint16(Pointer<Uint16> pointer, int length) { void doStoreUint16(Pointer<Uint16> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1); pointer[i] = 1;
} }
} }
void doStoreInt32(Pointer<Int32> pointer, int length) { void doStoreInt32(Pointer<Int32> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1); pointer[i] = 1;
} }
} }
void doStoreUint32(Pointer<Uint32> pointer, int length) { void doStoreUint32(Pointer<Uint32> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1); pointer[i] = 1;
} }
} }
void doStoreInt64(Pointer<Int64> pointer, int length) { void doStoreInt64(Pointer<Int64> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1); pointer[i] = 1;
} }
} }
void doStoreUint64(Pointer<Uint64> pointer, int length) { void doStoreUint64(Pointer<Uint64> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1); pointer[i] = 1;
} }
} }
void doStoreFloat(Pointer<Float> pointer, int length) { void doStoreFloat(Pointer<Float> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1.0); pointer[i] = 1.0;
} }
} }
void doStoreDouble(Pointer<Double> pointer, int length) { void doStoreDouble(Pointer<Double> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1.0); pointer[i] = 1.0;
} }
} }
void doStorePointer( void doStorePointer(
Pointer<Pointer<Int8>> pointer, int length, Pointer<Int8> data) { Pointer<Pointer<Int8>> pointer, int length, Pointer<Int8> data) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(data); pointer[i] = data;
} }
} }
void doStoreInt64Mint(Pointer<Int64> pointer, int length) { void doStoreInt64Mint(Pointer<Int64> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(0x7FFFFFFFFFFFFFFF); pointer[i] = 0x7FFFFFFFFFFFFFFF;
} }
} }
@ -97,7 +97,7 @@ void doStoreInt64Mint(Pointer<Int64> pointer, int length) {
int doLoadInt8(Pointer<Int8> pointer, int length) { int doLoadInt8(Pointer<Int8> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>(); x += pointer[i];
} }
return x; return x;
} }
@ -105,7 +105,7 @@ int doLoadInt8(Pointer<Int8> pointer, int length) {
int doLoadUint8(Pointer<Uint8> pointer, int length) { int doLoadUint8(Pointer<Uint8> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>(); x += pointer[i];
} }
return x; return x;
} }
@ -113,7 +113,7 @@ int doLoadUint8(Pointer<Uint8> pointer, int length) {
int doLoadInt16(Pointer<Int16> pointer, int length) { int doLoadInt16(Pointer<Int16> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>(); x += pointer[i];
} }
return x; return x;
} }
@ -121,7 +121,7 @@ int doLoadInt16(Pointer<Int16> pointer, int length) {
int doLoadUint16(Pointer<Uint16> pointer, int length) { int doLoadUint16(Pointer<Uint16> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>(); x += pointer[i];
} }
return x; return x;
} }
@ -129,7 +129,7 @@ int doLoadUint16(Pointer<Uint16> pointer, int length) {
int doLoadInt32(Pointer<Int32> pointer, int length) { int doLoadInt32(Pointer<Int32> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>(); x += pointer[i];
} }
return x; return x;
} }
@ -137,7 +137,7 @@ int doLoadInt32(Pointer<Int32> pointer, int length) {
int doLoadUint32(Pointer<Uint32> pointer, int length) { int doLoadUint32(Pointer<Uint32> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>(); x += pointer[i];
} }
return x; return x;
} }
@ -145,7 +145,7 @@ int doLoadUint32(Pointer<Uint32> pointer, int length) {
int doLoadInt64(Pointer<Int64> pointer, int length) { int doLoadInt64(Pointer<Int64> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>(); x += pointer[i];
} }
return x; return x;
} }
@ -153,7 +153,7 @@ int doLoadInt64(Pointer<Int64> pointer, int length) {
int doLoadUint64(Pointer<Uint64> pointer, int length) { int doLoadUint64(Pointer<Uint64> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>(); x += pointer[i];
} }
return x; return x;
} }
@ -161,7 +161,7 @@ int doLoadUint64(Pointer<Uint64> pointer, int length) {
double doLoadFloat(Pointer<Float> pointer, int length) { double doLoadFloat(Pointer<Float> pointer, int length) {
double x = 0; double x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<double>(); x += pointer[i];
} }
return x; return x;
} }
@ -169,7 +169,7 @@ double doLoadFloat(Pointer<Float> pointer, int length) {
double doLoadDouble(Pointer<Double> pointer, int length) { double doLoadDouble(Pointer<Double> pointer, int length) {
double x = 0; double x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<double>(); x += pointer[i];
} }
return x; return x;
} }
@ -179,7 +179,7 @@ int doLoadPointer(Pointer<Pointer<Int8>> pointer, int length) {
Pointer<Int8> x; Pointer<Int8> x;
int address_xor = 0; int address_xor = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x = pointer.elementAt(i).load(); x = pointer[i];
address_xor ^= x.address; address_xor ^= x.address;
} }
return address_xor; return address_xor;
@ -188,7 +188,7 @@ int doLoadPointer(Pointer<Pointer<Int8>> pointer, int length) {
int doLoadInt64Mint(Pointer<Int64> pointer, int length) { int doLoadInt64Mint(Pointer<Int64> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>(); x += pointer[i];
} }
return x; return x;
} }

View file

@ -17,7 +17,7 @@ import 'package:benchmark_harness/benchmark_harness.dart';
void doStoreInt32(Pointer<VeryLargeStruct> pointer, int length) { void doStoreInt32(Pointer<VeryLargeStruct> pointer, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pointer.elementAt(i).load<VeryLargeStruct>().c = 1; pointer[i].c = 1;
} }
} }
@ -28,7 +28,7 @@ void doStoreInt32(Pointer<VeryLargeStruct> pointer, int length) {
int doLoadInt32(Pointer<VeryLargeStruct> pointer, int length) { int doLoadInt32(Pointer<VeryLargeStruct> pointer, int length) {
int x = 0; int x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<VeryLargeStruct>().c; x += pointer[i].c;
} }
return x; return x;
} }

View file

@ -79,8 +79,8 @@ However, before we can write to C memory from dart, we need to `allocate` some m
```dart ```dart
Pointer<Uint8> p = allocate(); // Infers type argument allocate<Uint8>(), and allocates 1 byte. Pointer<Uint8> p = allocate(); // Infers type argument allocate<Uint8>(), and allocates 1 byte.
p.store(123); // Stores a Dart int into this C int8. p.value = 123; // Stores a Dart int into this C int8.
int v = p.load(); // Infers type argument p.load<int>(), and loads a value from C memory. int v = p.value; // Loads a value from C memory.
``` ```
Note that you can only load a Dart `int` from a C `Uint8`. Note that you can only load a Dart `int` from a C `Uint8`.
@ -92,10 +92,10 @@ We can do this by using `elementAt`.
```dart ```dart
CString string = allocate(count: 4).cast(); // Allocates 4 bytes and casts it to a string. CString string = allocate(count: 4).cast(); // Allocates 4 bytes and casts it to a string.
string.store(73); // Stores 'F' at index 0. string.value = 73; // Stores 'F' at index 0.
string.elementAt(1).store(73); // Stores 'F' at index 1. string[1] = 73; // Stores 'F' at index 1.
string.elementAt(2).store(70); // Stores 'I' at index 2. string[2] = 70; // Stores 'I' at index 2.
string.elementAt(3).store(0); // Null terminates the string. string[3] = 0; // Null terminates the string.
``` ```
We wrap the above logic of allocating strings in the constructor `CString.allocate`. We wrap the above logic of allocating strings in the constructor `CString.allocate`.
@ -113,7 +113,7 @@ With `dart:ffi` we are responsible for freeing C memory that we allocate.
So after calling `sqlite3_prepare_v2` we read out the statement pointer, and free the statement pointer pointer and `CString` which held the query string. So after calling `sqlite3_prepare_v2` we read out the statement pointer, and free the statement pointer pointer and `CString` which held the query string.
``` ```
StatementPointer statement = statementOut.load(); StatementPointer statement = statementOut.value;
statementOut.free(); statementOut.free();
queryC.free(); queryC.free();
``` ```

View file

@ -30,7 +30,7 @@ class Database {
final pathC = Utf8.allocate(path); final pathC = Utf8.allocate(path);
final int resultCode = final int resultCode =
bindings.sqlite3_open_v2(pathC, dbOut, flags, Pointer.fromAddress(0)); bindings.sqlite3_open_v2(pathC, dbOut, flags, Pointer.fromAddress(0));
_database = dbOut.load(); _database = dbOut.value;
dbOut.free(); dbOut.free();
pathC.free(); pathC.free();
@ -66,7 +66,7 @@ class Database {
Pointer<Utf8> queryC = Utf8.allocate(query); Pointer<Utf8> queryC = Utf8.allocate(query);
int resultCode = bindings.sqlite3_prepare_v2( int resultCode = bindings.sqlite3_prepare_v2(
_database, queryC, -1, statementOut, Pointer.fromAddress(0)); _database, queryC, -1, statementOut, Pointer.fromAddress(0));
Pointer<Statement> statement = statementOut.load(); Pointer<Statement> statement = statementOut.value;
statementOut.free(); statementOut.free();
queryC.free(); queryC.free();
@ -85,7 +85,7 @@ class Database {
Pointer<Utf8> queryC = Utf8.allocate(query); Pointer<Utf8> queryC = Utf8.allocate(query);
int resultCode = bindings.sqlite3_prepare_v2( int resultCode = bindings.sqlite3_prepare_v2(
_database, queryC, -1, statementOut, Pointer.fromAddress(0)); _database, queryC, -1, statementOut, Pointer.fromAddress(0));
Pointer<Statement> statement = statementOut.load(); Pointer<Statement> statement = statementOut.value;
statementOut.free(); statementOut.free();
queryC.free(); queryC.free();
@ -98,7 +98,7 @@ class Database {
int columnCount = bindings.sqlite3_column_count(statement); int columnCount = bindings.sqlite3_column_count(statement);
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
String columnName = String columnName =
bindings.sqlite3_column_name(statement, i).load<Utf8>().toString(); bindings.sqlite3_column_name(statement, i).ref.toString();
columnIndices[columnName] = i; columnIndices[columnName] = i;
} }
@ -106,13 +106,12 @@ class Database {
} }
SQLiteException _loadError([int errorCode]) { SQLiteException _loadError([int errorCode]) {
String errorMessage = String errorMessage = bindings.sqlite3_errmsg(_database).ref.toString();
bindings.sqlite3_errmsg(_database).load<Utf8>().toString();
if (errorCode == null) { if (errorCode == null) {
return SQLiteException(errorMessage); return SQLiteException(errorMessage);
} }
String errorCodeExplanation = String errorCodeExplanation =
bindings.sqlite3_errstr(errorCode).load<Utf8>().toString(); bindings.sqlite3_errstr(errorCode).ref.toString();
return SQLiteException( return SQLiteException(
"$errorMessage (Code $errorCode: $errorCodeExplanation)"); "$errorMessage (Code $errorCode: $errorCodeExplanation)");
} }
@ -214,7 +213,7 @@ class Row {
} else { } else {
dynamicType = _typeFromText(bindings dynamicType = _typeFromText(bindings
.sqlite3_column_decltype(_statement, columnIndex) .sqlite3_column_decltype(_statement, columnIndex)
.load<Utf8>() .ref
.toString()); .toString());
} }
@ -251,10 +250,7 @@ class Row {
/// Reads column [columnIndex] and converts to [Type.Text] if not text. /// Reads column [columnIndex] and converts to [Type.Text] if not text.
String readColumnByIndexAsText(int columnIndex) { String readColumnByIndexAsText(int columnIndex) {
_checkIsCurrentRow(); _checkIsCurrentRow();
return bindings return bindings.sqlite3_column_text(_statement, columnIndex).ref.toString();
.sqlite3_column_text(_statement, columnIndex)
.load<Utf8>()
.toString();
} }
void _checkIsCurrentRow() { void _checkIsCurrentRow() {

View file

@ -29,9 +29,9 @@ class Utf8 extends Struct<Utf8> {
List<int> units = Utf8Encoder().convert(dartStr); List<int> units = Utf8Encoder().convert(dartStr);
Pointer<Utf8> str = Pointer.allocate(count: units.length + 1); Pointer<Utf8> str = Pointer.allocate(count: units.length + 1);
for (int i = 0; i < units.length; ++i) { for (int i = 0; i < units.length; ++i) {
str.elementAt(i).load<Utf8>().char = units[i]; str[i].char = units[i];
} }
str.elementAt(units.length).load<Utf8>().char = 0; str[units.length].char = 0;
return str.cast(); return str.cast();
} }
@ -40,9 +40,9 @@ class Utf8 extends Struct<Utf8> {
final str = addressOf; final str = addressOf;
if (str == nullptr) return null; if (str == nullptr) return null;
int len = 0; int len = 0;
while (str.elementAt(++len).load<Utf8>().char != 0); while (str[++len].char != 0);
List<int> units = List(len); List<int> units = List(len);
for (int i = 0; i < len; ++i) units[i] = str.elementAt(i).load<Utf8>().char; for (int i = 0; i < len; ++i) units[i] = str[i].char;
return Utf8Decoder().convert(units); return Utf8Decoder().convert(units);
} }
} }

View file

@ -4,6 +4,8 @@
// VMOptions=--optimization-counter-threshold=5 // VMOptions=--optimization-counter-threshold=5
import 'dart:ffi';
import "package:test/test.dart"; import "package:test/test.dart";
import '../lib/sqlite.dart'; import '../lib/sqlite.dart';
@ -11,6 +13,8 @@ import '../lib/src/ffi/utf8.dart';
void main() { void main() {
test("sqlite integration test", () { test("sqlite integration test", () {
// TODO(dacoharkes): Put the database relative to this file,
// instead of where the script was invoked from.
Database d = Database("test.db"); Database d = Database("test.db");
d.execute("drop table if exists Cookies;"); d.execute("drop table if exists Cookies;");
d.execute(""" d.execute("""
@ -165,7 +169,7 @@ void main() {
test("Utf8 unit test", () { test("Utf8 unit test", () {
final String test = 'Hasta Mañana'; final String test = 'Hasta Mañana';
final medium = Utf8.allocate(test); final medium = Utf8.allocate(test);
expect(test, medium.load<Utf8>().toString()); expect(test, medium.ref.toString());
medium.free(); medium.free();
}); });
} }

View file

@ -37,22 +37,22 @@ void main() {
void testNonAlias() { void testNonAlias() {
final source = Pointer<Int64>.allocate(); final source = Pointer<Int64>.allocate();
source.store(42); source.value = 42;
final int a = source.load(); final int a = source.value;
source.store(1984); source.value = 1984;
// alias.load() should be re-executed, as we wrote to alias. // alias.value should be re-executed, as we wrote to alias.
Expect.notEquals(a, source.load<int>()); Expect.notEquals(a, source.value);
source.free(); source.free();
} }
void testAliasCast() { void testAliasCast() {
final source = Pointer<Int64>.allocate(); final source = Pointer<Int64>.allocate();
final alias = source.cast<Int8>().cast<Int64>(); final alias = source.cast<Int8>().cast<Int64>();
source.store(42); source.value = 42;
final int a = source.load(); final int a = source.value;
alias.store(1984); alias.value = 1984;
// source.load() should be re-executed, we wrote alias which aliases source. // source.value should be re-executed, we wrote alias which aliases source.
Expect.notEquals(a, source.load<int>()); Expect.notEquals(a, source.value);
source.free(); source.free();
} }
@ -60,22 +60,22 @@ void testAliasCast2() {
final source = Pointer<Int64>.allocate(); final source = Pointer<Int64>.allocate();
final alias = source.cast<Int16>().cast<Int64>(); final alias = source.cast<Int16>().cast<Int64>();
final alias2 = source.cast<Int8>().cast<Int64>(); final alias2 = source.cast<Int8>().cast<Int64>();
alias.store(42); alias.value = 42;
final int a = alias.load(); final int a = alias.value;
alias2.store(1984); alias2.value = 1984;
// alias.load() should be re-executed, we wrote alias2 which aliases alias. // alias.value should be re-executed, we wrote alias2 which aliases alias.
Expect.notEquals(a, alias.load<int>()); Expect.notEquals(a, alias.value);
source.free(); source.free();
} }
void testAliasOffsetBy() { void testAliasOffsetBy() {
final source = Pointer<Int64>.allocate(count: 2); final source = Pointer<Int64>.allocate(count: 2);
final alias = source.offsetBy(8).offsetBy(-8); final alias = source.offsetBy(8).offsetBy(-8);
source.store(42); source.value = 42;
final int a = source.load(); final int a = source.value;
alias.store(1984); alias.value = 1984;
// source.load() should be re-executed, we wrote alias which aliases source. // source.value should be re-executed, we wrote alias which aliases source.
Expect.notEquals(a, source.load<int>()); Expect.notEquals(a, source.value);
source.free(); source.free();
} }
@ -83,22 +83,22 @@ void testAliasOffsetBy2() {
final source = Pointer<Int64>.allocate(count: 3); final source = Pointer<Int64>.allocate(count: 3);
final alias = source.offsetBy(16).offsetBy(-16); final alias = source.offsetBy(16).offsetBy(-16);
final alias2 = source.offsetBy(8).offsetBy(-8); final alias2 = source.offsetBy(8).offsetBy(-8);
alias.store(42); alias.value = 42;
final int a = alias.load(); final int a = alias.value;
alias2.store(1984); alias2.value = 1984;
// alias.load() should be re-executed, we wrote alias2 which aliases alias. // alias.value should be re-executed, we wrote alias2 which aliases alias.
Expect.notEquals(a, alias.load<int>()); Expect.notEquals(a, alias.value);
source.free(); source.free();
} }
void testAliasElementAt() { void testAliasElementAt() {
final source = Pointer<Int64>.allocate(count: 2); final source = Pointer<Int64>.allocate(count: 2);
final alias = source.elementAt(1).elementAt(-1); final alias = source.elementAt(1).elementAt(-1);
source.store(42); source.value = 42;
final int a = source.load(); final int a = source.value;
alias.store(1984); alias.value = 1984;
// source.load() should be re-executed, we wrote alias which aliases source. // source.value should be re-executed, we wrote alias which aliases source.
Expect.notEquals(a, source.load<int>()); Expect.notEquals(a, source.value);
source.free(); source.free();
} }
@ -106,22 +106,22 @@ void testAliasElementAt2() {
final source = Pointer<Int64>.allocate(count: 3); final source = Pointer<Int64>.allocate(count: 3);
final alias = source.elementAt(2).elementAt(-2); final alias = source.elementAt(2).elementAt(-2);
final alias2 = source.elementAt(1).elementAt(-1); final alias2 = source.elementAt(1).elementAt(-1);
alias.store(42); alias.value = 42;
final int a = alias.load(); final int a = alias.value;
alias2.store(1984); alias2.value = 1984;
// alias.load() should be re-executed, we wrote alias2 which aliases alias. // alias.value should be re-executed, we wrote alias2 which aliases alias.
Expect.notEquals(a, alias.load<int>()); Expect.notEquals(a, alias.value);
source.free(); source.free();
} }
void testAliasFromAddress() { void testAliasFromAddress() {
final source = Pointer<Int64>.allocate(); final source = Pointer<Int64>.allocate();
final alias = Pointer<Int64>.fromAddress(source.address); final alias = Pointer<Int64>.fromAddress(source.address);
source.store(42); source.value = 42;
final int a = source.load(); final int a = source.value;
alias.store(1984); alias.value = 1984;
// source.load() should be re-executed, we wrote alias which aliases source. // source.value should be re-executed, we wrote alias which aliases source.
Expect.notEquals(a, source.load<int>()); Expect.notEquals(a, source.value);
source.free(); source.free();
} }
@ -129,24 +129,24 @@ void testAliasFromAddress2() {
final source = Pointer<Int64>.allocate(); final source = Pointer<Int64>.allocate();
final alias = Pointer<Int64>.fromAddress(source.address); final alias = Pointer<Int64>.fromAddress(source.address);
final alias2 = Pointer<Int64>.fromAddress(source.address); final alias2 = Pointer<Int64>.fromAddress(source.address);
alias.store(42); alias.value = 42;
final int a = alias.load(); final int a = alias.value;
alias2.store(1984); alias2.value = 1984;
// alias.load() should be re-executed, we wrote alias2 which aliases alias. // alias.value should be re-executed, we wrote alias2 which aliases alias.
Expect.notEquals(a, alias.load<int>()); Expect.notEquals(a, alias.value);
source.free(); source.free();
} }
void testAliasFromAddressViaMemory() { void testAliasFromAddressViaMemory() {
final helper = Pointer<IntPtr>.allocate(); final helper = Pointer<IntPtr>.allocate();
final source = Pointer<Int64>.allocate(); final source = Pointer<Int64>.allocate();
helper.store(source.address); helper.value = source.address;
final alias = Pointer<Int64>.fromAddress(helper.load()); final alias = Pointer<Int64>.fromAddress(helper.value);
source.store(42); source.value = 42;
final int a = source.load(); final int a = source.value;
alias.store(1984); alias.value = 1984;
// source.load() should be re-executed, we wrote alias which aliases source. // source.value should be re-executed, we wrote alias which aliases source.
Expect.notEquals(a, source.load<int>()); Expect.notEquals(a, source.value);
helper.free(); helper.free();
source.free(); source.free();
} }
@ -154,14 +154,14 @@ void testAliasFromAddressViaMemory() {
void testAliasFromAddressViaMemory2() { void testAliasFromAddressViaMemory2() {
final helper = Pointer<IntPtr>.allocate(); final helper = Pointer<IntPtr>.allocate();
final source = Pointer<Int64>.allocate(); final source = Pointer<Int64>.allocate();
helper.store(source.address); helper.value = source.address;
final alias = Pointer<Int64>.fromAddress(helper.load()); final alias = Pointer<Int64>.fromAddress(helper.value);
final alias2 = Pointer<Int64>.fromAddress(helper.load()); final alias2 = Pointer<Int64>.fromAddress(helper.value);
alias.store(42); alias.value = 42;
final int a = alias.load(); final int a = alias.value;
alias2.store(1984); alias2.value = 1984;
// alias.load() should be re-executed, we wrote alias2 which aliases alias. // alias.value should be re-executed, we wrote alias2 which aliases alias.
Expect.notEquals(a, alias.load<int>()); Expect.notEquals(a, alias.value);
helper.free(); helper.free();
source.free(); source.free();
} }
@ -178,11 +178,11 @@ void testAliasFromAddressViaNativeFunction() {
final source = Pointer<Int64>.allocate(); final source = Pointer<Int64>.allocate();
final alias = final alias =
Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address)); Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
source.store(42); source.value = 42;
final int a = source.load(); final int a = source.value;
alias.store(1984); alias.value = 1984;
// source.load() should be re-executed, we wrote alias which aliases source. // source.value should be re-executed, we wrote alias which aliases source.
Expect.notEquals(a, source.load<int>()); Expect.notEquals(a, source.value);
source.free(); source.free();
} }
@ -192,11 +192,11 @@ void testAliasFromAddressViaNativeFunction2() {
Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address)); Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
final alias2 = final alias2 =
Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address)); Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
alias.store(42); alias.value = 42;
final int a = alias.load(); final int a = alias.value;
alias2.store(1984); alias2.value = 1984;
// alias.load() should be re-executed, we wrote alias2 which aliases alias. // alias.value should be re-executed, we wrote alias2 which aliases alias.
Expect.notEquals(a, alias.load<int>()); Expect.notEquals(a, alias.value);
source.free(); source.free();
} }
@ -207,9 +207,9 @@ Pointer<Int8> makeDerived(Pointer<Int64> source) =>
testPartialOverlap() { testPartialOverlap() {
final source = Pointer<Int64>.allocate(count: 2); final source = Pointer<Int64>.allocate(count: 2);
final derived = makeDerived(source); final derived = makeDerived(source);
source.store(0x1122334455667788); source.value = 0x1122334455667788;
final int value = source.load(); final int value = source.value;
derived.store(0xaa); derived.value = 0xaa;
Expect.notEquals(value, source.load<int>()); Expect.notEquals(value, source.value);
source.free(); source.free();
} }

View file

@ -17,7 +17,7 @@ class Coordinate extends Struct<Coordinate> {
Pointer<Coordinate> next; Pointer<Coordinate> next;
factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) { factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
return Pointer<Coordinate>.allocate().load<Coordinate>() return Pointer<Coordinate>.allocate().ref
..x = x ..x = x
..y = y ..y = y
..next = next; ..next = next;

View file

@ -9,8 +9,7 @@
library FfiTest; library FfiTest;
import 'dart:ffi' as ffi; import 'dart:ffi';
import 'dart:ffi' show Pointer;
import "package:expect/expect.dart"; import "package:expect/expect.dart";
@ -22,16 +21,16 @@ void main() {
void testPointerAllocateTooLarge() { void testPointerAllocateTooLarge() {
// Try to allocate something that doesn't fit in 64 bit address space. // Try to allocate something that doesn't fit in 64 bit address space.
int maxInt = 9223372036854775807; // 2^63 - 1 int maxInt = 9223372036854775807; // 2^63 - 1
Expect.throws(() => Pointer<ffi.Int64>.allocate(count: maxInt)); Expect.throws(() => Pointer<Int64>.allocate(count: maxInt));
// Try to allocate almost the full 64 bit address space. // Try to allocate almost the full 64 bit address space.
int maxInt1_8 = 1152921504606846975; // 2^60 -1 int maxInt1_8 = 1152921504606846975; // 2^60 -1
Expect.throws(() => Pointer<ffi.Int64>.allocate(count: maxInt1_8)); Expect.throws(() => Pointer<Int64>.allocate(count: maxInt1_8));
} }
void testPointerAllocateNegative() { void testPointerAllocateNegative() {
// Passing in -1 will be converted into an unsigned integer. So, it will try // Passing in -1 will be converted into an unsigned integer. So, it will try
// to allocate SIZE_MAX - 1 + 1 bytes. This will fail as it is the max amount // to allocate SIZE_MAX - 1 + 1 bytes. This will fail as it is the max amount
// of addressable memory on the system. // of addressable memory on the system.
Expect.throws(() => Pointer<ffi.Int8>.allocate(count: -1)); Expect.throws(() => Pointer<Int8>.allocate(count: -1));
} }

View file

@ -6,8 +6,7 @@
library FfiTest; library FfiTest;
import 'dart:ffi' as ffi; import 'dart:ffi';
import 'dart:ffi' show Pointer;
import "package:expect/expect.dart"; import "package:expect/expect.dart";
@ -55,39 +54,39 @@ void main() {
} }
void testPointerBasic() { void testPointerBasic() {
Pointer<ffi.Int64> p = Pointer.allocate(); Pointer<Int64> p = Pointer.allocate();
p.store(42); p.value = 42;
Expect.equals(42, p.load<int>()); Expect.equals(42, p.value);
p.free(); p.free();
} }
void testPointerFromPointer() { void testPointerFromPointer() {
Pointer<ffi.Int64> p = Pointer.allocate(); Pointer<Int64> p = Pointer.allocate();
p.store(1337); p.value = 1337;
int ptr = p.address; int ptr = p.address;
Pointer<ffi.Int64> p2 = Pointer.fromAddress(ptr); Pointer<Int64> p2 = Pointer.fromAddress(ptr);
Expect.equals(1337, p2.load<int>()); Expect.equals(1337, p2.value);
p.free(); p.free();
} }
void testPointerPointerArithmetic() { void testPointerPointerArithmetic() {
Pointer<ffi.Int64> p = Pointer.allocate(count: 2); Pointer<Int64> p = Pointer.allocate(count: 2);
Pointer<ffi.Int64> p2 = p.elementAt(1); Pointer<Int64> p2 = p.elementAt(1);
p2.store(100); p2.value = 100;
Pointer<ffi.Int64> p3 = p.offsetBy(8); Pointer<Int64> p3 = p.offsetBy(8);
Expect.equals(100, p3.load<int>()); Expect.equals(100, p3.value);
p.free(); p.free();
} }
void testPointerPointerArithmeticSizes() { void testPointerPointerArithmeticSizes() {
Pointer<ffi.Int64> p = Pointer.allocate(count: 2); Pointer<Int64> p = Pointer.allocate(count: 2);
Pointer<ffi.Int64> p2 = p.elementAt(1); Pointer<Int64> p2 = p.elementAt(1);
int addr = p.address; int addr = p.address;
Expect.equals(addr + 8, p2.address); Expect.equals(addr + 8, p2.address);
p.free(); p.free();
Pointer<ffi.Int32> p3 = Pointer.allocate(count: 2); Pointer<Int32> p3 = Pointer.allocate(count: 2);
Pointer<ffi.Int32> p4 = p3.elementAt(1); Pointer<Int32> p4 = p3.elementAt(1);
addr = p3.address; addr = p3.address;
Expect.equals(addr + 4, p4.address); Expect.equals(addr + 4, p4.address);
p3.free(); p3.free();
@ -100,9 +99,9 @@ void testPointerAllocateZero() {
// //
// Null pointer throws a Dart exception. // Null pointer throws a Dart exception.
bool returnedNullPointer = false; bool returnedNullPointer = false;
ffi.Pointer<ffi.Int8> p; Pointer<Int8> p;
try { try {
p = Pointer<ffi.Int8>.allocate(count: 0); p = Pointer<Int8>.allocate(count: 0);
} on Exception { } on Exception {
returnedNullPointer = true; returnedNullPointer = true;
} }
@ -112,289 +111,286 @@ void testPointerAllocateZero() {
} }
void testPointerCast() { void testPointerCast() {
Pointer<ffi.Int64> p = Pointer.allocate(); Pointer<Int64> p = Pointer.allocate();
Pointer<ffi.Int32> p2 = p.cast(); // gets the correct type args back Pointer<Int32> p2 = p.cast(); // gets the correct type args back
p.free(); p.free();
} }
void testCastGeneric() { void testCastGeneric() {
Pointer<T> generic<T extends ffi.NativeType>(Pointer<ffi.Int16> p) { Pointer<T> generic<T extends NativeType>(Pointer<Int16> p) {
return p.cast(); return p.cast();
} }
Pointer<ffi.Int16> p = Pointer.allocate(); Pointer<Int16> p = Pointer.allocate();
Pointer<ffi.Int64> p2 = generic(p); Pointer<Int64> p2 = generic(p);
p.free(); p.free();
} }
void testCastGeneric2() { void testCastGeneric2() {
Pointer<ffi.Int64> generic<T extends ffi.NativeType>(Pointer<T> p) { Pointer<Int64> generic<T extends NativeType>(Pointer<T> p) {
return p.cast(); return p.cast();
} }
Pointer<ffi.Int16> p = Pointer.allocate(); Pointer<Int16> p = Pointer.allocate();
Pointer<ffi.Int64> p2 = generic(p); Pointer<Int64> p2 = generic(p);
p.free(); p.free();
} }
void testCastNativeType() { void testCastNativeType() {
ffi.Pointer<ffi.Int64> p = Pointer.allocate(); Pointer<Int64> p = Pointer.allocate();
p.cast<ffi.Pointer>(); p.cast<Pointer>();
p.free(); p.free();
} }
void testCondensedNumbersInt8() { void testCondensedNumbersInt8() {
ffi.Pointer<ffi.Int8> p = Pointer.allocate(count: 8); Pointer<Int8> p = Pointer.allocate(count: 8);
for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) { for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
p.elementAt(i).store(i * 3); p[i] = i * 3;
} }
for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) { for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
Expect.equals(i * 3, p.elementAt(i).load<int>()); Expect.equals(i * 3, p[i]);
} }
p.free(); p.free();
} }
void testCondensedNumbersFloat() { void testCondensedNumbersFloat() {
ffi.Pointer<ffi.Float> p = Pointer.allocate(count: 8); Pointer<Float> p = Pointer.allocate(count: 8);
for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) { for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
p.elementAt(i).store(1.511366173271439e-13); p[i] = 1.511366173271439e-13;
} }
for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) { for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
Expect.equals(1.511366173271439e-13, p.elementAt(i).load<double>()); Expect.equals(1.511366173271439e-13, p[i]);
} }
p.free(); p.free();
} }
void testRangeInt8() { void testRangeInt8() {
ffi.Pointer<ffi.Int8> p = Pointer.allocate(); Pointer<Int8> p = Pointer.allocate();
p.store(127); p.value = 127;
Expect.equals(127, p.load<int>()); Expect.equals(127, p.value);
p.store(-128); p.value = -128;
Expect.equals(-128, p.load<int>()); Expect.equals(-128, p.value);
Expect.equals(0x0000000000000080, 128); Expect.equals(0x0000000000000080, 128);
Expect.equals(0xFFFFFFFFFFFFFF80, -128); Expect.equals(0xFFFFFFFFFFFFFF80, -128);
p.store(128); p.value = 128;
Expect.equals(-128, p.load<int>()); // truncated and sign extended Expect.equals(-128, p.value); // truncated and sign extended
Expect.equals(0xFFFFFFFFFFFFFF7F, -129); Expect.equals(0xFFFFFFFFFFFFFF7F, -129);
Expect.equals(0x000000000000007F, 127); Expect.equals(0x000000000000007F, 127);
p.store(-129); p.value = -129;
Expect.equals(127, p.load<int>()); // truncated Expect.equals(127, p.value); // truncated
p.free(); p.free();
} }
void testRangeUint8() { void testRangeUint8() {
ffi.Pointer<ffi.Uint8> p = Pointer.allocate(); Pointer<Uint8> p = Pointer.allocate();
p.store(255); p.value = 255;
Expect.equals(255, p.load<int>()); Expect.equals(255, p.value);
p.store(0); p.value = 0;
Expect.equals(0, p.load<int>()); Expect.equals(0, p.value);
Expect.equals(0x0000000000000000, 0); Expect.equals(0x0000000000000000, 0);
Expect.equals(0x0000000000000100, 256); Expect.equals(0x0000000000000100, 256);
p.store(256); p.value = 256;
Expect.equals(0, p.load<int>()); // truncated Expect.equals(0, p.value); // truncated
Expect.equals(0xFFFFFFFFFFFFFFFF, -1); Expect.equals(0xFFFFFFFFFFFFFFFF, -1);
Expect.equals(0x00000000000000FF, 255); Expect.equals(0x00000000000000FF, 255);
p.store(-1); p.value = -1;
Expect.equals(255, p.load<int>()); // truncated Expect.equals(255, p.value); // truncated
p.free(); p.free();
} }
void testRangeInt16() { void testRangeInt16() {
ffi.Pointer<ffi.Int16> p = Pointer.allocate(); Pointer<Int16> p = Pointer.allocate();
p.store(0x7FFF); p.value = 0x7FFF;
Expect.equals(0x7FFF, p.load<int>()); Expect.equals(0x7FFF, p.value);
p.store(-0x8000); p.value = -0x8000;
Expect.equals(-0x8000, p.load<int>()); Expect.equals(-0x8000, p.value);
p.store(0x8000); p.value = 0x8000;
Expect.equals( Expect.equals(0xFFFFFFFFFFFF8000, p.value); // truncated and sign extended
0xFFFFFFFFFFFF8000, p.load<int>()); // truncated and sign extended p.value = -0x8001;
p.store(-0x8001); Expect.equals(0x7FFF, p.value); // truncated
Expect.equals(0x7FFF, p.load<int>()); // truncated
p.free(); p.free();
} }
void testRangeUint16() { void testRangeUint16() {
ffi.Pointer<ffi.Uint16> p = Pointer.allocate(); Pointer<Uint16> p = Pointer.allocate();
p.store(0xFFFF); p.value = 0xFFFF;
Expect.equals(0xFFFF, p.load<int>()); Expect.equals(0xFFFF, p.value);
p.store(0); p.value = 0;
Expect.equals(0, p.load<int>()); Expect.equals(0, p.value);
p.store(0x10000); p.value = 0x10000;
Expect.equals(0, p.load<int>()); // truncated Expect.equals(0, p.value); // truncated
p.store(-1); p.value = -1;
Expect.equals(0xFFFF, p.load<int>()); // truncated Expect.equals(0xFFFF, p.value); // truncated
p.free(); p.free();
} }
void testRangeInt32() { void testRangeInt32() {
ffi.Pointer<ffi.Int32> p = Pointer.allocate(); Pointer<Int32> p = Pointer.allocate();
p.store(0x7FFFFFFF); p.value = 0x7FFFFFFF;
Expect.equals(0x7FFFFFFF, p.load<int>()); Expect.equals(0x7FFFFFFF, p.value);
p.store(-0x80000000); p.value = -0x80000000;
Expect.equals(-0x80000000, p.load<int>()); Expect.equals(-0x80000000, p.value);
p.store(0x80000000); p.value = 0x80000000;
Expect.equals( Expect.equals(0xFFFFFFFF80000000, p.value); // truncated and sign extended
0xFFFFFFFF80000000, p.load<int>()); // truncated and sign extended p.value = -0x80000001;
p.store(-0x80000001); Expect.equals(0x7FFFFFFF, p.value); // truncated
Expect.equals(0x7FFFFFFF, p.load<int>()); // truncated
p.free(); p.free();
} }
void testRangeUint32() { void testRangeUint32() {
ffi.Pointer<ffi.Uint32> p = Pointer.allocate(); Pointer<Uint32> p = Pointer.allocate();
p.store(0xFFFFFFFF); p.value = 0xFFFFFFFF;
Expect.equals(0xFFFFFFFF, p.load<int>()); Expect.equals(0xFFFFFFFF, p.value);
p.store(0); p.value = 0;
Expect.equals(0, p.load<int>()); Expect.equals(0, p.value);
p.store(0x100000000); p.value = 0x100000000;
Expect.equals(0, p.load<int>()); // truncated Expect.equals(0, p.value); // truncated
p.store(-1); p.value = -1;
Expect.equals(0xFFFFFFFF, p.load<int>()); // truncated Expect.equals(0xFFFFFFFF, p.value); // truncated
p.free(); p.free();
} }
void testRangeInt64() { void testRangeInt64() {
ffi.Pointer<ffi.Int64> p = Pointer.allocate(); Pointer<Int64> p = Pointer.allocate();
p.store(0x7FFFFFFFFFFFFFFF); // 2 ^ 63 - 1 p.value = 0x7FFFFFFFFFFFFFFF; // 2 ^ 63 - 1
Expect.equals(0x7FFFFFFFFFFFFFFF, p.load<int>()); Expect.equals(0x7FFFFFFFFFFFFFFF, p.value);
p.store(-0x8000000000000000); // -2 ^ 63 p.value = -0x8000000000000000; // -2 ^ 63
Expect.equals(-0x8000000000000000, p.load<int>()); Expect.equals(-0x8000000000000000, p.value);
p.free(); p.free();
} }
void testRangeUint64() { void testRangeUint64() {
ffi.Pointer<ffi.Uint64> p = Pointer.allocate(); Pointer<Uint64> p = Pointer.allocate();
p.store(0x7FFFFFFFFFFFFFFF); // 2 ^ 63 - 1 p.value = 0x7FFFFFFFFFFFFFFF; // 2 ^ 63 - 1
Expect.equals(0x7FFFFFFFFFFFFFFF, p.load<int>()); Expect.equals(0x7FFFFFFFFFFFFFFF, p.value);
p.store(-0x8000000000000000); // -2 ^ 63 interpreted as 2 ^ 63 p.value = -0x8000000000000000; // -2 ^ 63 interpreted as 2 ^ 63
Expect.equals(-0x8000000000000000, p.load<int>()); Expect.equals(-0x8000000000000000, p.value);
// Dart allows interpreting bits both signed and unsigned // Dart allows interpreting bits both signed and unsigned
Expect.equals(0xFFFFFFFFFFFFFFFF, -1); Expect.equals(0xFFFFFFFFFFFFFFFF, -1);
p.store(-1); // -1 interpreted as 2 ^ 64 - 1 p.value = -1; // -1 interpreted as 2 ^ 64 - 1
Expect.equals(-1, p.load<int>()); Expect.equals(-1, p.value);
Expect.equals(0xFFFFFFFFFFFFFFFF, p.load<int>()); Expect.equals(0xFFFFFFFFFFFFFFFF, p.value);
p.free(); p.free();
} }
void testRangeIntPtr() { void testRangeIntPtr() {
ffi.Pointer<ffi.IntPtr> p = Pointer.allocate(); Pointer<IntPtr> p = Pointer.allocate();
int pAddr = p.address; int pAddr = p.address;
p.store(pAddr); // its own address should fit p.value = pAddr; // its own address should fit
p.store(0x7FFFFFFF); // and 32 bit addresses should fit p.value = 0x7FFFFFFF; // and 32 bit addresses should fit
Expect.equals(0x7FFFFFFF, p.load<int>()); Expect.equals(0x7FFFFFFF, p.value);
p.store(-0x80000000); p.value = -0x80000000;
Expect.equals(-0x80000000, p.load<int>()); Expect.equals(-0x80000000, p.value);
p.free(); p.free();
} }
void testFloat() { void testFloat() {
ffi.Pointer<ffi.Float> p = Pointer.allocate(); Pointer<Float> p = Pointer.allocate();
p.store(1.511366173271439e-13); p.value = 1.511366173271439e-13;
Expect.equals(1.511366173271439e-13, p.load<double>()); Expect.equals(1.511366173271439e-13, p.value);
p.store(1.4260258159703532e-105); // float does not have enough precision p.value = 1.4260258159703532e-105; // float does not have enough precision
Expect.notEquals(1.4260258159703532e-105, p.load<double>()); Expect.notEquals(1.4260258159703532e-105, p.value);
p.free(); p.free();
} }
void testDouble() { void testDouble() {
ffi.Pointer<ffi.Double> p = Pointer.allocate(); Pointer<Double> p = Pointer.allocate();
p.store(1.4260258159703532e-105); p.value = 1.4260258159703532e-105;
Expect.equals(1.4260258159703532e-105, p.load<double>()); Expect.equals(1.4260258159703532e-105, p.value);
p.free(); p.free();
} }
void testVoid() { void testVoid() {
ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate(); Pointer<IntPtr> p1 = Pointer.allocate();
ffi.Pointer<ffi.Void> p2 = p1.cast(); // make this dart pointer opaque Pointer<Void> p2 = p1.cast(); // make this dart pointer opaque
p2.address; // we can print the address p2.address; // we can print the address
p2.free(); p2.free();
} }
void testPointerPointer() { void testPointerPointer() {
ffi.Pointer<ffi.Int16> p = Pointer.allocate(); Pointer<Int16> p = Pointer.allocate();
p.store(17); p.value = 17;
ffi.Pointer<ffi.Pointer<ffi.Int16>> p2 = Pointer.allocate(); Pointer<Pointer<Int16>> p2 = Pointer.allocate();
p2.store(p); p2.value = p;
Expect.equals(17, p2.load<ffi.Pointer<ffi.Int16>>().load<int>()); Expect.equals(17, p2.value.value);
p2.free(); p2.free();
p.free(); p.free();
} }
void testPointerPointerNull() { void testPointerPointerNull() {
Pointer<Pointer<ffi.Int8>> pointerToPointer = Pointer.allocate(); Pointer<Pointer<Int8>> pointerToPointer = Pointer.allocate();
Pointer<ffi.Int8> value = ffi.nullptr.cast(); Pointer<Int8> value = nullptr.cast();
pointerToPointer.store(value); pointerToPointer.value = value;
value = pointerToPointer.load(); value = pointerToPointer.value;
Expect.equals(value, ffi.nullptr); Expect.equals(value, nullptr);
value = Pointer.allocate(); value = Pointer.allocate();
pointerToPointer.store(value); pointerToPointer.value = value;
value = pointerToPointer.load(); value = pointerToPointer.value;
Expect.isNotNull(value); Expect.isNotNull(value);
value.free(); value.free();
value = ffi.nullptr.cast(); value = nullptr.cast();
pointerToPointer.store(value); pointerToPointer.value = value;
value = pointerToPointer.load(); value = pointerToPointer.value;
Expect.equals(value, ffi.nullptr); Expect.equals(value, nullptr);
pointerToPointer.free(); pointerToPointer.free();
} }
void testPointerStoreNull() { void testPointerStoreNull() {
int i = null; int i = null;
ffi.Pointer<ffi.Int8> p = Pointer.allocate(); Pointer<Int8> p = Pointer.allocate();
Expect.throws(() => p.store(i)); Expect.throws(() => p.value = i);
p.free(); p.free();
double d = null; double d = null;
ffi.Pointer<ffi.Float> p2 = Pointer.allocate(); Pointer<Float> p2 = Pointer.allocate();
Expect.throws(() => p2.store(d)); Expect.throws(() => p2.value = d);
p2.free(); p2.free();
Pointer<ffi.Void> x = null; Pointer<Void> x = null;
ffi.Pointer<ffi.Pointer<ffi.Void>> p3 = Pointer.allocate(); Pointer<Pointer<Void>> p3 = Pointer.allocate();
Expect.throws(() => p3.store(x)); Expect.throws(() => p3.value = x);
p3.free(); p3.free();
} }
void testSizeOf() { void testSizeOf() {
Expect.equals(1, ffi.sizeOf<ffi.Int8>()); Expect.equals(1, sizeOf<Int8>());
Expect.equals(2, ffi.sizeOf<ffi.Int16>()); Expect.equals(2, sizeOf<Int16>());
Expect.equals(4, ffi.sizeOf<ffi.Int32>()); Expect.equals(4, sizeOf<Int32>());
Expect.equals(8, ffi.sizeOf<ffi.Int64>()); Expect.equals(8, sizeOf<Int64>());
Expect.equals(1, ffi.sizeOf<ffi.Uint8>()); Expect.equals(1, sizeOf<Uint8>());
Expect.equals(2, ffi.sizeOf<ffi.Uint16>()); Expect.equals(2, sizeOf<Uint16>());
Expect.equals(4, ffi.sizeOf<ffi.Uint32>()); Expect.equals(4, sizeOf<Uint32>());
Expect.equals(8, ffi.sizeOf<ffi.Uint64>()); Expect.equals(8, sizeOf<Uint64>());
Expect.equals( Expect.equals(true, 4 == sizeOf<IntPtr>() || 8 == sizeOf<IntPtr>());
true, 4 == ffi.sizeOf<ffi.IntPtr>() || 8 == ffi.sizeOf<ffi.IntPtr>()); Expect.equals(4, sizeOf<Float>());
Expect.equals(4, ffi.sizeOf<ffi.Float>()); Expect.equals(8, sizeOf<Double>());
Expect.equals(8, ffi.sizeOf<ffi.Double>());
} }
// note: stack overflows at around 15k calls // note: stack overflows at around 15k calls
void testPointerChain(int length) { void testPointerChain(int length) {
void createChain(ffi.Pointer<ffi.IntPtr> head, int length, int value) { void createChain(Pointer<IntPtr> head, int length, int value) {
if (length == 0) { if (length == 0) {
head.store(value); head.value = value;
return; return;
} }
ffi.Pointer<ffi.IntPtr> next = Pointer.allocate(); Pointer<IntPtr> next = Pointer.allocate();
head.store(next.address); head.value = next.address;
createChain(next, length - 1, value); createChain(next, length - 1, value);
} }
int getChainValue(ffi.Pointer<ffi.IntPtr> head, int length) { int getChainValue(Pointer<IntPtr> head, int length) {
if (length == 0) { if (length == 0) {
return head.load(); return head.value;
} }
ffi.Pointer<ffi.IntPtr> next = Pointer.fromAddress(head.load()); Pointer<IntPtr> next = Pointer.fromAddress(head.value);
return getChainValue(next, length - 1); return getChainValue(next, length - 1);
} }
void freeChain(ffi.Pointer<ffi.IntPtr> head, int length) { void freeChain(Pointer<IntPtr> head, int length) {
ffi.Pointer<ffi.IntPtr> next = Pointer.fromAddress(head.load()); Pointer<IntPtr> next = Pointer.fromAddress(head.value);
head.free(); head.free();
if (length == 0) { if (length == 0) {
return; return;
@ -402,7 +398,7 @@ void testPointerChain(int length) {
freeChain(next, length - 1); freeChain(next, length - 1);
} }
ffi.Pointer<ffi.IntPtr> head = Pointer.allocate(); Pointer<IntPtr> head = Pointer.allocate();
createChain(head, length, 512); createChain(head, length, 512);
int tailValue = getChainValue(head, length); int tailValue = getChainValue(head, length);
Expect.equals(512, tailValue); Expect.equals(512, tailValue);
@ -410,56 +406,56 @@ void testPointerChain(int length) {
} }
void testTypeTest() { void testTypeTest() {
ffi.Pointer<ffi.Int8> p = Pointer.allocate(); Pointer<Int8> p = Pointer.allocate();
Expect.isTrue(p is ffi.Pointer); Expect.isTrue(p is Pointer);
p.free(); p.free();
} }
void testToString() { void testToString() {
ffi.Pointer<ffi.Int16> p = Pointer.allocate(); Pointer<Int16> p = Pointer.allocate();
Expect.stringEquals( Expect.stringEquals(
"Pointer<Int16>: address=0x", p.toString().substring(0, 26)); "Pointer<Int16>: address=0x", p.toString().substring(0, 26));
p.free(); p.free();
ffi.Pointer<ffi.Int64> p2 = Pointer.fromAddress(0x123abc); Pointer<Int64> p2 = Pointer.fromAddress(0x123abc);
Expect.stringEquals("Pointer<Int64>: address=0x123abc", p2.toString()); Expect.stringEquals("Pointer<Int64>: address=0x123abc", p2.toString());
} }
void testEquality() { void testEquality() {
ffi.Pointer<ffi.Int8> p = Pointer.fromAddress(12345678); Pointer<Int8> p = Pointer.fromAddress(12345678);
ffi.Pointer<ffi.Int8> p2 = Pointer.fromAddress(12345678); Pointer<Int8> p2 = Pointer.fromAddress(12345678);
Expect.equals(p, p2); Expect.equals(p, p2);
Expect.equals(p.hashCode, p2.hashCode); Expect.equals(p.hashCode, p2.hashCode);
ffi.Pointer<ffi.Int16> p3 = p.cast(); Pointer<Int16> p3 = p.cast();
Expect.equals(p, p3); Expect.equals(p, p3);
Expect.equals(p.hashCode, p3.hashCode); Expect.equals(p.hashCode, p3.hashCode);
Expect.notEquals(p, null); Expect.notEquals(p, null);
Expect.notEquals(null, p); Expect.notEquals(null, p);
ffi.Pointer<ffi.Int8> p4 = p.offsetBy(1337); Pointer<Int8> p4 = p.offsetBy(1337);
Expect.notEquals(p, p4); Expect.notEquals(p, p4);
} }
typedef Int8UnOp = ffi.Int8 Function(ffi.Int8); typedef Int8UnOp = Int8 Function(Int8);
void testAllocateGeneric() { void testAllocateGeneric() {
ffi.Pointer<T> generic<T extends ffi.NativeType>() { Pointer<T> generic<T extends NativeType>() {
ffi.Pointer<T> pointer; Pointer<T> pointer;
pointer = Pointer.allocate(); pointer = Pointer.allocate();
return pointer; return pointer;
} }
ffi.Pointer p = generic<ffi.Int64>(); Pointer p = generic<Int64>();
p.free(); p.free();
} }
void testAllocateVoid() { void testAllocateVoid() {
Expect.throws(() { Expect.throws(() {
ffi.Pointer<ffi.Void> p = Pointer.allocate(); Pointer<Void> p = Pointer.allocate();
}); });
} }
void testAllocateNativeFunction() { void testAllocateNativeFunction() {
Expect.throws(() { Expect.throws(() {
ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.allocate(); Pointer<NativeFunction<Int8UnOp>> p = Pointer.allocate();
}); });
} }
@ -470,42 +466,42 @@ void testAllocateNativeType() {
} }
void testSizeOfGeneric() { void testSizeOfGeneric() {
int generic<T extends ffi.Pointer>() { int generic<T extends Pointer>() {
int size; int size;
size = ffi.sizeOf<T>(); size = sizeOf<T>();
return size; return size;
} }
int size = generic<ffi.Pointer<ffi.Int64>>(); int size = generic<Pointer<Int64>>();
Expect.isTrue(size == 8 || size == 4); Expect.isTrue(size == 8 || size == 4);
} }
void testSizeOfVoid() { void testSizeOfVoid() {
Expect.throws(() { Expect.throws(() {
ffi.sizeOf<ffi.Void>(); sizeOf<Void>();
}); });
} }
void testSizeOfNativeFunction() { void testSizeOfNativeFunction() {
Expect.throws(() { Expect.throws(() {
ffi.sizeOf<ffi.NativeFunction<Int8UnOp>>(); sizeOf<NativeFunction<Int8UnOp>>();
}); });
} }
void testSizeOfNativeType() { void testSizeOfNativeType() {
Expect.throws(() { Expect.throws(() {
ffi.sizeOf(); sizeOf();
}); });
} }
void testDynamicInvocation() { void testDynamicInvocation() {
dynamic p = Pointer<ffi.Int8>.allocate(); dynamic p = Pointer<Int8>.allocate();
Expect.throws(() { Expect.throws(() {
final int i = p.load(); final int i = p.value;
}); });
Expect.throws(() => p.store(1)); Expect.throws(() => p.value = 1);
p.elementAt(5); // Works, but is slow. p.elementAt(5); // Works, but is slow.
final int addr = p.address; final int addr = p.address;
final Pointer<ffi.Int16> p2 = p.cast<ffi.Int16>(); final Pointer<Int16> p2 = p.cast<Int16>();
p.free(); p.free();
} }

View file

@ -42,7 +42,7 @@ main() {
void testInt8Load() { void testInt8Load() {
// Load // Load
Pointer<Int8> ptr = Pointer.allocate(); Pointer<Int8> ptr = Pointer.allocate();
ptr.store(0xff); ptr.value = 0xff;
Int8List list = ptr.asExternalTypedData(); Int8List list = ptr.asExternalTypedData();
Expect.equals(list[0], -1); Expect.equals(list[0], -1);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -55,14 +55,14 @@ void testInt8Store() {
Int8List list = ptr.asExternalTypedData(); Int8List list = ptr.asExternalTypedData();
list[0] = 0xff; list[0] = 0xff;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<int>(), -1); Expect.equals(ptr.value, -1);
ptr.free(); ptr.free();
} }
void testUint8Load() { void testUint8Load() {
// Load // Load
Pointer<Uint8> ptr = Pointer.allocate(); Pointer<Uint8> ptr = Pointer.allocate();
ptr.store(0xff); ptr.value = 0xff;
Uint8List list = ptr.asExternalTypedData(); Uint8List list = ptr.asExternalTypedData();
Expect.equals(list[0], 0xff); Expect.equals(list[0], 0xff);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -75,14 +75,14 @@ void testUint8Store() {
Uint8List list = ptr.asExternalTypedData(); Uint8List list = ptr.asExternalTypedData();
list[0] = 0xff; list[0] = 0xff;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<int>(), 0xff); Expect.equals(ptr.value, 0xff);
ptr.free(); ptr.free();
} }
void testInt16Load() { void testInt16Load() {
// Load // Load
Pointer<Int16> ptr = Pointer.allocate(); Pointer<Int16> ptr = Pointer.allocate();
ptr.store(0xffff); ptr.value = 0xffff;
Int16List list = ptr.asExternalTypedData(); Int16List list = ptr.asExternalTypedData();
Expect.equals(list[0], -1); Expect.equals(list[0], -1);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -95,14 +95,14 @@ void testInt16Store() {
Int16List list = ptr.asExternalTypedData(); Int16List list = ptr.asExternalTypedData();
list[0] = 0xffff; list[0] = 0xffff;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<int>(), -1); Expect.equals(ptr.value, -1);
ptr.free(); ptr.free();
} }
void testUint16Load() { void testUint16Load() {
// Load // Load
Pointer<Uint16> ptr = Pointer.allocate(); Pointer<Uint16> ptr = Pointer.allocate();
ptr.store(0xffff); ptr.value = 0xffff;
Uint16List list = ptr.asExternalTypedData(); Uint16List list = ptr.asExternalTypedData();
Expect.equals(list[0], 0xffff); Expect.equals(list[0], 0xffff);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -115,14 +115,14 @@ void testUint16Store() {
Uint16List list = ptr.asExternalTypedData(); Uint16List list = ptr.asExternalTypedData();
list[0] = 0xffff; list[0] = 0xffff;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<int>(), 0xffff); Expect.equals(ptr.value, 0xffff);
ptr.free(); ptr.free();
} }
void testInt32Load() { void testInt32Load() {
// Load // Load
Pointer<Int32> ptr = Pointer.allocate(); Pointer<Int32> ptr = Pointer.allocate();
ptr.store(0xffffffff); ptr.value = 0xffffffff;
Int32List list = ptr.asExternalTypedData(); Int32List list = ptr.asExternalTypedData();
Expect.equals(list[0], -1); Expect.equals(list[0], -1);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -135,14 +135,14 @@ void testInt32Store() {
Int32List list = ptr.asExternalTypedData(); Int32List list = ptr.asExternalTypedData();
list[0] = 0xffffffff; list[0] = 0xffffffff;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<int>(), -1); Expect.equals(ptr.value, -1);
ptr.free(); ptr.free();
} }
void testUint32Load() { void testUint32Load() {
// Load // Load
Pointer<Uint32> ptr = Pointer.allocate(); Pointer<Uint32> ptr = Pointer.allocate();
ptr.store(0xffffffff); ptr.value = 0xffffffff;
Uint32List list = ptr.asExternalTypedData(); Uint32List list = ptr.asExternalTypedData();
Expect.equals(list[0], 0xffffffff); Expect.equals(list[0], 0xffffffff);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -155,14 +155,14 @@ void testUint32Store() {
Uint32List list = ptr.asExternalTypedData(); Uint32List list = ptr.asExternalTypedData();
list[0] = 0xffffffff; list[0] = 0xffffffff;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<int>(), 0xffffffff); Expect.equals(ptr.value, 0xffffffff);
ptr.free(); ptr.free();
} }
void testInt64Load() { void testInt64Load() {
// Load // Load
Pointer<Int64> ptr = Pointer.allocate(); Pointer<Int64> ptr = Pointer.allocate();
ptr.store(0xffffffffffffffff); ptr.value = 0xffffffffffffffff;
Int64List list = ptr.asExternalTypedData(); Int64List list = ptr.asExternalTypedData();
Expect.equals(list[0], -1); Expect.equals(list[0], -1);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -175,14 +175,14 @@ void testInt64Store() {
Int64List list = ptr.asExternalTypedData(); Int64List list = ptr.asExternalTypedData();
list[0] = 0xffffffffffffffff; list[0] = 0xffffffffffffffff;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<int>(), -1); Expect.equals(ptr.value, -1);
ptr.free(); ptr.free();
} }
void testUint64Load() { void testUint64Load() {
// Load // Load
Pointer<Uint64> ptr = Pointer.allocate(); Pointer<Uint64> ptr = Pointer.allocate();
ptr.store(0xffffffffffffffff); ptr.value = 0xffffffffffffffff;
Uint64List list = ptr.asExternalTypedData(); Uint64List list = ptr.asExternalTypedData();
Expect.equals(list[0], 0xffffffffffffffff); Expect.equals(list[0], 0xffffffffffffffff);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -195,7 +195,7 @@ void testUint64Store() {
Uint64List list = ptr.asExternalTypedData(); Uint64List list = ptr.asExternalTypedData();
list[0] = 0xffffffffffffffff; list[0] = 0xffffffffffffffff;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<int>(), 0xffffffffffffffff); Expect.equals(ptr.value, 0xffffffffffffffff);
ptr.free(); ptr.free();
} }
@ -217,7 +217,7 @@ double maxDouble = (2 - pow(2, -52)) * pow(2, pow(2, 10) - 1);
void testFloatLoad() { void testFloatLoad() {
// Load // Load
Pointer<Float> ptr = Pointer.allocate(); Pointer<Float> ptr = Pointer.allocate();
ptr.store(maxFloat); ptr.value = maxFloat;
Float32List list = ptr.asExternalTypedData(); Float32List list = ptr.asExternalTypedData();
Expect.equals(list[0], maxFloat); Expect.equals(list[0], maxFloat);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -230,14 +230,14 @@ void testFloatStore() {
Float32List list = ptr.asExternalTypedData(); Float32List list = ptr.asExternalTypedData();
list[0] = maxFloat; list[0] = maxFloat;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<double>(), maxFloat); Expect.equals(ptr.value, maxFloat);
ptr.free(); ptr.free();
} }
void testDoubleLoad() { void testDoubleLoad() {
// Load // Load
Pointer<Double> ptr = Pointer.allocate(); Pointer<Double> ptr = Pointer.allocate();
ptr.store(maxDouble); ptr.value = maxDouble;
Float64List list = ptr.asExternalTypedData(); Float64List list = ptr.asExternalTypedData();
Expect.equals(list[0], maxDouble); Expect.equals(list[0], maxDouble);
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
@ -250,7 +250,7 @@ void testDoubleStore() {
Float64List list = ptr.asExternalTypedData(); Float64List list = ptr.asExternalTypedData();
list[0] = maxDouble; list[0] = maxDouble;
Expect.equals(list.length, 1); Expect.equals(list.length, 1);
Expect.equals(ptr.load<double>(), maxDouble); Expect.equals(ptr.value, maxDouble);
ptr.free(); ptr.free();
} }
@ -258,7 +258,7 @@ void testArrayLoad() {
const int count = 0x100; const int count = 0x100;
Pointer<Int32> ptr = Pointer.allocate(count: count); Pointer<Int32> ptr = Pointer.allocate(count: count);
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
ptr.elementAt(i).store(i); ptr[i] = i;
} }
Int32List array = ptr.asExternalTypedData(count: count); Int32List array = ptr.asExternalTypedData(count: count);
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
@ -275,7 +275,7 @@ void testArrayStore() {
array[i] = i; array[i] = i;
} }
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
Expect.equals(ptr.elementAt(i).load<int>(), i); Expect.equals(ptr[i], i);
} }
ptr.free(); ptr.free();
} }

View file

@ -143,7 +143,7 @@ double manyArgs(
} }
typedef StoreType = Pointer<Int64> Function(Pointer<Int64>); typedef StoreType = Pointer<Int64> Function(Pointer<Int64>);
Pointer<Int64> store(Pointer<Int64> ptr) => ptr.elementAt(1)..store(1337); Pointer<Int64> store(Pointer<Int64> ptr) => ptr.elementAt(1)..value = 1337;
typedef NullPointersType = Pointer<Int64> Function(Pointer<Int64>); typedef NullPointersType = Pointer<Int64> Function(Pointer<Int64>);
Pointer<Int64> nullPointers(Pointer<Int64> ptr) => ptr.elementAt(1); Pointer<Int64> nullPointers(Pointer<Int64> ptr) => ptr.elementAt(1);
@ -182,15 +182,19 @@ void testGC() {
typedef WaitForHelper = Void Function(Pointer<Void>); typedef WaitForHelper = Void Function(Pointer<Void>);
void waitForHelper(Pointer<Void> helper) { void waitForHelper(Pointer<Void> helper) {
print("helper: $helper"); print("helper: $helper");
testLibrary.lookupFunction<WaitForHelper, WaitForHelper>("WaitForHelper")(helper); testLibrary
.lookupFunction<WaitForHelper, WaitForHelper>("WaitForHelper")(helper);
} }
final List<Test> testcases = [ final List<Test> testcases = [
Test("SimpleAddition", Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 0)), Test("SimpleAddition",
Test("IntComputation", Pointer.fromFunction<IntComputationType>(intComputation, 0)), Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 0)),
Test( Test("IntComputation",
"UintComputation", Pointer.fromFunction<UintComputationType>(uintComputation, 0)), Pointer.fromFunction<IntComputationType>(intComputation, 0)),
Test("SimpleMultiply", Pointer.fromFunction<SimpleMultiplyType>(simpleMultiply, 0.0)), Test("UintComputation",
Pointer.fromFunction<UintComputationType>(uintComputation, 0)),
Test("SimpleMultiply",
Pointer.fromFunction<SimpleMultiplyType>(simpleMultiply, 0.0)),
Test("SimpleMultiplyFloat", Test("SimpleMultiplyFloat",
Pointer.fromFunction<SimpleMultiplyFloatType>(simpleMultiplyFloat, 0.0)), Pointer.fromFunction<SimpleMultiplyFloatType>(simpleMultiplyFloat, 0.0)),
Test("ManyInts", Pointer.fromFunction<ManyIntsType>(manyInts, 0)), Test("ManyInts", Pointer.fromFunction<ManyIntsType>(manyInts, 0)),
@ -202,17 +206,17 @@ final List<Test> testcases = [
Test("ReturnVoid", Pointer.fromFunction<ReturnVoid>(returnVoid)), Test("ReturnVoid", Pointer.fromFunction<ReturnVoid>(returnVoid)),
Test("ThrowExceptionDouble", Test("ThrowExceptionDouble",
Pointer.fromFunction<ThrowExceptionDouble>(throwExceptionDouble, 42.0)), Pointer.fromFunction<ThrowExceptionDouble>(throwExceptionDouble, 42.0)),
Test( Test("ThrowExceptionPointer",
"ThrowExceptionPointer", Pointer.fromFunction<ThrowExceptionPointer>(throwExceptionPointer)),
Pointer.fromFunction<ThrowExceptionPointer>( Test("ThrowException",
throwExceptionPointer)), Pointer.fromFunction<ThrowExceptionInt>(throwExceptionInt, 42)),
Test("ThrowException", Pointer.fromFunction<ThrowExceptionInt>(throwExceptionInt, 42)),
Test("GC", Pointer.fromFunction<ReturnVoid>(testGC)), Test("GC", Pointer.fromFunction<ReturnVoid>(testGC)),
Test("UnprotectCode", Pointer.fromFunction<WaitForHelper>(waitForHelper)), Test("UnprotectCode", Pointer.fromFunction<WaitForHelper>(waitForHelper)),
]; ];
testCallbackWrongThread() => testCallbackWrongThread() =>
Test("CallbackWrongThread", Pointer.fromFunction<ReturnVoid>(returnVoid)).run(); Test("CallbackWrongThread", Pointer.fromFunction<ReturnVoid>(returnVoid))
.run();
testCallbackOutsideIsolate() => testCallbackOutsideIsolate() =>
Test("CallbackOutsideIsolate", Pointer.fromFunction<ReturnVoid>(returnVoid)) Test("CallbackOutsideIsolate", Pointer.fromFunction<ReturnVoid>(returnVoid))
@ -227,7 +231,8 @@ isolateHelper(int callbackPointer) {
} }
testCallbackWrongIsolate() async { testCallbackWrongIsolate() async {
final int callbackPointer = Pointer.fromFunction<ReturnVoid>(returnVoid).address; final int callbackPointer =
Pointer.fromFunction<ReturnVoid>(returnVoid).address;
final ReceivePort exitPort = ReceivePort(); final ReceivePort exitPort = ReceivePort();
await Isolate.spawn(isolateHelper, callbackPointer, await Isolate.spawn(isolateHelper, callbackPointer,
errorsAreFatal: true, onExit: exitPort.sendPort); errorsAreFatal: true, onExit: exitPort.sendPort);

View file

@ -9,8 +9,7 @@
library FfiTest; library FfiTest;
import 'dart:ffi' as ffi; import 'dart:ffi';
import 'dart:ffi' show Pointer;
import 'dylib_utils.dart'; import 'dylib_utils.dart';
@ -27,24 +26,23 @@ void main() {
testFunctionWithVeryLargeStruct(); testFunctionWithVeryLargeStruct();
} }
ffi.DynamicLibrary ffiTestFunctions = DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
dlopenPlatformSpecific("ffi_test_functions");
/// pass a struct to a c function and get a struct as return value /// pass a struct to a c function and get a struct as return value
void testFunctionWithStruct() { void testFunctionWithStruct() {
ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>> p1 = Pointer<NativeFunction<NativeCoordinateOp>> p1 =
ffiTestFunctions.lookup("TransposeCoordinate"); ffiTestFunctions.lookup("TransposeCoordinate");
NativeCoordinateOp f1 = p1.asFunction(); NativeCoordinateOp f1 = p1.asFunction();
Pointer<Coordinate> c1 = Pointer<Coordinate> c1 =
Coordinate.allocate(10.0, 20.0, ffi.nullptr.cast<Coordinate>()).addressOf; Coordinate.allocate(10.0, 20.0, nullptr.cast<Coordinate>()).addressOf;
Pointer<Coordinate> c2 = Coordinate.allocate(42.0, 84.0, c1).addressOf; Pointer<Coordinate> c2 = Coordinate.allocate(42.0, 84.0, c1).addressOf;
c1.load<Coordinate>().next = c2; c1.ref.next = c2;
Coordinate result = f1(c1).load(); Coordinate result = f1(c1).ref;
Expect.approxEquals(20.0, c1.load<Coordinate>().x); Expect.approxEquals(20.0, c1.ref.x);
Expect.approxEquals(30.0, c1.load<Coordinate>().y); Expect.approxEquals(30.0, c1.ref.y);
Expect.approxEquals(42.0, result.x); Expect.approxEquals(42.0, result.x);
Expect.approxEquals(84.0, result.y); Expect.approxEquals(84.0, result.y);
@ -55,13 +53,13 @@ void testFunctionWithStruct() {
/// pass an array of structs to a c funtion /// pass an array of structs to a c funtion
void testFunctionWithStructArray() { void testFunctionWithStructArray() {
ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>> p1 = Pointer<NativeFunction<NativeCoordinateOp>> p1 =
ffiTestFunctions.lookup("CoordinateElemAt1"); ffiTestFunctions.lookup("CoordinateElemAt1");
NativeCoordinateOp f1 = p1.asFunction(); NativeCoordinateOp f1 = p1.asFunction();
Coordinate c1 = Pointer<Coordinate>.allocate(count: 3).load(); Coordinate c1 = Pointer<Coordinate>.allocate(count: 3).ref;
Coordinate c2 = c1.addressOf.elementAt(1).load(); Coordinate c2 = c1.addressOf[1];
Coordinate c3 = c1.addressOf.elementAt(2).load(); Coordinate c3 = c1.addressOf[2];
c1.x = 10.0; c1.x = 10.0;
c1.y = 10.0; c1.y = 10.0;
c1.next = c3.addressOf; c1.next = c3.addressOf;
@ -72,7 +70,7 @@ void testFunctionWithStructArray() {
c3.y = 30.0; c3.y = 30.0;
c3.next = c2.addressOf; c3.next = c2.addressOf;
Coordinate result = f1(c1.addressOf).load(); Coordinate result = f1(c1.addressOf).ref;
Expect.approxEquals(20.0, result.x); Expect.approxEquals(20.0, result.x);
Expect.approxEquals(20.0, result.y); Expect.approxEquals(20.0, result.y);
@ -80,15 +78,15 @@ void testFunctionWithStructArray() {
} }
typedef VeryLargeStructSum = int Function(Pointer<VeryLargeStruct>); typedef VeryLargeStructSum = int Function(Pointer<VeryLargeStruct>);
typedef NativeVeryLargeStructSum = ffi.Int64 Function(Pointer<VeryLargeStruct>); typedef NativeVeryLargeStructSum = Int64 Function(Pointer<VeryLargeStruct>);
void testFunctionWithVeryLargeStruct() { void testFunctionWithVeryLargeStruct() {
ffi.Pointer<ffi.NativeFunction<NativeVeryLargeStructSum>> p1 = Pointer<NativeFunction<NativeVeryLargeStructSum>> p1 =
ffiTestFunctions.lookup("SumVeryLargeStruct"); ffiTestFunctions.lookup("SumVeryLargeStruct");
VeryLargeStructSum f = p1.asFunction(); VeryLargeStructSum f = p1.asFunction();
VeryLargeStruct vls1 = Pointer<VeryLargeStruct>.allocate(count: 2).load(); VeryLargeStruct vls1 = Pointer<VeryLargeStruct>.allocate(count: 2).ref;
VeryLargeStruct vls2 = vls1.addressOf.elementAt(1).load(); VeryLargeStruct vls2 = vls1.addressOf[1];
List<VeryLargeStruct> structs = [vls1, vls2]; List<VeryLargeStruct> structs = [vls1, vls2];
for (VeryLargeStruct struct in structs) { for (VeryLargeStruct struct in structs) {
struct.a = 1; struct.a = 1;
@ -108,9 +106,9 @@ void testFunctionWithVeryLargeStruct() {
vls1.numChildren = 2; vls1.numChildren = 2;
vls1.children = vls1.addressOf; vls1.children = vls1.addressOf;
vls2.parent = vls2.addressOf; vls2.parent = vls2.addressOf;
vls2.parent = ffi.nullptr.cast(); vls2.parent = nullptr.cast();
vls2.numChildren = 0; vls2.numChildren = 0;
vls2.children = ffi.nullptr.cast(); vls2.children = nullptr.cast();
int result = f(vls1.addressOf); int result = f(vls1.addressOf);
Expect.equals(2051, result); Expect.equals(2051, result);

View file

@ -15,8 +15,7 @@
library FfiTest; library FfiTest;
import 'dart:ffi' as ffi; import 'dart:ffi';
import 'dart:ffi' show Pointer;
import 'dylib_utils.dart'; import 'dylib_utils.dart';
@ -47,27 +46,24 @@ void main() {
} }
} }
ffi.DynamicLibrary ffiTestFunctions = DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
dlopenPlatformSpecific("ffi_test_functions");
typedef NativeBinaryOp = ffi.Int32 Function(ffi.Int32, ffi.Int32); typedef NativeBinaryOp = Int32 Function(Int32, Int32);
typedef UnaryOp = int Function(int); typedef UnaryOp = int Function(int);
typedef BinaryOp = int Function(int, int); typedef BinaryOp = int Function(int, int);
typedef GenericBinaryOp<T> = int Function(int, T); typedef GenericBinaryOp<T> = int Function(int, T);
void testNativeFunctionFromCast() { void testNativeFunctionFromCast() {
ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate(); Pointer<IntPtr> p1 = Pointer.allocate();
ffi.Pointer<ffi.NativeFunction<NativeBinaryOp>> p2 = p1.cast(); Pointer<NativeFunction<NativeBinaryOp>> p2 = p1.cast();
p2.asFunction<BinaryOp>(); p2.asFunction<BinaryOp>();
p2.asFunction<GenericBinaryOp<int>>(); p2.asFunction<GenericBinaryOp<int>>();
p1.free(); p1.free();
} }
typedef NativeQuadOpSigned = ffi.Int64 Function( typedef NativeQuadOpSigned = Int64 Function(Int8, Int16, Int32, Int64);
ffi.Int8, ffi.Int16, ffi.Int32, ffi.Int64);
typedef QuadOp = int Function(int, int, int, int); typedef QuadOp = int Function(int, int, int, int);
typedef NativeQuadOpUnsigned = ffi.Uint64 Function( typedef NativeQuadOpUnsigned = Uint64 Function(Uint8, Uint16, Uint32, Uint64);
ffi.Uint8, ffi.Uint16, ffi.Uint32, ffi.Uint64);
BinaryOp sumPlus42 = BinaryOp sumPlus42 =
ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42"); ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42");
@ -86,76 +82,76 @@ void testNativeFunctionFromLookup() {
-0x8000000000000000, intComputation(0, 0, 0, -0x8000000000000000)); -0x8000000000000000, intComputation(0, 0, 0, -0x8000000000000000));
} }
typedef NativeReturnMaxUint8 = ffi.Uint8 Function(); typedef NativeReturnMaxUint8 = Uint8 Function();
int Function() returnMaxUint8 = ffiTestFunctions int Function() returnMaxUint8 = ffiTestFunctions
.lookup("ReturnMaxUint8") .lookup("ReturnMaxUint8")
.cast<ffi.NativeFunction<NativeReturnMaxUint8>>() .cast<NativeFunction<NativeReturnMaxUint8>>()
.asFunction(); .asFunction();
typedef NativeReturnMaxUint16 = ffi.Uint16 Function(); typedef NativeReturnMaxUint16 = Uint16 Function();
int Function() returnMaxUint16 = ffiTestFunctions int Function() returnMaxUint16 = ffiTestFunctions
.lookup("ReturnMaxUint16") .lookup("ReturnMaxUint16")
.cast<ffi.NativeFunction<NativeReturnMaxUint16>>() .cast<NativeFunction<NativeReturnMaxUint16>>()
.asFunction(); .asFunction();
typedef NativeReturnMaxUint32 = ffi.Uint32 Function(); typedef NativeReturnMaxUint32 = Uint32 Function();
int Function() returnMaxUint32 = ffiTestFunctions int Function() returnMaxUint32 = ffiTestFunctions
.lookup("ReturnMaxUint32") .lookup("ReturnMaxUint32")
.cast<ffi.NativeFunction<NativeReturnMaxUint32>>() .cast<NativeFunction<NativeReturnMaxUint32>>()
.asFunction(); .asFunction();
typedef NativeReturnMinInt8 = ffi.Int8 Function(); typedef NativeReturnMinInt8 = Int8 Function();
int Function() returnMinInt8 = ffiTestFunctions int Function() returnMinInt8 = ffiTestFunctions
.lookup("ReturnMinInt8") .lookup("ReturnMinInt8")
.cast<ffi.NativeFunction<NativeReturnMinInt8>>() .cast<NativeFunction<NativeReturnMinInt8>>()
.asFunction(); .asFunction();
typedef NativeReturnMinInt16 = ffi.Int16 Function(); typedef NativeReturnMinInt16 = Int16 Function();
int Function() returnMinInt16 = ffiTestFunctions int Function() returnMinInt16 = ffiTestFunctions
.lookup("ReturnMinInt16") .lookup("ReturnMinInt16")
.cast<ffi.NativeFunction<NativeReturnMinInt16>>() .cast<NativeFunction<NativeReturnMinInt16>>()
.asFunction(); .asFunction();
typedef NativeReturnMinInt32 = ffi.Int32 Function(); typedef NativeReturnMinInt32 = Int32 Function();
int Function() returnMinInt32 = ffiTestFunctions int Function() returnMinInt32 = ffiTestFunctions
.lookup("ReturnMinInt32") .lookup("ReturnMinInt32")
.cast<ffi.NativeFunction<NativeReturnMinInt32>>() .cast<NativeFunction<NativeReturnMinInt32>>()
.asFunction(); .asFunction();
typedef NativeTakeMaxUint8 = ffi.IntPtr Function(ffi.Uint8); typedef NativeTakeMaxUint8 = IntPtr Function(Uint8);
int Function(int) takeMaxUint8 = ffiTestFunctions int Function(int) takeMaxUint8 = ffiTestFunctions
.lookup("TakeMaxUint8") .lookup("TakeMaxUint8")
.cast<ffi.NativeFunction<NativeTakeMaxUint8>>() .cast<NativeFunction<NativeTakeMaxUint8>>()
.asFunction(); .asFunction();
typedef NativeTakeMaxUint16 = ffi.IntPtr Function(ffi.Uint16); typedef NativeTakeMaxUint16 = IntPtr Function(Uint16);
int Function(int) takeMaxUint16 = ffiTestFunctions int Function(int) takeMaxUint16 = ffiTestFunctions
.lookup("TakeMaxUint16") .lookup("TakeMaxUint16")
.cast<ffi.NativeFunction<NativeTakeMaxUint16>>() .cast<NativeFunction<NativeTakeMaxUint16>>()
.asFunction(); .asFunction();
typedef NativeTakeMaxUint32 = ffi.IntPtr Function(ffi.Uint32); typedef NativeTakeMaxUint32 = IntPtr Function(Uint32);
int Function(int) takeMaxUint32 = ffiTestFunctions int Function(int) takeMaxUint32 = ffiTestFunctions
.lookup("TakeMaxUint32") .lookup("TakeMaxUint32")
.cast<ffi.NativeFunction<NativeTakeMaxUint32>>() .cast<NativeFunction<NativeTakeMaxUint32>>()
.asFunction(); .asFunction();
typedef NativeTakeMinInt8 = ffi.IntPtr Function(ffi.Int8); typedef NativeTakeMinInt8 = IntPtr Function(Int8);
int Function(int) takeMinInt8 = ffiTestFunctions int Function(int) takeMinInt8 = ffiTestFunctions
.lookup("TakeMinInt8") .lookup("TakeMinInt8")
.cast<ffi.NativeFunction<NativeTakeMinInt8>>() .cast<NativeFunction<NativeTakeMinInt8>>()
.asFunction(); .asFunction();
typedef NativeTakeMinInt16 = ffi.IntPtr Function(ffi.Int16); typedef NativeTakeMinInt16 = IntPtr Function(Int16);
int Function(int) takeMinInt16 = ffiTestFunctions int Function(int) takeMinInt16 = ffiTestFunctions
.lookup("TakeMinInt16") .lookup("TakeMinInt16")
.cast<ffi.NativeFunction<NativeTakeMinInt16>>() .cast<NativeFunction<NativeTakeMinInt16>>()
.asFunction(); .asFunction();
typedef NativeTakeMinInt32 = ffi.IntPtr Function(ffi.Int32); typedef NativeTakeMinInt32 = IntPtr Function(Int32);
int Function(int) takeMinInt32 = ffiTestFunctions int Function(int) takeMinInt32 = ffiTestFunctions
.lookup("TakeMinInt32") .lookup("TakeMinInt32")
.cast<ffi.NativeFunction<NativeTakeMinInt32>>() .cast<NativeFunction<NativeTakeMinInt32>>()
.asFunction(); .asFunction();
void testExtension() { void testExtension() {
@ -188,8 +184,8 @@ void test64bitInterpretations() {
Expect.equals(-1, uintComputation(0, 0, 0, -1)); Expect.equals(-1, uintComputation(0, 0, 0, -1));
} }
typedef NativeSenaryOp = ffi.Int64 Function( typedef NativeSenaryOp = Int64 Function(
ffi.Int8, ffi.Int16, ffi.Int32, ffi.Uint8, ffi.Uint16, ffi.Uint32); Int8, Int16, Int32, Uint8, Uint16, Uint32);
typedef SenaryOp = int Function(int, int, int, int, int, int); typedef SenaryOp = int Function(int, int, int, int, int, int);
SenaryOp sumSmallNumbers = ffiTestFunctions SenaryOp sumSmallNumbers = ffiTestFunctions
@ -213,7 +209,7 @@ void testTruncation() {
Expect.equals(0xFFFFFFFF, sumSmallNumbers(0, 0, 0, 0, 0, -1)); Expect.equals(0xFFFFFFFF, sumSmallNumbers(0, 0, 0, 0, 0, -1));
} }
typedef NativeDoubleUnaryOp = ffi.Double Function(ffi.Double); typedef NativeDoubleUnaryOp = Double Function(Double);
typedef DoubleUnaryOp = double Function(double); typedef DoubleUnaryOp = double Function(double);
DoubleUnaryOp times1_337Double = ffiTestFunctions DoubleUnaryOp times1_337Double = ffiTestFunctions
@ -223,7 +219,7 @@ void testNativeFunctionDoubles() {
Expect.approxEquals(2.0 * 1.337, times1_337Double(2.0)); Expect.approxEquals(2.0 * 1.337, times1_337Double(2.0));
} }
typedef NativeFloatUnaryOp = ffi.Float Function(ffi.Float); typedef NativeFloatUnaryOp = Float Function(Float);
DoubleUnaryOp times1_337Float = ffiTestFunctions DoubleUnaryOp times1_337Float = ffiTestFunctions
.lookupFunction<NativeFloatUnaryOp, DoubleUnaryOp>("Times1_337Float"); .lookupFunction<NativeFloatUnaryOp, DoubleUnaryOp>("Times1_337Float");
@ -232,17 +228,8 @@ void testNativeFunctionFloats() {
Expect.approxEquals(1337.0, times1_337Float(1000.0)); Expect.approxEquals(1337.0, times1_337Float(1000.0));
} }
typedef NativeDecenaryOp = ffi.IntPtr Function( typedef NativeDecenaryOp = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr,
ffi.IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr);
typedef DecenaryOp = int Function( typedef DecenaryOp = int Function(
int, int, int, int, int, int, int, int, int, int); int, int, int, int, int, int, int, int, int, int);
@ -253,18 +240,8 @@ void testNativeFunctionManyArguments1() {
Expect.equals(55, sumManyInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); Expect.equals(55, sumManyInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
} }
typedef NativeUndenaryOp = ffi.IntPtr Function( typedef NativeUndenaryOp = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr,
ffi.IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr,
ffi.IntPtr);
typedef UndenaryOp = int Function( typedef UndenaryOp = int Function(
int, int, int, int, int, int, int, int, int, int, int); int, int, int, int, int, int, int, int, int, int, int);
@ -275,17 +252,8 @@ void testNativeFunctionManyArguments4() {
Expect.equals(66, sumManyIntsOdd(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); Expect.equals(66, sumManyIntsOdd(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
} }
typedef NativeDoubleDecenaryOp = ffi.Double Function( typedef NativeDoubleDecenaryOp = Double Function(Double, Double, Double, Double,
ffi.Double, Double, Double, Double, Double, Double, Double);
ffi.Double,
ffi.Double,
ffi.Double,
ffi.Double,
ffi.Double,
ffi.Double,
ffi.Double,
ffi.Double,
ffi.Double);
typedef DoubleDecenaryOp = double Function(double, double, double, double, typedef DoubleDecenaryOp = double Function(double, double, double, double,
double, double, double, double, double, double); double, double, double, double, double, double);
@ -297,27 +265,27 @@ void testNativeFunctionManyArguments2() {
55.0, sumManyDoubles(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); 55.0, sumManyDoubles(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0));
} }
typedef NativeVigesimalOp = ffi.Double Function( typedef NativeVigesimalOp = Double Function(
ffi.IntPtr, IntPtr,
ffi.Float, Float,
ffi.IntPtr, IntPtr,
ffi.Double, Double,
ffi.IntPtr, IntPtr,
ffi.Float, Float,
ffi.IntPtr, IntPtr,
ffi.Double, Double,
ffi.IntPtr, IntPtr,
ffi.Float, Float,
ffi.IntPtr, IntPtr,
ffi.Double, Double,
ffi.IntPtr, IntPtr,
ffi.Float, Float,
ffi.IntPtr, IntPtr,
ffi.Double, Double,
ffi.IntPtr, IntPtr,
ffi.Float, Float,
ffi.IntPtr, IntPtr,
ffi.Double); Double);
typedef VigesimalOp = double Function( typedef VigesimalOp = double Function(
int, int,
double, double,
@ -350,19 +318,18 @@ void testNativeFunctionManyArguments3() {
14.0, 15, 16.0, 17, 18.0, 19, 20.0)); 14.0, 15, 16.0, 17, 18.0, 19, 20.0));
} }
typedef Int64PointerUnOp = ffi.Pointer<ffi.Int64> Function( typedef Int64PointerUnOp = Pointer<Int64> Function(Pointer<Int64>);
ffi.Pointer<ffi.Int64>);
Int64PointerUnOp assign1337Index1 = ffiTestFunctions Int64PointerUnOp assign1337Index1 = ffiTestFunctions
.lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1"); .lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
void testNativeFunctionPointer() { void testNativeFunctionPointer() {
ffi.Pointer<ffi.Int64> p2 = Pointer.allocate(count: 2); Pointer<Int64> p2 = Pointer.allocate(count: 2);
p2.store(42); p2.value = 42;
p2.elementAt(1).store(1000); p2[1] = 1000;
ffi.Pointer<ffi.Int64> result = assign1337Index1(p2); Pointer<Int64> result = assign1337Index1(p2);
Expect.equals(1337, result.load<int>()); Expect.equals(1337, result.value);
Expect.equals(1337, p2.elementAt(1).load<int>()); Expect.equals(1337, p2[1]);
Expect.equals(p2.elementAt(1).address, result.address); Expect.equals(p2.elementAt(1).address, result.address);
p2.free(); p2.free();
} }
@ -387,24 +354,24 @@ Int64PointerUnOp nullableInt64ElemAt1 = ffiTestFunctions
.lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("NullableInt64ElemAt1"); .lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("NullableInt64ElemAt1");
void testNullPointers() { void testNullPointers() {
Pointer<ffi.Int64> result = nullableInt64ElemAt1(ffi.nullptr.cast()); Pointer<Int64> result = nullableInt64ElemAt1(nullptr.cast());
Expect.equals(result, ffi.nullptr); Expect.equals(result, nullptr);
Pointer<ffi.Int64> p2 = Pointer.allocate(count: 2); Pointer<Int64> p2 = Pointer.allocate(count: 2);
result = nullableInt64ElemAt1(p2); result = nullableInt64ElemAt1(p2);
Expect.notEquals(result, ffi.nullptr); Expect.notEquals(result, nullptr);
p2.free(); p2.free();
} }
typedef NativeFloatPointerToBool = ffi.Uint8 Function(ffi.Pointer<ffi.Float>); typedef NativeFloatPointerToBool = Uint8 Function(Pointer<Float>);
typedef FloatPointerToBool = int Function(ffi.Pointer<ffi.Float>); typedef FloatPointerToBool = int Function(Pointer<Float>);
FloatPointerToBool isRoughly1337 = ffiTestFunctions.lookupFunction< FloatPointerToBool isRoughly1337 = ffiTestFunctions.lookupFunction<
NativeFloatPointerToBool, FloatPointerToBool>("IsRoughly1337"); NativeFloatPointerToBool, FloatPointerToBool>("IsRoughly1337");
void testFloatRounding() { void testFloatRounding() {
Pointer<ffi.Float> p2 = Pointer.allocate(); Pointer<Float> p2 = Pointer.allocate();
p2.store(1337.0); p2.value = 1337.0;
int result = isRoughly1337(p2); int result = isRoughly1337(p2);
Expect.equals(1, result); Expect.equals(1, result);
@ -412,7 +379,7 @@ void testFloatRounding() {
p2.free(); p2.free();
} }
typedef NativeFloatToVoid = ffi.Void Function(ffi.Float); typedef NativeFloatToVoid = Void Function(Float);
typedef DoubleToVoid = void Function(double); typedef DoubleToVoid = void Function(double);
DoubleToVoid devNullFloat = ffiTestFunctions DoubleToVoid devNullFloat = ffiTestFunctions
@ -426,7 +393,7 @@ void testVoidReturn() {
Expect.isNull(result); Expect.isNull(result);
} }
typedef NativeVoidToFloat = ffi.Float Function(); typedef NativeVoidToFloat = Float Function();
typedef VoidToDouble = double Function(); typedef VoidToDouble = double Function();
VoidToDouble inventFloatValue = ffiTestFunctions VoidToDouble inventFloatValue = ffiTestFunctions

View file

@ -15,8 +15,8 @@
// Note #2: When we switch to extension methods we will _only_ use the static // Note #2: When we switch to extension methods we will _only_ use the static
// type of the container. // type of the container.
// //
// ===== a.store(b) ====== // ===== a.value = b ======
// Does a.store(b), where a and b have specific static and dynamic types: run // Does a.value = b, where a and b have specific static and dynamic types: run
// fine, fail at compile time, or fail at runtime? // fine, fail at compile time, or fail at runtime?
// ======================= // =======================
// b P<I>//P<I> P<NT>//P<I> P<NT>//P<NT> // b P<I>//P<I> P<NT>//P<I> P<NT>//P<NT>
@ -29,11 +29,11 @@
// //
// P<P<NT>>//P<P<NT>> 7 ok 8 ok 9 ok // P<P<NT>>//P<P<NT>> 7 ok 8 ok 9 ok
// //
// ====== final c = a.load() ====== // ====== final c = a.value ======
// What is the (inferred) static type and runtime type of `a.load()`. Note that // What is the (inferred) static type and runtime type of `a.value`. Note that
// we assume extension method here: on Pointer<PointerT>> { Pointer<T> load(); } // we assume extension method here: on Pointer<PointerT>> { Pointer<T> load(); }
// ================================ // ================================
// a a.load() // a a.value
// inferred static type*//runtime type // inferred static type*//runtime type
// P<P<I>>//P<P<I>> P<I>//P<I> // P<P<I>>//P<P<I>> P<I>//P<I>
// //
@ -43,8 +43,8 @@
// //
// * The inferred static type when we get extension methods. // * The inferred static type when we get extension methods.
// //
// ====== b = a.load() ====== // ====== b = a.value ======
// What happens when we try to assign the result of a.load() to variable b with // What happens when we try to assign the result of a.value to variable b with
// a specific static type: runs fine, fails at compile time, or fails at runtime. // a specific static type: runs fine, fails at compile time, or fails at runtime.
// ========================== // ==========================
// b P<I> P<NT> // b P<I> P<NT>
@ -64,13 +64,13 @@ import 'dart:ffi';
import "package:expect/expect.dart"; import "package:expect/expect.dart";
// ===== a.store(b) ====== // ===== a.value = b ======
// The tests follow table cells left to right, top to bottom. // The tests follow table cells left to right, top to bottom.
void store1() { void store1() {
final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate(); final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate();
final Pointer<Int8> b = Pointer<Int8>.allocate(); final Pointer<Int8> b = Pointer<Int8>.allocate();
a.store(b); a.value = b;
a.free(); a.free();
b.free(); b.free();
@ -81,8 +81,9 @@ void store2() {
final Pointer<NativeType> b = final Pointer<NativeType> b =
Pointer<Int8>.allocate(); // Reified Pointer<Int8> at runtime. Pointer<Int8>.allocate(); // Reified Pointer<Int8> at runtime.
// We disable implicit downcasts, they will go away when NNBD lands. // Successful implicit downcast of argument at runtime.
a.store(b); //# 1: compile-time error // Should succeed now, should statically be rejected when NNBD lands.
a.value = b;
a.free(); a.free();
b.free(); b.free();
@ -93,8 +94,11 @@ void store3() {
final Pointer<NativeType> b = final Pointer<NativeType> b =
Pointer<Int8>.allocate().cast<Pointer<NativeType>>(); Pointer<Int8>.allocate().cast<Pointer<NativeType>>();
// We disable implicit downcasts, they will go away when NNBD lands. // Failing implicit downcast of argument at runtime.
a.store(b); //# 2: compile-time error // Should fail now at runtime, should statically be rejected when NNBD lands.
Expect.throws(() {
a.value = b;
});
a.free(); a.free();
b.free(); b.free();
@ -106,7 +110,7 @@ void store4() {
final Pointer<Int8> b = Pointer<Int8>.allocate(); final Pointer<Int8> b = Pointer<Int8>.allocate();
a.store(b); a.value = b;
a.free(); a.free();
b.free(); b.free();
@ -119,7 +123,7 @@ void store5() {
final Pointer<NativeType> b = final Pointer<NativeType> b =
Pointer<Int8>.allocate(); // Reified as Pointer<Int8> at runtime. Pointer<Int8>.allocate(); // Reified as Pointer<Int8> at runtime.
a.store(b); a.value = b;
a.free(); a.free();
b.free(); b.free();
@ -133,7 +137,7 @@ void store6() {
// Fails on type check of argument. // Fails on type check of argument.
Expect.throws(() { Expect.throws(() {
a.store(b); a.value = b;
}); });
a.free(); a.free();
@ -145,7 +149,7 @@ void store7() {
Pointer<Pointer<NativeType>>.allocate(); Pointer<Pointer<NativeType>>.allocate();
final Pointer<Int8> b = Pointer<Int8>.allocate(); final Pointer<Int8> b = Pointer<Int8>.allocate();
a.store(b); a.value = b;
a.free(); a.free();
b.free(); b.free();
@ -158,7 +162,7 @@ void store8() {
// Reified as Pointer<Int8> at runtime. // Reified as Pointer<Int8> at runtime.
final Pointer<NativeType> b = Pointer<Int8>.allocate(); final Pointer<NativeType> b = Pointer<Int8>.allocate();
a.store(b); a.value = b;
a.free(); a.free();
b.free(); b.free();
@ -170,18 +174,18 @@ void store9() {
final Pointer<NativeType> b = final Pointer<NativeType> b =
Pointer<Int8>.allocate().cast<Pointer<NativeType>>(); Pointer<Int8>.allocate().cast<Pointer<NativeType>>();
a.store(b); a.value = b;
a.free(); a.free();
b.free(); b.free();
} }
// ====== b = a.load() ====== // ====== b = a.value ======
// The tests follow table cells left to right, top to bottom. // The tests follow table cells left to right, top to bottom.
void load1() { void load1() {
final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate(); final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate();
Pointer<Int8> b = a.load(); Pointer<Int8> b = a.value;
Expect.type<Pointer<Int8>>(b); Expect.type<Pointer<Int8>>(b);
a.free(); a.free();
@ -190,7 +194,7 @@ void load1() {
void load2() { void load2() {
final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate(); final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate();
Pointer<NativeType> b = a.load<Pointer<Int8>>(); Pointer<NativeType> b = a.value;
Expect.type<Pointer<Int8>>(b); Expect.type<Pointer<Int8>>(b);
a.free(); a.free();
@ -200,7 +204,7 @@ void load3() {
// Reified as Pointer<Pointer<Int8>> at runtime. // Reified as Pointer<Pointer<Int8>> at runtime.
final Pointer<Pointer<NativeType>> a = Pointer<Pointer<Int8>>.allocate(); final Pointer<Pointer<NativeType>> a = Pointer<Pointer<Int8>>.allocate();
Pointer<Int8> b = a.load<Pointer<NativeType>>(); Pointer<Int8> b = a.value;
Expect.type<Pointer<Int8>>(b); Expect.type<Pointer<Int8>>(b);
a.free(); a.free();
@ -211,7 +215,7 @@ void load4() {
final Pointer<Pointer<NativeType>> a = Pointer<Pointer<Int8>>.allocate(); final Pointer<Pointer<NativeType>> a = Pointer<Pointer<Int8>>.allocate();
// Return value runtime type is Pointer<Int8>. // Return value runtime type is Pointer<Int8>.
Pointer<NativeType> b = a.load(); Pointer<NativeType> b = a.value;
Expect.type<Pointer<Int8>>(b); Expect.type<Pointer<Int8>>(b);
a.free(); a.free();
@ -224,7 +228,7 @@ void load5() {
// Failing implicit downcast of return value at runtime. // Failing implicit downcast of return value at runtime.
// Should fail now at runtime, should statically be rejected when NNBD lands. // Should fail now at runtime, should statically be rejected when NNBD lands.
Expect.throws(() { Expect.throws(() {
Pointer<Int8> b = a.load<Pointer<NativeType>>(); Pointer<Int8> b = a.value;
}); });
a.free(); a.free();
@ -234,7 +238,7 @@ void load6() {
final Pointer<Pointer<NativeType>> a = final Pointer<Pointer<NativeType>> a =
Pointer<Pointer<NativeType>>.allocate(); Pointer<Pointer<NativeType>>.allocate();
Pointer<NativeType> b = a.load(); Pointer<NativeType> b = a.value;
Expect.type<Pointer<NativeType>>(b); Expect.type<Pointer<NativeType>>(b);
a.free(); a.free();

View file

@ -8,8 +8,7 @@
library FfiTest; library FfiTest;
import 'dart:ffi' as ffi; import 'dart:ffi';
import 'dart:ffi' show Pointer;
import 'dylib_utils.dart'; import 'dylib_utils.dart';
@ -47,29 +46,29 @@ void main() {
testNativeFunctionSignatureInvalidOptionalPositional(); testNativeFunctionSignatureInvalidOptionalPositional();
} }
typedef Int8UnOp = ffi.Int8 Function(ffi.Int8); typedef Int8UnOp = Int8 Function(Int8);
typedef IntUnOp = int Function(int); typedef IntUnOp = int Function(int);
void testGetGeneric() { void testGetGeneric() {
int generic(ffi.Pointer p) { int generic(Pointer p) {
int result; int result;
result = p.load<int>(); //# 20: compile-time error result = p.value; //# 20: compile-time error
return result; return result;
} }
ffi.Pointer<ffi.Int8> p = Pointer.allocate(); Pointer<Int8> p = Pointer.allocate();
p.store(123); p.value = 123;
ffi.Pointer loseType = p; Pointer loseType = p;
generic(loseType); generic(loseType);
p.free(); p.free();
} }
void testGetGeneric2() { void testGetGeneric2() {
T generic<T extends Object>() { T generic<T extends Object>() {
Pointer<ffi.Int8> p = Pointer.allocate(); Pointer<Int8> p = Pointer.allocate();
p.store(123); p.value = 123;
T result; T result;
result = p.load<T>(); //# 21: compile-time error result = p.value; //# 21: compile-time error
p.free(); p.free();
return result; return result;
} }
@ -78,50 +77,50 @@ void testGetGeneric2() {
} }
void testGetVoid() { void testGetVoid() {
ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate(); Pointer<IntPtr> p1 = Pointer.allocate();
ffi.Pointer<ffi.Void> p2 = p1.cast(); Pointer<Void> p2 = p1.cast();
p2.load<int>(); //# 22: compile-time error p2.value; //# 22: compile-time error
p1.free(); p1.free();
} }
void testGetNativeFunction() { void testGetNativeFunction() {
Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
IntUnOp f = p.load(); //# 23: compile-time error IntUnOp f = p.value; //# 23: compile-time error
} }
void testGetNativeType() { void testGetNativeType() {
// Is it possible to obtain a ffi.Pointer<ffi.NativeType> at all? // Is it possible to obtain a Pointer<NativeType> at all?
} }
void testGetTypeMismatch() { void testGetTypeMismatch() {
ffi.Pointer<ffi.Pointer<ffi.Int16>> p = Pointer.allocate(); Pointer<Pointer<Int16>> p = Pointer.allocate();
ffi.Pointer<ffi.Int16> typedNull = ffi.nullptr.cast(); Pointer<Int16> typedNull = nullptr.cast();
p.store(typedNull); p.value = typedNull;
// this fails to compile due to type mismatch // this fails to compile due to type mismatch
ffi.Pointer<ffi.Int8> p2 = p.load(); //# 25: compile-time error Pointer<Int8> p2 = p.value; //# 25: compile-time error
p.free(); p.free();
} }
void testSetGeneric() { void testSetGeneric() {
void generic(ffi.Pointer p) { void generic(Pointer p) {
p.store(123); //# 26: compile-time error p.value = 123; //# 26: compile-time error
} }
ffi.Pointer<ffi.Int8> p = Pointer.allocate(); Pointer<Int8> p = Pointer.allocate();
p.store(123); p.value = 123;
ffi.Pointer loseType = p; Pointer loseType = p;
generic(loseType); generic(loseType);
p.free(); p.free();
} }
void testSetGeneric2() { void testSetGeneric2() {
void generic<T extends Object>(T arg) { void generic<T extends Object>(T arg) {
ffi.Pointer<ffi.Int8> p = Pointer.allocate(); Pointer<Int8> p = Pointer.allocate();
p.store(arg); //# 27: compile-time error p.value = arg; //# 27: compile-time error
p.free(); p.free();
} }
@ -129,33 +128,33 @@ void testSetGeneric2() {
} }
void testSetVoid() { void testSetVoid() {
ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate(); Pointer<IntPtr> p1 = Pointer.allocate();
ffi.Pointer<ffi.Void> p2 = p1.cast(); Pointer<Void> p2 = p1.cast();
p2.store(1234); //# 28: compile-time error p2.value = 1234; //# 28: compile-time error
p1.free(); p1.free();
} }
void testSetNativeFunction() { void testSetNativeFunction() {
Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
IntUnOp f = (a) => a + 1; IntUnOp f = (a) => a + 1;
p.store(f); //# 29: compile-time error p.value = f; //# 29: compile-time error
} }
void testSetNativeType() { void testSetNativeType() {
// Is it possible to obtain a ffi.Pointer<ffi.NativeType> at all? // Is it possible to obtain a Pointer<NativeType> at all?
} }
void testSetTypeMismatch() { void testSetTypeMismatch() {
// the pointer to pointer types must match up // the pointer to pointer types must match up
ffi.Pointer<ffi.Int8> pHelper = Pointer.allocate(); Pointer<Int8> pHelper = Pointer.allocate();
pHelper.store(123); pHelper.value = 123;
ffi.Pointer<ffi.Pointer<ffi.Int16>> p = Pointer.allocate(); Pointer<Pointer<Int16>> p = Pointer.allocate();
// this fails to compile due to type mismatch // this fails to compile due to type mismatch
p.store(pHelper); //# 40: compile-time error p.value = pHelper; //# 40: compile-time error
pHelper.free(); pHelper.free();
p.free(); p.free();
@ -163,7 +162,7 @@ void testSetTypeMismatch() {
void testAsFunctionGeneric() { void testAsFunctionGeneric() {
T generic<T extends Function>() { T generic<T extends Function>() {
ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
Function f; Function f;
f = p.asFunction<T>(); //# 11: compile-time error f = p.asFunction<T>(); //# 11: compile-time error
return f; return f;
@ -173,29 +172,29 @@ void testAsFunctionGeneric() {
} }
void testAsFunctionGeneric2() { void testAsFunctionGeneric2() {
generic(ffi.Pointer<ffi.NativeFunction> p) { generic(Pointer<NativeFunction> p) {
Function f; Function f;
f = p.asFunction<IntUnOp>(); //# 12: compile-time error f = p.asFunction<IntUnOp>(); //# 12: compile-time error
return f; return f;
} }
ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
generic(p); generic(p);
} }
void testAsFunctionWrongNativeFunctionSignature() { void testAsFunctionWrongNativeFunctionSignature() {
ffi.Pointer<ffi.NativeFunction<IntUnOp>> p; Pointer<NativeFunction<IntUnOp>> p;
Function f = p.asFunction<IntUnOp>(); //# 13: compile-time error Function f = p.asFunction<IntUnOp>(); //# 13: compile-time error
} }
typedef IntBinOp = int Function(int, int); typedef IntBinOp = int Function(int, int);
void testAsFunctionTypeMismatch() { void testAsFunctionTypeMismatch() {
ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337); Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
IntBinOp f = p.asFunction(); //# 14: compile-time error IntBinOp f = p.asFunction(); //# 14: compile-time error
} }
typedef NativeDoubleUnOp = ffi.Double Function(ffi.Double); typedef NativeDoubleUnOp = Double Function(Double);
typedef DoubleUnOp = double Function(double); typedef DoubleUnOp = double Function(double);
double myTimesThree(double d) => d * 3; double myTimesThree(double d) => d * 3;
@ -203,9 +202,9 @@ double myTimesThree(double d) => d * 3;
int myTimesFour(int i) => i * 4; int myTimesFour(int i) => i * 4;
void testFromFunctionGeneric() { void testFromFunctionGeneric() {
ffi.Pointer<ffi.NativeFunction> generic<T extends Function>(T f) { Pointer<NativeFunction> generic<T extends Function>(T f) {
ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> result; Pointer<NativeFunction<NativeDoubleUnOp>> result;
result = ffi.fromFunction(f); //# 70: compile-time error result = Pointer.fromFunction(f); //# 70: compile-time error
return result; return result;
} }
@ -213,9 +212,9 @@ void testFromFunctionGeneric() {
} }
void testFromFunctionGeneric2() { void testFromFunctionGeneric2() {
ffi.Pointer<ffi.NativeFunction<T>> generic<T extends Function>() { Pointer<NativeFunction<T>> generic<T extends Function>() {
ffi.Pointer<ffi.NativeFunction<T>> result; Pointer<NativeFunction<T>> result;
result = ffi.fromFunction(myTimesThree); //# 71: compile-time error result = Pointer.fromFunction(myTimesThree); //# 71: compile-time error
return result; return result;
} }
@ -223,18 +222,18 @@ void testFromFunctionGeneric2() {
} }
void testFromFunctionWrongNativeFunctionSignature() { void testFromFunctionWrongNativeFunctionSignature() {
ffi.fromFunction<IntUnOp>(myTimesFour); //# 72: compile-time error Pointer.fromFunction<IntUnOp>(myTimesFour); //# 72: compile-time error
} }
void testFromFunctionTypeMismatch() { void testFromFunctionTypeMismatch() {
ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> p; Pointer<NativeFunction<NativeDoubleUnOp>> p;
p = ffi.fromFunction(myTimesFour); //# 73: compile-time error p = Pointer.fromFunction(myTimesFour); //# 73: compile-time error
} }
void testFromFunctionClosure() { void testFromFunctionClosure() {
DoubleUnOp someClosure = (double z) => z / 27.0; DoubleUnOp someClosure = (double z) => z / 27.0;
ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> p; Pointer<NativeFunction<NativeDoubleUnOp>> p;
p = ffi.fromFunction(someClosure); //# 74: compile-time error p = Pointer.fromFunction(someClosure); //# 74: compile-time error
} }
class X { class X {
@ -245,17 +244,18 @@ DoubleUnOp fld = null;
void testFromFunctionTearOff() { void testFromFunctionTearOff() {
fld = X().tearoff; fld = X().tearoff;
ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> p; Pointer<NativeFunction<NativeDoubleUnOp>> p;
p = ffi.fromFunction(fld); //# 75: compile-time error p = Pointer.fromFunction(fld); //# 75: compile-time error
} }
void testFromFunctionAbstract() { void testFromFunctionAbstract() {
ffi.Pointer.fromFunction<Function>(testFromFunctionAbstract); //# 76: compile-time error Pointer.fromFunction<Function>(//# 76: compile-time error
testFromFunctionAbstract); //# 76: compile-time error
} }
void testLookupFunctionGeneric() { void testLookupFunctionGeneric() {
Function generic<T extends Function>() { Function generic<T extends Function>() {
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
Function result; Function result;
result = l.lookupFunction<T, DoubleUnOp>("cos"); //# 15: compile-time error result = l.lookupFunction<T, DoubleUnOp>("cos"); //# 15: compile-time error
return result; return result;
@ -266,7 +266,7 @@ void testLookupFunctionGeneric() {
void testLookupFunctionGeneric2() { void testLookupFunctionGeneric2() {
Function generic<T extends Function>() { Function generic<T extends Function>() {
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
Function result; Function result;
result = //# 16: compile-time error result = //# 16: compile-time error
l.lookupFunction<NativeDoubleUnOp, T>("cos"); //# 16: compile-time error l.lookupFunction<NativeDoubleUnOp, T>("cos"); //# 16: compile-time error
@ -277,40 +277,40 @@ void testLookupFunctionGeneric2() {
} }
void testLookupFunctionWrongNativeFunctionSignature() { void testLookupFunctionWrongNativeFunctionSignature() {
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<IntUnOp, IntUnOp>("cos"); //# 17: compile-time error l.lookupFunction<IntUnOp, IntUnOp>("cos"); //# 17: compile-time error
} }
void testLookupFunctionTypeMismatch() { void testLookupFunctionTypeMismatch() {
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<NativeDoubleUnOp, IntUnOp>("cos"); //# 18: compile-time error l.lookupFunction<NativeDoubleUnOp, IntUnOp>("cos"); //# 18: compile-time error
} }
// TODO(dacoharkes): make the next 4 test compile errors // TODO(dacoharkes): make the next 4 test compile errors
typedef Invalid1 = int Function(ffi.Int8); typedef Invalid1 = int Function(Int8);
typedef Invalid2 = ffi.Int8 Function(int); typedef Invalid2 = Int8 Function(int);
typedef Invalid3 = ffi.Int8 Function({ffi.Int8 named}); typedef Invalid3 = Int8 Function({Int8 named});
typedef Invalid4 = ffi.Int8 Function([ffi.Int8 positional]); typedef Invalid4 = Int8 Function([Int8 positional]);
void testNativeFunctionSignatureInvalidReturn() { void testNativeFunctionSignatureInvalidReturn() {
// ffi.Pointer<ffi.NativeFunction<Invalid1>> p = ffi.fromAddress(999); // Pointer<NativeFunction<Invalid1>> p = fromAddress(999);
} }
void testNativeFunctionSignatureInvalidParam() { void testNativeFunctionSignatureInvalidParam() {
// ffi.Pointer<ffi.NativeFunction<Invalid2>> p = ffi.fromAddress(999); // Pointer<NativeFunction<Invalid2>> p = fromAddress(999);
} }
void testNativeFunctionSignatureInvalidOptionalNamed() { void testNativeFunctionSignatureInvalidOptionalNamed() {
// ffi.Pointer<ffi.NativeFunction<Invalid3>> p = ffi.fromAddress(999); // Pointer<NativeFunction<Invalid3>> p = fromAddress(999);
} }
void testNativeFunctionSignatureInvalidOptionalPositional() { void testNativeFunctionSignatureInvalidOptionalPositional() {
// ffi.Pointer<ffi.NativeFunction<Invalid4>> p = ffi.fromAddress(999); // Pointer<NativeFunction<Invalid4>> p = fromAddress(999);
} }
// error on missing field annotation // error on missing field annotation
class TestStruct extends ffi.Struct<TestStruct> { class TestStruct extends Struct<TestStruct> {
@ffi.Double() @Double()
double x; double x;
double y; //# 50: compile-time error double y; //# 50: compile-time error
@ -320,55 +320,55 @@ class TestStruct extends ffi.Struct<TestStruct> {
class TestStruct3 extends TestStruct {} //# 52: compile-time error class TestStruct3 extends TestStruct {} //# 52: compile-time error
// error on double annotation // error on double annotation
class TestStruct4 extends ffi.Struct<TestStruct4> { class TestStruct4 extends Struct<TestStruct4> {
@ffi.Double() @Double()
@ffi.Double() //# 53: compile-time error @Double() //# 53: compile-time error
double z; double z;
} }
// error on annotation not matching up // error on annotation not matching up
class TestStruct5 extends ffi.Struct<TestStruct5> { class TestStruct5 extends Struct<TestStruct5> {
@ffi.Int64() //# 54: compile-time error @Int64() //# 54: compile-time error
double z; //# 54: compile-time error double z; //# 54: compile-time error
} }
// error on annotation not matching up // error on annotation not matching up
class TestStruct6 extends ffi.Struct<TestStruct6> { class TestStruct6 extends Struct<TestStruct6> {
@ffi.Void() //# 55: compile-time error @Void() //# 55: compile-time error
double z; //# 55: compile-time error double z; //# 55: compile-time error
} }
// error on annotation not matching up // error on annotation not matching up
class TestStruct7 extends ffi.Struct<TestStruct7> { class TestStruct7 extends Struct<TestStruct7> {
@ffi.NativeType() //# 56: compile-time error @NativeType() //# 56: compile-time error
double z; //# 56: compile-time error double z; //# 56: compile-time error
} }
// error on field initializer on field // error on field initializer on field
class TestStruct8 extends ffi.Struct<TestStruct8> { class TestStruct8 extends Struct<TestStruct8> {
@ffi.Double() //# 57: compile-time error @Double() //# 57: compile-time error
double z = 10.0; //# 57: compile-time error double z = 10.0; //# 57: compile-time error
} }
// error on field initializer in constructor // error on field initializer in constructor
class TestStruct9 extends ffi.Struct<TestStruct9> { class TestStruct9 extends Struct<TestStruct9> {
@ffi.Double() @Double()
double z; double z;
TestStruct9() : z = 0.0 {} //# 58: compile-time error TestStruct9() : z = 0.0 {} //# 58: compile-time error
} }
// A struct "C" must extend "Struct<C>", not "Struct<AnythingElse>". // A struct "C" must extend "Struct<C>", not "Struct<AnythingElse>".
class TestStruct10 extends ffi.Struct<ffi.Int8> {} //# 59: compile-time error class TestStruct10 extends Struct<Int8> {} //# 59: compile-time error
// Struct classes may not be generic. // Struct classes may not be generic.
class TestStruct11<T> extends //# 60: compile-time error class TestStruct11<T> extends //# 60: compile-time error
ffi.Struct<TestStruct11<dynamic>> {} //# 60: compile-time error Struct<TestStruct11<dynamic>> {} //# 60: compile-time error
// Structs may not appear inside structs (currently, there is no suitable // Structs may not appear inside structs (currently, there is no suitable
// annotation). // annotation).
class TestStruct12 extends ffi.Struct<TestStruct12> { class TestStruct12 extends Struct<TestStruct12> {
@ffi.Pointer //# 61: compile-time error @Pointer //# 61: compile-time error
TestStruct9 struct; //# 61: compile-time error TestStruct9 struct; //# 61: compile-time error
} }
@ -377,78 +377,78 @@ class DummyAnnotation {
} }
// Structs fields may have other annotations. // Structs fields may have other annotations.
class TestStruct13 extends ffi.Struct<TestStruct13> { class TestStruct13 extends Struct<TestStruct13> {
@DummyAnnotation() @DummyAnnotation()
@ffi.Double() @Double()
double z; double z;
} }
// Cannot extend native types. // Cannot extend native types.
class ENativeType extends ffi.NativeType {} //# 90: compile-time error class ENativeType extends NativeType {} //# 90: compile-time error
class EInt8 extends ffi.Int8 {} //# 91: compile-time error class EInt8 extends Int8 {} //# 91: compile-time error
class EInt16 extends ffi.Int16 {} //# 92: compile-time error class EInt16 extends Int16 {} //# 92: compile-time error
class EInt32 extends ffi.Int32 {} //# 93: compile-time error class EInt32 extends Int32 {} //# 93: compile-time error
class EInt64 extends ffi.Int64 {} //# 94: compile-time error class EInt64 extends Int64 {} //# 94: compile-time error
class EUint8 extends ffi.Uint8 {} //# 95: compile-time error class EUint8 extends Uint8 {} //# 95: compile-time error
class EUint16 extends ffi.Uint16 {} //# 96: compile-time error class EUint16 extends Uint16 {} //# 96: compile-time error
class EUint32 extends ffi.Uint32 {} //# 97: compile-time error class EUint32 extends Uint32 {} //# 97: compile-time error
class EUint64 extends ffi.Uint64 {} //# 98: compile-time error class EUint64 extends Uint64 {} //# 98: compile-time error
class EIntPtr extends ffi.IntPtr {} //# 99: compile-time error class EIntPtr extends IntPtr {} //# 99: compile-time error
class EFloat extends ffi.Float {} //# 910: compile-time error class EFloat extends Float {} //# 910: compile-time error
class EDouble extends ffi.Double {} //# 911: compile-time error class EDouble extends Double {} //# 911: compile-time error
class EVoid extends ffi.Void {} //# 912: compile-time error class EVoid extends Void {} //# 912: compile-time error
class ENativeFunction extends ffi.NativeFunction {} //# 913: compile-time error class ENativeFunction extends NativeFunction {} //# 913: compile-time error
class EPointer extends ffi.Pointer {} //# 914: compile-time error class EPointer extends Pointer {} //# 914: compile-time error
// Cannot implement native natives or Struct. // Cannot implement native natives or Struct.
// Cannot extend native types. // Cannot extend native types.
class INativeType implements ffi.NativeType {} //# 80: compile-time error class INativeType implements NativeType {} //# 80: compile-time error
class IInt8 implements ffi.Int8 {} //# 81: compile-time error class IInt8 implements Int8 {} //# 81: compile-time error
class IInt16 implements ffi.Int16 {} //# 82: compile-time error class IInt16 implements Int16 {} //# 82: compile-time error
class IInt32 implements ffi.Int32 {} //# 83: compile-time error class IInt32 implements Int32 {} //# 83: compile-time error
class IInt64 implements ffi.Int64 {} //# 84: compile-time error class IInt64 implements Int64 {} //# 84: compile-time error
class IUint8 implements ffi.Uint8 {} //# 85: compile-time error class IUint8 implements Uint8 {} //# 85: compile-time error
class IUint16 implements ffi.Uint16 {} //# 86: compile-time error class IUint16 implements Uint16 {} //# 86: compile-time error
class IUint32 implements ffi.Uint32 {} //# 87: compile-time error class IUint32 implements Uint32 {} //# 87: compile-time error
class IUint64 implements ffi.Uint64 {} //# 88: compile-time error class IUint64 implements Uint64 {} //# 88: compile-time error
class IIntPtr implements ffi.IntPtr {} //# 88: compile-time error class IIntPtr implements IntPtr {} //# 88: compile-time error
class IFloat implements ffi.Float {} //# 810: compile-time error class IFloat implements Float {} //# 810: compile-time error
class IDouble implements ffi.Double {} //# 811: compile-time error class IDouble implements Double {} //# 811: compile-time error
class IVoid implements ffi.Void {} //# 812: compile-time error class IVoid implements Void {} //# 812: compile-time error
class INativeFunction //# 813: compile-time error class INativeFunction //# 813: compile-time error
implements //# 813: compile-time error implements //# 813: compile-time error
ffi.NativeFunction {} //# 813: compile-time error NativeFunction {} //# 813: compile-time error
class IPointer implements ffi.Pointer {} //# 814: compile-time error class IPointer implements Pointer {} //# 814: compile-time error
class IStruct implements ffi.Struct {} //# 815: compile-time error class IStruct implements Struct {} //# 815: compile-time error

View file

@ -33,15 +33,15 @@ void testStructAllocate() {
Coordinate.allocate(10.0, 10.0, nullptr.cast()).addressOf; Coordinate.allocate(10.0, 10.0, nullptr.cast()).addressOf;
Pointer<Coordinate> c2 = Coordinate.allocate(20.0, 20.0, c1).addressOf; Pointer<Coordinate> c2 = Coordinate.allocate(20.0, 20.0, c1).addressOf;
Pointer<Coordinate> c3 = Coordinate.allocate(30.0, 30.0, c2).addressOf; Pointer<Coordinate> c3 = Coordinate.allocate(30.0, 30.0, c2).addressOf;
c1.load<Coordinate>().next = c3; c1.ref.next = c3;
Coordinate currentCoordinate = c1.load(); Coordinate currentCoordinate = c1.ref;
Expect.equals(10.0, currentCoordinate.x); Expect.equals(10.0, currentCoordinate.x);
currentCoordinate = currentCoordinate.next.load(); currentCoordinate = currentCoordinate.next.ref;
Expect.equals(30.0, currentCoordinate.x); Expect.equals(30.0, currentCoordinate.x);
currentCoordinate = currentCoordinate.next.load(); currentCoordinate = currentCoordinate.next.ref;
Expect.equals(20.0, currentCoordinate.x); Expect.equals(20.0, currentCoordinate.x);
currentCoordinate = currentCoordinate.next.load(); currentCoordinate = currentCoordinate.next.ref;
Expect.equals(10.0, currentCoordinate.x); Expect.equals(10.0, currentCoordinate.x);
c1.free(); c1.free();
@ -54,23 +54,26 @@ void testStructFromAddress() {
Pointer<Coordinate> c1 = Pointer.allocate(count: 3); Pointer<Coordinate> c1 = Pointer.allocate(count: 3);
Pointer<Coordinate> c2 = c1.elementAt(1); Pointer<Coordinate> c2 = c1.elementAt(1);
Pointer<Coordinate> c3 = c1.elementAt(2); Pointer<Coordinate> c3 = c1.elementAt(2);
c1.load<Coordinate>().x = 10.0; c1.ref
c1.load<Coordinate>().y = 10.0; ..x = 10.0
c1.load<Coordinate>().next = c3; ..y = 10.0
c2.load<Coordinate>().x = 20.0; ..next = c3;
c2.load<Coordinate>().y = 20.0; c2.ref
c2.load<Coordinate>().next = c1; ..x = 20.0
c3.load<Coordinate>().x = 30.0; ..y = 20.0
c3.load<Coordinate>().y = 30.0; ..next = c1;
c3.load<Coordinate>().next = c2; c3.ref
..x = 30.0
..y = 30.0
..next = c2;
Coordinate currentCoordinate = c1.load(); Coordinate currentCoordinate = c1.ref;
Expect.equals(10.0, currentCoordinate.x); Expect.equals(10.0, currentCoordinate.x);
currentCoordinate = currentCoordinate.next.load(); currentCoordinate = currentCoordinate.next.ref;
Expect.equals(30.0, currentCoordinate.x); Expect.equals(30.0, currentCoordinate.x);
currentCoordinate = currentCoordinate.next.load(); currentCoordinate = currentCoordinate.next.ref;
Expect.equals(20.0, currentCoordinate.x); Expect.equals(20.0, currentCoordinate.x);
currentCoordinate = currentCoordinate.next.load(); currentCoordinate = currentCoordinate.next.ref;
Expect.equals(10.0, currentCoordinate.x); Expect.equals(10.0, currentCoordinate.x);
c1.free(); c1.free();
@ -79,11 +82,11 @@ void testStructFromAddress() {
void testStructWithNulls() { void testStructWithNulls() {
Pointer<Coordinate> coordinate = Pointer<Coordinate> coordinate =
Coordinate.allocate(10.0, 10.0, nullptr.cast<Coordinate>()).addressOf; Coordinate.allocate(10.0, 10.0, nullptr.cast<Coordinate>()).addressOf;
Expect.equals(coordinate.load<Coordinate>().next, nullptr); Expect.equals(coordinate.ref.next, nullptr);
coordinate.load<Coordinate>().next = coordinate; coordinate.ref.next = coordinate;
Expect.notEquals(coordinate.load<Coordinate>().next, nullptr); Expect.notEquals(coordinate.ref.next, nullptr);
coordinate.load<Coordinate>().next = nullptr.cast(); coordinate.ref.next = nullptr.cast();
Expect.equals(coordinate.load<Coordinate>().next, nullptr); Expect.equals(coordinate.ref.next, nullptr);
coordinate.free(); coordinate.free();
} }
@ -91,11 +94,11 @@ void testBareStruct() {
int structSize = sizeOf<Double>() * 2 + sizeOf<IntPtr>(); int structSize = sizeOf<Double>() * 2 + sizeOf<IntPtr>();
bare.Coordinate c1 = Pointer<Uint8>.allocate(count: structSize * 3) bare.Coordinate c1 = Pointer<Uint8>.allocate(count: structSize * 3)
.cast<bare.Coordinate>() .cast<bare.Coordinate>()
.load(); .ref;
bare.Coordinate c2 = bare.Coordinate c2 =
c1.addressOf.offsetBy(structSize).cast<bare.Coordinate>().load(); c1.addressOf.offsetBy(structSize).cast<bare.Coordinate>().ref;
bare.Coordinate c3 = bare.Coordinate c3 =
c1.addressOf.offsetBy(structSize * 2).cast<bare.Coordinate>().load(); c1.addressOf.offsetBy(structSize * 2).cast<bare.Coordinate>().ref;
c1.x = 10.0; c1.x = 10.0;
c1.y = 10.0; c1.y = 10.0;
c1.next = c3.addressOf; c1.next = c3.addressOf;
@ -108,11 +111,11 @@ void testBareStruct() {
bare.Coordinate currentCoordinate = c1; bare.Coordinate currentCoordinate = c1;
Expect.equals(10.0, currentCoordinate.x); Expect.equals(10.0, currentCoordinate.x);
currentCoordinate = currentCoordinate.next.load(); currentCoordinate = currentCoordinate.next.ref;
Expect.equals(30.0, currentCoordinate.x); Expect.equals(30.0, currentCoordinate.x);
currentCoordinate = currentCoordinate.next.load(); currentCoordinate = currentCoordinate.next.ref;
Expect.equals(20.0, currentCoordinate.x); Expect.equals(20.0, currentCoordinate.x);
currentCoordinate = currentCoordinate.next.load(); currentCoordinate = currentCoordinate.next.ref;
Expect.equals(10.0, currentCoordinate.x); Expect.equals(10.0, currentCoordinate.x);
c1.addressOf.free(); c1.addressOf.free();

View file

@ -5,19 +5,18 @@
library Utf8; library Utf8;
import 'dart:convert'; import 'dart:convert';
import 'dart:ffi' as ffi; import 'dart:ffi';
import 'dart:ffi' show Pointer;
/// Sample non-struct Pointer wrapper for dart:ffi library. /// Sample non-struct Pointer wrapper for dart:ffi library.
class Utf8 extends ffi.Struct<Utf8> { class Utf8 extends Struct<Utf8> {
@ffi.Uint8() @Uint8()
int char; int char;
static String fromUtf8(Pointer<Utf8> str) { static String fromUtf8(Pointer<Utf8> str) {
List<int> units = []; List<int> units = [];
int len = 0; int len = 0;
while (true) { while (true) {
int char = str.elementAt(len++).load<Utf8>().char; int char = str[len++].char;
if (char == 0) break; if (char == 0) break;
units.add(char); units.add(char);
} }
@ -29,9 +28,9 @@ class Utf8 extends ffi.Struct<Utf8> {
Pointer<Utf8> result = Pointer<Utf8> result =
Pointer<Utf8>.allocate(count: units.length + 1).cast(); Pointer<Utf8>.allocate(count: units.length + 1).cast();
for (int i = 0; i < units.length; i++) { for (int i = 0; i < units.length; i++) {
result.elementAt(i).load<Utf8>().char = units[i]; result[i].char = units[i];
} }
result.elementAt(units.length).load<Utf8>().char = 0; result[units.length].char = 0;
return result; return result;
} }
} }