Skip to content

Quick Start

Vihaco uses Rust edition 2024. Add the crates you need from the source repository. The vihaco facade re-exports the component and runtime macros.

A component declares state and instructions with component!. The #[dispatch(...)] implementation executes each instruction and returns effects. This is the complete example from upstream:

use eyre::Result;
use vihaco::{
component, dispatch, Effects, GeneratedComponent, Message, expect_exactly_one_effect,
};
component! {
#[derive(Debug, Default)]
pub component Counter {
value: i64,
}
instruction {
Add(i64),
Print,
}
}
use counter::runtime::Instruction as CounterInst;
#[derive(Debug, Clone, Message)]
pub struct Prefix(pub String);
#[derive(Debug, Clone, PartialEq)]
pub struct Line(pub String);
#[dispatch(instruction = counter::runtime::Instruction, message = Prefix, effect = Line)]
impl counter::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::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(())
}

The parser derive turns a surface instruction into syntax that can be parsed and resolved. The upstream example is:

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));
}

Continue with the tutorials for instructions, messages, components, observers, and composites, or browse the generated Rust API.