Rust doc fixes. No code changes. (0.38.5)
This commit is contained in:
parent
4e155b55a5
commit
5fdd02f3a6
1 changed files with 197 additions and 104 deletions
125
docs/rust.md
125
docs/rust.md
|
|
@ -1,3 +1,112 @@
|
||||||
|
# Writing Rust-backed opcodes for Fun VM
|
||||||
|
|
||||||
|
This guide explains how to implement VM opcodes in Rust, wire them into the C VM, and use them from Fun scripts.
|
||||||
|
|
||||||
|
It assumes you are comfortable with basic Rust and C and have a working Fun checkout.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Fun’s VM is written in C, but you can implement opcode handlers in Rust and call them via FFI. The typical flow is:
|
||||||
|
|
||||||
|
1) Write a Rust function with a stable C ABI (extern "C", #[no_mangle]) that takes a pointer to the VM and returns an int status code.
|
||||||
|
2) Use VM stack helpers (exposed to Rust via FFI) to pop arguments and push results.
|
||||||
|
3) Expose that Rust function to the C VM by calling it from the opcode dispatch (a case in the VM’s opcode switch or a small shim under src/vm/rust/).
|
||||||
|
4) Add or reuse a Fun builtin that maps to your opcode, then call it from Fun code.
|
||||||
|
|
||||||
|
## Project layout (relevant parts)
|
||||||
|
|
||||||
|
- src/rust/src/lib.rs — Rust library with exported opcode functions and FFI helpers.
|
||||||
|
- src/vm/rust/ — C-side wiring examples and small opcode cases calling into Rust.
|
||||||
|
- examples/rust_hello.fun — Example Fun script using a Rust-backed opcode.
|
||||||
|
- docs/opcodes.md — General overview of many built-in opcodes (mostly C-based).
|
||||||
|
|
||||||
|
## Enabling Rust in the build
|
||||||
|
|
||||||
|
Rust integration is optional and gated by a CMake flag. Default builds usually have it OFF.
|
||||||
|
|
||||||
|
Enable it for a configured profile (Debug or Release):
|
||||||
|
|
||||||
|
- Debug example:
|
||||||
|
cmake -S . -B build_debug -DFUN_WITH_RUST=ON
|
||||||
|
cmake --build build_debug --target fun
|
||||||
|
|
||||||
|
- Release example:
|
||||||
|
cmake -S . -B build_release -DFUN_WITH_RUST=ON
|
||||||
|
cmake --build build_release --target fun
|
||||||
|
|
||||||
|
Useful targets in this repository include:
|
||||||
|
- fun — the main executable
|
||||||
|
- rust_ops_build — helps build/link Rust ops when enabled
|
||||||
|
- test_opcodes — test executable (if you want to extend tests)
|
||||||
|
|
||||||
|
Note: In CLion, prefer building with one of the provided CMake profiles (Debug/Release) and avoid creating custom build directories.
|
||||||
|
|
||||||
|
## Writing an opcode in Rust
|
||||||
|
|
||||||
|
The Rust side is a no_std static library exposing C ABI functions that the VM can call. See src/rust/src/lib.rs for examples already in the tree.
|
||||||
|
|
||||||
|
Key points:
|
||||||
|
- Use extern "C" and #[no_mangle] to fix the symbol name.
|
||||||
|
- Take a raw pointer to the VM as *mut Vm; return i32 status (0 for success).
|
||||||
|
- Interact with the VM stack via helper FFI functions declared as externs.
|
||||||
|
- Provide a minimal panic handler (no_std) as shown in lib.rs.
|
||||||
|
|
||||||
|
Example: integer addition opcode implemented in Rust.
|
||||||
|
|
||||||
|
In src/rust/src/lib.rs:
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vm;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn vm_pop_i64(vm: *mut Vm) -> i64;
|
||||||
|
fn vm_push_i64(vm: *mut Vm, v: i64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn fun_op_radd(vm: *mut Vm) -> i32 {
|
||||||
|
unsafe {
|
||||||
|
let b = vm_pop_i64(vm);
|
||||||
|
let a = vm_pop_i64(vm);
|
||||||
|
vm_push_i64(vm, a + b);
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} }
|
||||||
|
|
||||||
|
What this does:
|
||||||
|
- Pops two 64-bit integers from the VM stack.
|
||||||
|
- Pushes back their sum.
|
||||||
|
- Returns 0 to indicate success to the VM.
|
||||||
|
|
||||||
|
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/.
|
||||||
|
|
||||||
|
String demo wiring (already present): src/vm/rust/hello.c
|
||||||
|
|
||||||
|
case OP_RUST_HELLO: {
|
||||||
|
#ifdef FUN_WITH_RUST
|
||||||
|
const char *s = fun_rust_get_string();
|
||||||
|
if (!s) s = "";
|
||||||
|
push_value(vm, make_string(s));
|
||||||
|
#else
|
||||||
|
vm_raise_error(vm, "RUST_HELLO requires FUN_WITH_RUST=ON at build time");
|
||||||
|
push_value(vm, make_nil());
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
For a stack-based math opcode (like fun_op_radd), you would declare and call the Rust function similarly:
|
||||||
|
|
||||||
|
#ifdef FUN_WITH_RUST
|
||||||
|
extern int fun_op_radd(void* vm); // or use the proper VM type if available
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case OP_RADD: {
|
case OP_RADD: {
|
||||||
|
|
@ -86,19 +195,3 @@ Authoritative and practical resources on exposing Rust to C (FFI) and maintainin
|
||||||
https://cbindgen.github.io/cbindgen/
|
https://cbindgen.github.io/cbindgen/
|
||||||
- bindgen (generate Rust bindings to existing C headers; useful when mixing C and Rust)
|
- bindgen (generate Rust bindings to existing C headers; useful when mixing C and Rust)
|
||||||
https://github.com/rust-lang/rust-bindgen
|
https://github.com/rust-lang/rust-bindgen
|
||||||
|
|
||||||
## Return-only Rust string helper
|
|
||||||
|
|
||||||
Two variants are available for passing a string to Rust and getting output:
|
|
||||||
|
|
||||||
- rust_hello_args(msg)
|
|
||||||
- Rust side prints the message to stdout; Fun receives Nil. Use when you only want side-effect printing.
|
|
||||||
- rust_hello_args_return(msg)
|
|
||||||
- Rust side does not print; it returns the provided string to Fun (useful for assignment or chaining).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
msg = rust_hello_args_return("Hello back from Rust (no print)!")
|
|
||||||
print(msg)
|
|
||||||
|
|
||||||
See examples/rust_hello_args_return.fun for a complete script.
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue