§ 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, thecomponent!andcomposite!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 the execution component. 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
component!andcomposite!(#[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 declares instruction products with component!.
Each product gets its own Execute<I> implementation, so its
message, effect, and fault types can be specific to that operation.
use eyre::Result;
use vihaco::{component, Effects, Execute, Execution, StepResult};
component! {
component Counter {
value: i64,
}
instruction {
Add(i64),
Read,
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Value(pub i64);
impl Execute<counter::instruction::Add> for counter::Counter {
type Message = ();
type Effect = ();
type Fault = eyre::Report;
fn execute(&mut self, instruction: &counter::instruction::Add, _: ()) -> Result<StepResult<()>> {
self.value += instruction.0;
Ok(StepResult { effects: Effects::none(), execution: Execution::Complete })
}
}
impl Execute<counter::instruction::Read> for counter::Counter {
type Message = ();
type Effect = Value;
type Fault = eyre::Report;
fn execute(&mut self, _: &counter::instruction::Read, _: ()) -> Result<StepResult<Value>> {
Ok(StepResult { effects: Effects::one(Value(self.value)), execution: Execution::Complete })
}
}
fn main() -> Result<()> {
let mut counter = counter::Counter { value: 0 };
Execute::execute(&mut counter, &counter::instruction::Add(5), ())?;
let value = Execute::execute(&mut counter, &counter::instruction::Read, ())?
.effects
.into_iter()
.next()
.expect("Read emits one value");
assert_eq!(value, Value(5));
Ok(())
}
A composite's generated execute_generated method is the
route-dispatch boundary; components themselves use Execute
directly. 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.