§ 1Workspace at a glance
vihaco is a Cargo workspace of five focused crates. vihaco
is the foundation; everything else builds on it. Depend on what your
workload actually needs — there is no umbrella crate.
vihacofoundation-
The framework. The
Instruction/Message/Effectstypes and their derives, the#[component],#[observe], and#[composite]macros, themodule/syntax/runtimelayers, and theValue/Typevalue model. Re-exports the macros, so most projects depend only on this crate. vihaco-cpucomponent-
A ready-made CPU/host component — a small stack machine with
cpu::RuntimeInstruction(constants, arithmetic, branches,halt, …), a pattern-derivedcpu::SurfaceInstruction, and theStepOutcomecontrol-flow effect. Use it directly, or as a reference for writing your own components. vihaco-parser-deriveparser-
The
#[derive(Parse)]proc-macro. It turns an instruction enum or struct into a chumsky parser from declarative#[syntax_class]and#[pattern]attributes. vihaco-parserparser-
The
Parse<'src>andSurfaceInstructiontraits, plus parser implementations for primitives, lexical types (Ident,BareToken, andQuotedString), vectors, and tuples. vihaco-runtime-deriveinternal-
The procedural macros behind
#[derive(Message)],#[component],#[observe], and#[composite](#[derive(Instruction)]lives invihaco-abi-derive). Both are re-exported throughvihaco— you rarely depend on them directly.
§ 2Pick crates by use case
- Define instructions, components, and effects:
vihaco. - Reuse a CPU / stack machine as one of your components:
vihaco+vihaco-cpu. - Parse source text into instructions:
vihaco+vihaco-parser+vihaco-parser-derive.
§ 3Setup
Requires Rust edition 2024. There is no published release yet, so depend on the git repo. The git dependency form is identical for each crate:
[dependencies]
vihaco = { git = "https://github.com/QuEraComputing/vihaco" }
vihaco-cpu = { git = "https://github.com/QuEraComputing/vihaco" }
vihaco-parser = { git = "https://github.com/QuEraComputing/vihaco" }
vihaco-parser-derive = { git = "https://github.com/QuEraComputing/vihaco" }
eyre = "0.6" # vihaco APIs return eyre::Result § 4A first component
A component bundles three things: an Instruction enum (the
operations), an optional Message (resolved execution input),
and an optional effect type (what execution returns). The
#[component(...)] attribute generates the runtime glue from a
single execute method.
use eyre::Result;
use vihaco::{
Effects, GeneratedComponent, Instruction, Message, component, expect_exactly_one_effect,
};
#[derive(Debug, Clone, Instruction)]
pub enum CounterInst {
Add(i64),
Print,
}
#[derive(Debug, Clone, Message)]
pub struct Prefix(pub String);
#[derive(Debug, Clone, PartialEq)]
pub struct Line(pub String);
#[derive(Debug, Default)]
pub struct Counter {
value: i64,
}
#[component(instruction = CounterInst, message = Prefix, effect = Line)]
impl Counter {
fn execute(&mut self, inst: CounterInst, msg: Prefix) -> Result<Effects<Line>> {
match inst {
CounterInst::Add(v) => {
self.value += v;
Ok(Effects::none())
}
CounterInst::Print => Ok(Effects::one(Line(format!("{}{}", msg.0, self.value)))),
}
}
}
fn main() -> Result<()> {
let mut counter = Counter::default();
// `Add` ignores its message and returns no effects.
counter.execute_generated(CounterInst::Add(2), Prefix(String::new()))?;
counter.execute_generated(CounterInst::Add(3), Prefix(String::new()))?;
// `Print` returns exactly one `Line` effect.
let effects = counter.execute_generated(CounterInst::Print, Prefix("total = ".into()))?;
let line = expect_exactly_one_effect(effects)?;
assert_eq!(line, Line("total = 5".into()));
Ok(())
}
execute_generated is the runtime entry point the macro
generates (via the GeneratedComponent trait);
expect_exactly_one_effect is a helper for the common
single-effect case. For the full data-flow model — when to use a
Message, how effects are delivered to observers — read
Building Components.
§ 5Parsing source text
Source-text parsing is orthogonal to bytecode. A user-declared surface
enum derives vihaco_parser::Parse from its syntax class and
patterns. When the source and runtime representations match, that enum
can also derive Instruction:
use chumsky::Parser as _;
use vihaco::Instruction;
use vihaco_parser::Parse;
// The same enum can derive both `Instruction` (bytecode + runtime) and
// `Parse` (SST). The two derives are orthogonal.
#[derive(Debug, Clone, PartialEq, Instruction, vihaco_parser_derive::Parse)]
#[syntax_class(instruction, head = "counter")]
pub enum CounterInst {
#[pattern = "'add $0"]
Add(i64),
Print,
}
fn main() {
// The syntax class supplies the `counter::` namespace. Patterns bind
// source operands directly to Rust fields.
let inst = CounterInst::parser()
.parse("counter::add 5")
.into_result()
.unwrap();
assert_eq!(inst, CounterInst::Add(5));
}
That is the whole instruction-level surface. Module-level parsing adds device headers, typed function bodies, and application-specific resolution, covered in Pattern Parser Integration, Pattern Parser, and Module Parsing and Resolution.
§ 6Next steps
- Work through the Guides in order — they build the full authoring model from instructions up to composites.
- Browse the API Reference (generated rustdoc).
- Read
vihaco-cpuas a worked example of a non-trivial component.