Expand description
Byteflow — embeddable flow runtime (package byteflow-actors).
Not a language, not Tokio, not a JVM. You assemble register bytecode in
host Rust (ChunkBuilder), spawn many lightweight flows on an M:N
scheduler, and they talk through mailboxes with a strict hop protocol.
Dependents write use byteflow::... (crate name) while crates.io lists
the package as byteflow-actors.
§What you get
| Piece | Role |
|---|---|
ChunkBuilder / Opcode | Assemble .bf programs in Rust (no source language) |
Vm / VmResult | Per-flow register interpreter; effects hand off to the scheduler |
Runtime | Worker pool + timer; spawn / join / host Runtime::send |
Value::Message | Atomic Hop envelope — the only value allowed on Send / Ask |
Value::Cap | FlowCap address for bytecode delivery (Send / Ask targets) |
Supervisor | Restart policies when a flow fails |
std_native_table | print, now_ms, make_msg, msg_*, msg_reply_cap |
§Atomic Hop (messaging contract)
Every bytecode Send / Ask carries exactly one Message:
Message { sender, reply_cap, request_id, tag, payload }- Bare
Int/Pid/StronSend→ trap /SendError::NotAHop - Scheduler stamps
sender(authenticated origin) and mintsreply_cap(SEND-only Cap back to the caller) - Reply with
std_native_table’smsg_reply_cap— notmsg_sender(Pidis identity, not an address)
Also: selective receive (ReceiveMatch), and Ask for correlated RPC.
§FlowCap (addressing)
| Value | Use |
|---|---|
Value::Cap | Target of Send / Ask; from SelfPid, Spawn, or reply_cap |
Value::Pid | Identity inside a delivered hop (msg_sender) |
Host Runtime::send still takes FlowId (trusted embedder path).
§Values (ABI v4)
Unit | Bool | Int | Float | Pid | Message | Cap | Str | Bytes
Str / Bytes are Arc-backed for cheap register/mailbox clones. They
are not Atomic Hops by themselves.
§Quick start — scalar
use byteflow::{ChunkBuilder, Opcode, FlowOutcome, Runtime, Value};
let mut b = ChunkBuilder::new("demo");
b.begin_function("main", 0, 2);
b.emit_load_imm(0, 41);
b.emit_load_imm(1, 1);
b.emit_binop(Opcode::Add, 0, 0, 1);
b.emit_return(0);
let rt = Runtime::new(b.finish())?;
let outcome = rt.spawn(0, &[])?.join();
rt.shutdown();
assert!(matches!(outcome, FlowOutcome::Completed(Value::Int(42))));§Quick start — Atomic Hop (ping-pong)
Hop demos need the std native table (make_msg / msg_*):
use byteflow::{samples, std_native_table, FlowOutcome, Runtime, Value};
let rt = Runtime::with_natives(samples::ping_pong(), std_native_table())?;
let main = rt.function_index("main").expect("main");
let outcome = rt.spawn(main, &[])?.join();
rt.shutdown();
assert!(matches!(outcome, FlowOutcome::Completed(Value::Int(2))));More samples: samples::atomic_request_reply, samples::ask_reply,
samples::selective_receive, forged-sender security regressions.
§Design guides (rendered on docs.rs)
docs::atomic_hop— hop protocol, Cap addressing, natives tabledocs::security— threat model, invariants S1–S7, roadmapdocs::error_model— fail-closed errors (no productionunwrap)
§What this is not
- Not a replacement for Tokio / async Rust (no
.awaitIO loop) - Not a distributed cluster runtime (single process, in-memory mailboxes)
- Not a full object-capability OS (native quotas / Cap attenuation come later)
Host owns I/O and policy. Byteflow owns cheap concurrency and hop delivery.
Re-exports§
pub use bytecode::asm_macros;pub use bytecode::decode;pub use bytecode::disassemble;pub use bytecode::encode;pub use bytecode::verify;pub use bytecode::Chunk;pub use bytecode::ChunkBuilder;pub use bytecode::FormatError;pub use bytecode::FunctionDef;pub use bytecode::Instruction;pub use bytecode::Label;pub use bytecode::Message;pub use bytecode::Opcode;pub use bytecode::Value;pub use bytecode::VerifyError;pub use bytecode::ABI_VERSION;pub use bytecode::MAGIC;pub use natives::std_native_map;pub use natives::std_native_table;pub use natives::std_natives;pub use scheduler::fault_count;pub use scheduler::next_flow_id;pub use scheduler::flow_id_from_u64;pub use scheduler::report_fault;pub use scheduler::CapId;pub use scheduler::CapRights;pub use scheduler::ChildSpec;pub use scheduler::Delivery;pub use scheduler::Mailbox;pub use scheduler::Flow;pub use scheduler::FlowHandle;pub use scheduler::FlowId;pub use scheduler::FlowMetrics;pub use scheduler::FlowOutcome;pub use scheduler::FlowState;pub use scheduler::RestartPolicy;pub use scheduler::Runtime;pub use scheduler::RuntimeConfig;pub use scheduler::RuntimeError;pub use scheduler::RuntimeMetrics;pub use scheduler::RuntimeMetricsSnapshot;pub use scheduler::RuntimeSpawner;pub use scheduler::SendError;pub use scheduler::SpawnError;pub use scheduler::Supervisor;pub use scheduler::SupervisorConfig;pub use scheduler::DEFAULT_QUANTUM;pub use vm::expect_arg;pub use vm::expect_bool;pub use vm::expect_int;pub use vm::expect_message;pub use vm::expect_u64;pub use vm::Fault;pub use vm::NativeFn;pub use vm::NativeResult;pub use vm::NativeTable;pub use vm::NativeTableBuilder;pub use vm::Vm;pub use vm::VmResult;pub use vm::MAX_CALL_DEPTH;
Modules§
- bytecode
- Instruction set,
.bf(BFV0) wire format, assembler and verifier. - docs
- Long-form design notes shipped inside the crate (also under
docs/on GitHub). - log
- Host-side scheduler diagnostics on stderr, gated by
BYTEFLOW_LOG. - natives
- Standard native (FFI) table shipped with the facade.
- samples
- Built-in demo chunks assembled with
crate::ChunkBuilder. - scheduler
- M:N flows, mailboxes, timer, supervisor and
Runtime. - vm
- Register-based interpreter for one virtual flow.
Macros§
- emit_
native1_ from emit_native1_from!(builder, dest, src, native)— sugar forcrate::ChunkBuilder::emit_native1_from.- emit_
native_ n emit_native_n!(builder, base, native, argc)— sugar forcrate::ChunkBuilder::emit_native_n.