byteflow-actors
Byteflow is a small, embeddable actor runtime for Rust: register-based bytecode, lightweight virtual processes, mailboxes, cooperative scheduling, and a one-for-one supervisor — without a separate scripting language.
You assemble programs with ChunkBuilder in host Rust. The host owns I/O; Byteflow owns cheap concurrency.
Package name:
byteflow-actorson crates.io
Rust import:use byteflow::...(the library crate is namedbyteflow)
Why this exists
Use Byteflow when you need many isolated units of work that talk through messages, share a handful of OS threads, and can fail without taking the worker down:
- plugin / rule / workflow engines inside a larger binary
- simulations and game logic (not the render loop)
- sandboxed “virtual processes” with a host-defined FFI table
It is not a Tokio replacement, not a distributed cluster, and not a JVM.
Install
[]
= "0.2"
use ;
CLI (same package):
cargo install byteflow-actors
byteflow demo ping-pong
Quick start
use ;
Std natives (print, now_ms)
Stable indices: print = 0, now_ms = 1.
use ;
let mut b = new;
b.begin_function;
b.emit_load_imm;
b.emit_call_native; // print(r0)
b.emit_call_native; // r1 = now_ms()
b.emit_return;
let rt = with_natives;
Or std_natives() → (NativeTable, HashMap<name, index>) so host registration stays aligned with bytecode.
Messaging (ping-pong)
cargo run --example ping_pong
# pong replied 2
Built-in samples: byteflow::samples::{ping_pong, add_forty_two, boom}.
Architecture
| Layer | Responsibility |
|---|---|
| Bytecode | ISA, ChunkBuilder, BFV0 (.bf) encode/decode, static verify |
| VM | One process: registers, call stack, cooperative quantum, CallNative |
| Scheduler | M:N workers, FIFO mailboxes (park/wake), timer, supervisor |
| Facade | Public API + std natives + samples + byteflow CLI |
Process lifecycle (sketch):
- Worker runs at most
quantuminstructions (default 10 000). Yield/ budget → run queue (stealable).Sleep→ timer thread → injector.- Empty
Receive→ process parks inside its mailbox; the nextSendwakes under the same lock (no lost wakeup). Fault/Trap→ProcessState::Failed→ supervisor (Always/OnFailure/Never; default intensity 3 / 5s).
join() is for the embedder’s native thread only — workers never block on it.
Untrusted .bf files go through Opcode::from_u8 + verify before execution.
CLI
byteflow demo [ping-pong|add]
byteflow pack <demo> <out.bf>
byteflow verify <file.bf>
byteflow disasm <file.bf>
byteflow run <file.bf> [function]
run attaches the std native table so modules that CallNative indices 0/1 work.
Safety & design notes
#![forbid(unsafe_code)]- Process panics are caught at the worker boundary so one bad process cannot kill the OS thread.
- Native functions must not block — they run inline on a worker.
- Values today:
Unit | Bool | Int | Float | Pid(no strings yet).
Status (v0.2)
Included: register ISA + assembler, BFV0, verifier, per-process VM, M:N scheduler, mailboxes, supervisor, std natives, CLI, examples.
Not yet: strings/bytes in Value, bounded mailboxes, Criterion benches, timing wheel, JIT, distribution.
Links
- Repository: github.com/mchael158/bytecode-vm
- Docs: docs.rs/byteflow-actors
- License: MIT OR Apache-2.0