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.3"
use ;
CLI (same package):
cargo install byteflow-actors
byteflow demo ping-pong
Quick start
use ;
Std natives (print, now_ms, make_msg, …)
Stable indices: print = 0, now_ms = 1, make_msg = 2, msg_* = 3–6.
use ;
Or std_natives() → (NativeTable, HashMap<name, index>) so host registration stays aligned with bytecode.
Messaging
Scalar ping-pong (two mailbox values):
cargo run --example ping_pong
Atomic request-reply (Value::Message — one envelope per hop):
cargo run --example atomic_actors
# optional scheduler logs on stderr:
# BYTEFLOW_LOG=info cargo run --example atomic_actors
See docs/atomic-actors.md. Built-in samples:
byteflow::samples::{ping_pong, atomic_request_reply, 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 (print, now_ms, make_msg, msg_*) so modules that CallNative those indices 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.
- Host APIs return
Result(SpawnError/RuntimeError) — nounwrap/expecton production paths (seedocs/error-model.md). - Values today:
Unit | Bool | Int | Float | Pid | Message(no strings/bytes yet).
Status (v0.3)
Included: register ISA + assembler, BFV0 (ABI v2 / Message), verifier, per-process VM, M:N scheduler, mailboxes, atomic envelopes, supervisor, std natives, CLI, examples, fail-closed error model.
Not yet: strings/bytes in Value, bounded mailboxes, Criterion benches, timing wheel, JIT, distribution.
See CHANGELOG.md.
Links
- Repository: github.com/mchael158/bytecode-vm
- Docs: docs.rs/byteflow-actors
- License: MIT OR Apache-2.0