§ 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::Instruction(constants, arithmetic, branches,halt, …) and theStepOutcomecontrol-flow effect. Use it directly, or as a reference for writing your own components. vihaco-parserparser-
The
#[derive(Parse)]proc-macro. It turns an instruction enum into a chumsky parser, driven by#[head]/#[token]/#[delimiters]/#[parse_with]attributes. vihaco-parser-coreparser-
The
Parse<'src>trait and blanket impls for the primitives (i64,u64,f64,bool,String, …), plus theident()helper. Every parser in the workspace is aParseimpl. vihaco-deriveinternal-
The procedural macros behind
#[derive(Instruction)],#[derive(Message)],#[component],#[observe], and#[composite]. Re-exported throughvihaco— you rarely depend on it 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-core.
§ 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-core = { 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. The same enum can derive
vihaco_parser::Parse alongside Instruction;
calling parser() gives you a chumsky parser:
use chumsky::Parser as _;
use vihaco::Instruction;
use vihaco_parser_core::Parse;
// The same enum can derive both `Instruction` (bytecode + runtime) and
// `Parse` (source text). The two derives are orthogonal.
#[derive(Debug, Clone, PartialEq, Instruction, vihaco_parser::Parse)]
pub enum CounterInst {
Add(i64),
Print,
}
fn main() {
// The default token is the lowercase variant name; tuple fields are
// wrapped in `( )` by default. (Bare forms like `add 5` are opt-in via
// `#[delimiters(open = "", close = "", separator = "")]`.)
let inst = CounterInst::parser()
.parse("add(5)")
.into_result()
.unwrap();
assert_eq!(inst, CounterInst::Add(5));
}
That is the whole instruction-level surface. Module-level orchestration —
device headers, function bodies, sugar expansion, string interning, label
resolution — is a two-pass parse → resolve pipeline covered
in Parser Integration and
Advanced Parser Customization.
§ 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.