nandi/vflutter_ffipublic Fork 0
claude/ssh-key-rickub-25a7d3
Commits
Clone
git clone https://git.rickub.com/nandi/vflutter_ffi.git
git clone ssh://git@rickub.com/nandi/vflutter_ffi.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Initial commit: V -> Flutter FFI plugin ad0ccda · on claude/ssh-key-rickub-25a7d3 · nandi · 5h ago
vflutter_ffi.dart · 88 lines · 2.6 KBDart Blame HistoryRaw
 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));