/// 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('vf_init'); final int Function(int, int) _vfAdd = _lib.lookupFunction( 'vf_add'); final Pointer Function(Pointer) _vfGreet = _lib.lookupFunction< Pointer Function(Pointer), Pointer Function(Pointer)>('vf_greet'); final void Function(Pointer) _vfFree = _lib.lookupFunction), void Function(Pointer)>( '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 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 greetAsync(String name) => Isolate.run(() => greet(name));