| Initial commit: V -> Flutter FFI plugin ad0ccda nandi 10h ago | 1 | module main |
| 2 | |
| 3 | // --------------------------------------------------------------------------- |
| 4 | // C-ABI surface consumed by Dart FFI. |
| 5 | // |
| 6 | // Rules for everything below: |
| 7 | // * only C-compatible types cross the boundary (int, f64, &char, voidptr) |
| 8 | // * V strings/arrays/options/sumtypes never cross; convert first |
| 9 | // * anything V allocates and hands out is released by vf_free |
| 10 | // --------------------------------------------------------------------------- |
| 11 | |
| 12 | // Touches the V runtime so the GC and global initialisers are demonstrably |
| 13 | // live. The ELF/Mach-O constructor emitted by `v -shared` already does this; |
| 14 | // this exists for static-archive builds (iOS) where the caller wants a |
| 15 | // guaranteed, idempotent entry point. |
| 16 | @[export: 'vf_init'] |
| 17 | fn vf_init() { |
| 18 | probe := 'vf' |
| 19 | _ = probe.len |
| 20 | } |
| 21 | |
| 22 | @[export: 'vf_add'] |
| 23 | fn vf_add(a int, b int) int { |
| 24 | return a + b |
| 25 | } |
| 26 | |
| 27 | // Returns a V-allocated C string. Caller releases it with vf_free. |
| 28 | // |
| 29 | // Built with `-gc none`, so every intermediate V allocation here must be |
| 30 | // freed by hand. Only the returned buffer outlives the call. |
| 31 | @[export: 'vf_greet'] |
| 32 | fn vf_greet(name &char) &char { |
| 33 | n := unsafe { cstring_to_vstring(name) } |
| 34 | res := 'Hello, ${n}, from V!' |
| 35 | out := unsafe { res.str } |
| 36 | unsafe { n.free() } |
| 37 | return out |
| 38 | } |
| 39 | |
| 40 | @[export: 'vf_free'] |
| 41 | fn vf_free(p voidptr) { |
| 42 | unsafe { free(p) } |
| 43 | } |