You can add more extern helpers (e.g., for strings, arrays, maps) once they are exposed by the C VM. The repository already includes a simple string example returning a const char* from Rust, see fun_rust_get_string() usage below.
## Wiring the opcode in C
To make the VM call your Rust opcode, add a small C-side case that invokes the exported Rust symbol. A minimal pattern lives under src/vm/rust/.
- Follow the existing opcode conventions for your module (core, math, strings, etc.).
- If your build puts the Rust symbol into a static library, make sure the VM target links it when FUN_WITH_RUST is ON (the top-level CMake already does this for the examples provided).
## Using Rust-backed opcodes from Fun
Once wired, expose the opcode via a builtin function or directly in bytecode. The repository includes a demo builtin rust_hello() that returns a Rust-generated string.
If you build without Rust, calling rust_hello() raises a runtime error indicating that Rust integration is disabled.
## Stack discipline and error handling
- Always pop exactly the arguments you expect and push exactly the results your opcode promises. Mismatch leads to stack corruption and hard-to-debug failures.
- Return an int status to the VM (0 for success). If your project uses a different convention for some opcodes, match it consistently.
- Validate types where appropriate (e.g., ensure values are integers before arithmetic). If a check fails, use the VM’s error mechanism (e.g., vm_raise_error) and follow the module’s convention on what to push after errors.
## Data types and FFI surface
The minimal helpers shown cover 64-bit integers and simple strings. Extending the Rust<->C bridge usually involves:
- Declaring additional extern "C" functions in Rust that the C VM implements (to read/write values on the stack, construct arrays/maps/strings, etc.).
- Ensuring all pointers and lifetimes are well-defined: strings pushed to the VM should be copied or allocated using VM facilities so they remain valid after the call.
- Keeping Rust no_std unless you add an allocator and link setup to support std.
## Troubleshooting
- Link errors: Make sure FUN_WITH_RUST=ON for your build directory and that the Rust library is compiled before linking the VM. Use the rust_ops_build target if provided by your profile.
- Missing symbol at runtime: Confirm #[no_mangle] and extern "C" on the Rust function and that C sees the correct prototype.
- Wrong or garbled values: Double-check stack order (Fun uses a stack VM; many ops pop in reverse order: first b, then a).
- No output from rust_hello(): Ensure you run a binary built with FUN_WITH_RUST=ON; otherwise the VM deliberately raises an error and returns Nil for that call.
## Small end-to-end checklist
1) Write the Rust function in src/rust/src/lib.rs with extern "C", #[no_mangle].
2) Use FFI helpers to pop arguments and push results.
3) Add a C-side case under src/vm/... (or src/vm/rust/...) that calls your Rust function when the opcode executes.
4) Ensure the build links Rust code when FUN_WITH_RUST=ON.
5) Add or reuse a builtin in the parser/runtime to surface your opcode to Fun code.
6) Build and run a small .fun example to validate behavior.