1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
/// Idiomatic Dart surface over the V library.
///
/// Callers never see a Pointer, and never own V memory: every string that
/// crosses the boundary is copied into Dart and the V allocation is released
/// before the call returns.
library vflutter_ffi;
import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'package:ffi/ffi.dart';
const String _libName = 'vflutter';
DynamicLibrary _open() {
if (Platform.isMacOS || Platform.isIOS) {
// Static archive linked into the app binary.
return DynamicLibrary.process();
}
if (Platform.isAndroid || Platform.isLinux) {
return DynamicLibrary.open('lib$_libName.so');
}
if (Platform.isWindows) {
return DynamicLibrary.open('$_libName.dll');
}
throw UnsupportedError('vflutter_ffi: unsupported platform');
}
final DynamicLibrary _lib = _open();
final void Function() _vfInit =
_lib.lookupFunction<Void Function(), void Function()>('vf_init');
final int Function(int, int) _vfAdd =
_lib.lookupFunction<Int32 Function(Int32, Int32), int Function(int, int)>(
'vf_add');
final Pointer<Utf8> Function(Pointer<Utf8>) _vfGreet = _lib.lookupFunction<
Pointer<Utf8> Function(Pointer<Utf8>),
Pointer<Utf8> Function(Pointer<Utf8>)>('vf_greet');
final void Function(Pointer<Void>) _vfFree =
_lib.lookupFunction<Void Function(Pointer<Void>), void Function(Pointer<Void>)>(
'vf_free');
bool _ready = false;
/// Initialises the V runtime. Idempotent and cheap; called automatically by
/// every API below, so you rarely need it directly.
void ensureInitialized() {
if (_ready) return;
_vfInit();
_ready = true;
}
/// Adds two integers in V. The trivial case, useful as a liveness check.
int add(int a, int b) {
ensureInitialized();
return _vfAdd(a, b);
}
/// Round-trips a string through V.
///
/// V allocates the result; this function copies it into a Dart [String] and
/// frees the V allocation before returning, so there is nothing to release.
String greet(String name) {
ensureInitialized();
final arg = name.toNativeUtf8();
Pointer<Utf8> res = nullptr;
try {
res = _vfGreet(arg);
if (res == nullptr) {
throw StateError('vf_greet returned null');
}
return res.toDartString();
} finally {
calloc.free(arg);
if (res != nullptr) _vfFree(res.cast());
}
}
/// Runs [greet] on a helper isolate.
///
/// V compiled with `-gc none` has no stop-the-world phase and no thread-local
/// runtime state, so calls are safe from any isolate. Use this for work long
/// enough to jank a frame.
Future<String> greetAsync(String name) =>
Isolate.run(() => greet(name));
|