Skip to main content

vihaco_runtime/
lib.rs

1// SPDX-FileCopyrightText: 2026 The vihaco Authors
2// SPDX-License-Identifier: MIT
3
4//! Component execution, composite metadata, and observation machinery.
5//!
6//! The nondefault `typed-declarations` feature enables experimental typed
7//! execution and capability contracts, including derive support. It decouples
8//! the Component/Composite markers from HasInstructionSet; Cargo unification
9//! selects that contract for the shared runtime package instance. Declaration
10//! macros provide complete dialect/component capabilities and typed composite
11//! fields. Feature-off execution retains the existing declarations. The two
12//! declaration modes require separate Cargo feature graphs.
13//!
14//! The nondefault `program-image-execution` feature implies `typed-declarations`
15//! and adds `PopFromStack`, `PushToStack`, typed stack access, and capability-
16//! gated message preparation. A `#[program]` device supplies program access and
17//! operand-storage wiring. Composite authors implement Steps and choose effect
18//! handling; program execution lives in stdlib.
19//!
20//! With `typed-declarations`, `#[dialect]` gives public runtime instruction
21//! structs syntax parsers. Operand types retain their authored scope. Only
22//! immediate marked nongeneric unit/tuple structs belong to a dialect. Differing
23//! annotated operands generate a phase parameter defaulting to [`Runtime`].
24//! Composite syntax aggregates lower through instruction-owned [`Lower`]
25//! implementations; unchanged instructions receive identity lowering.
26//!
27//! ```
28//! # #[cfg(feature = "typed-declarations")]
29//! # {
30//! use vihaco_runtime::{dialect, Parse, chumsky::Parser};
31//!
32//! #[dialect]
33//! # #[vihaco(crate = ::vihaco_runtime)]
34//! pub mod arithmetic {
35//!     #[instruction]
36//!     pub struct Add(pub i64);
37//!
38//!     #[instruction]
39//!     #[pattern = "'stop"]
40//!     pub struct Halt;
41//! }
42//!
43//! let source = arithmetic::Add::parser().parse("add -3")
44//!     .into_result().unwrap();
45//! assert_eq!(source, arithmetic::Add(-3));
46//! let runtime = source;
47//! assert_eq!(runtime.0, -3);
48//! # }
49//! ```
50//!
51//! The attribute consumes `instruction` and `pattern` helpers, preserves module
52//! and field visibility, and supplies Clone/Debug/PartialEq without duplicating
53//! those authored derives. Named fields, generic or raw leaf names, conditional
54//! membership, and generated-name collisions are rejected. Gate the entire
55//! module with `cfg`/`cfg_attr`. Unannotated pattern bindings use their runtime
56//! field's parser. A binding such as `$0:u64` retains that syntax operand type;
57//! differing runtime types require explicit lowering. Parser annotations retain
58//! ordinary Rust type scope.
59
60extern crate self as vihaco_runtime;
61
62mod generated;
63
64mod marker;
65
66mod member_of;
67
68mod no_message;
69
70mod observe;
71
72#[cfg(feature = "typed-declarations")]
73mod build_message;
74
75#[cfg(feature = "typed-declarations")]
76mod capability;
77
78#[cfg(feature = "typed-declarations")]
79mod dispatch;
80
81#[cfg(feature = "typed-declarations")]
82mod execute;
83
84#[cfg(feature = "typed-declarations")]
85mod field;
86
87#[cfg(feature = "typed-declarations")]
88mod step;
89
90/// Generated declaration contracts. Manual implementations are unsupported.
91#[cfg(feature = "typed-declarations")]
92#[doc(hidden)]
93#[path = "declarations.rs"]
94pub mod __private;
95
96#[cfg(feature = "typed-declarations")]
97pub use build_message::{BuildMessage, PrepareMessage};
98
99#[cfg(feature = "typed-declarations")]
100#[doc(hidden)]
101pub use build_message::AutomaticMessage;
102
103#[cfg(feature = "typed-declarations")]
104pub use dispatch::Dispatch;
105
106#[cfg(feature = "typed-declarations")]
107pub use execute::Execute;
108
109#[cfg(feature = "typed-declarations")]
110pub use field::Field;
111
112#[cfg(feature = "typed-declarations")]
113pub use step::Step;
114
115// Re-export the sub-paths the runtime derive (`vihaco-runtime-derive`) emits so
116// that `vihaco-runtime` is a valid derive root on its own, mirroring the facade
117// (see design/crate-split.md ยง5.3).
118pub use chumsky;
119
120#[doc(hidden)]
121pub use eyre;
122pub use vihaco_abi::traits::{EffectSink, Reset};
123pub use vihaco_abi::{Effects, Lower, Runtime, Syntax, metadata};
124pub use vihaco_bytecode::{BytecodeSectionView, SstSectionView};
125pub use vihaco_module::loader;
126#[doc(hidden)]
127pub use vihaco_parser::trivia;
128pub use vihaco_parser::{Parse, SurfaceInstruction};
129
130pub use generated::{
131    Component, Composite, CompositeMetadata, GeneratedComponent, HasInstructionSet,
132    expect_exactly_one_effect,
133};
134
135pub use marker::Message;
136pub use member_of::MemberOf;
137pub use no_message::NoMessage;
138pub use observe::Observe;
139
140// `#[derive(Message)]` emits `#root::runtime::Message`; keep a `runtime` segment
141// available on this crate too (the facade exposes it via `pub use vihaco_runtime
142// as runtime;`) so direct dependents resolve the marker identically.
143pub use crate as runtime;
144
145// The `Instruction` derive lives in `vihaco-abi(-derive)`; re-export it here so
146// `#[composite]`'s generated `#root::Instruction` derive resolves through the
147// runtime root as well.
148#[cfg(feature = "derive")]
149pub use vihaco_abi::Instruction;
150
151// Re-export the runtime derives behind the `derive` feature (serde convention).
152#[cfg(feature = "derive")]
153pub use vihaco_runtime_derive::{Message, dispatch, machine, observe};
154
155/// Declare device fields and complete child capabilities.
156///
157/// With `typed-declarations`, named device declarations contribute every leaf
158/// from their declared dialects to a hidden flat runtime enum exposed through
159/// [`HasInstructionSet`]. Its syntax parser uses
160/// `field::nested_field::dialect::instruction` prefixes and accepts device aliases.
161/// Implement [`Step`] for every destination/leaf pair. With `program-image-execution`,
162/// a `#[program]` device selects program access and operand-storage wiring; Steps
163/// and effect handling remain authored.
164/// The generated [`Dispatch`] implementation requires complete [`Step`] coverage
165/// for the selected context when a `Dispatch<Context>` bound is required or dispatch
166/// is called. Declaring a composite alone does not check Step coverage.
167/// Generic declarations retain their original bounds.
168/// Every device needs an explicit u8 code, unique within its parent. Ordinary
169/// state is excluded from parent instruction sets.
170/// Without `program-image-execution`, `#[loadable]` devices form section boundaries
171/// and are excluded from parent instruction sets. The macro generates legacy
172/// section-loading implementations in that configuration. With the feature
173/// enabled, construct images explicitly and pair them with stdlib `Loadable`;
174/// `#[loadable]` helpers and generated section loading are unavailable.
175/// [`Field::get`] and [`Field::get_mut`] borrow eligible devices through direct or
176/// nested field routes, including devices that contain borrowed data.
177/// Named generic children are supported; bare type parameters and associated
178/// child types cannot supply an inferred inventory companion. Renamed child
179/// imports/type aliases require matching `__vihaco_inventory_Name` and field
180/// companion reexports. Inventory slots and variant names are not bytecode IDs.
181///
182/// ```
183/// # #[cfg(feature = "typed-declarations")]
184/// # mod example {
185/// use vihaco_runtime::{Execute, NoMessage, Step, field, component, composite, dialect};
186/// #[dialect]
187/// # #[vihaco(crate = ::vihaco_runtime)]
188/// mod control { #[instruction] pub struct Halt; }
189/// #[component]
190/// # #[vihaco(crate = ::vihaco_runtime)]
191/// #[instructions { control }]
192/// struct Cpu;
193/// impl Execute<control::Halt> for Cpu {
194///     type Message = NoMessage;
195///     type Effect = ();
196///     type Error = std::convert::Infallible;
197///     fn execute(&mut self, _: &control::Halt, _: NoMessage) -> Result<(), Self::Error> {
198///         Ok(())
199///     }
200/// }
201/// #[composite]
202/// # #[vihaco(crate = ::vihaco_runtime)]
203/// struct Machine { #[device(7, alias = "host")] cpu: Cpu }
204/// impl Step<field!(Machine::cpu), control::Halt> for Machine {
205///     fn step(&mut self, instruction: &control::Halt, _: &()) -> vihaco_runtime::eyre::Result<()> {
206///         self.cpu.execute(instruction, NoMessage::new())?;
207///         Ok(())
208///     }
209/// }
210/// # }
211/// # fn main() {}
212/// ```
213///
214/// Without `typed-declarations`, this retains the legacy composite expansion.
215#[cfg(feature = "derive")]
216pub use vihaco_runtime_derive::composite;
217
218#[cfg(all(feature = "derive", not(feature = "typed-declarations")))]
219pub use vihaco_runtime_derive::component_macro;
220
221#[cfg(all(feature = "derive", not(feature = "typed-declarations")))]
222pub use vihaco_runtime_derive::component_macro as component;
223
224#[cfg(feature = "derive")]
225pub use vihaco_parser_derive::Parse;
226
227/// Declare instructions with retained syntax operands and capability-based lowering.
228///
229/// Available with `typed-declarations`. The framework dependency is discovered
230/// automatically, including renamed dependencies. To use a module reexporting
231/// the framework API, apply `#[vihaco(crate = path)]` to the dialect module.
232/// The path is resolved in the annotated module's parent scope; `self`, `super`,
233/// `crate`, and absolute paths are supported. Operand types retain their
234/// authored scope. Unannotated bindings use the corresponding field's parser.
235/// `$0:SyntaxType` retains another `Parse` type. If it differs from the field,
236/// the generated instruction has a phase parameter defaulting to [`Runtime`],
237/// and its [`Syntax`] form requires an instruction-owned [`Lower`] implementation.
238/// Unchanged instructions remain nongeneric and receive identity lowering.
239/// Write authored lowering implementations outside the dialect module, beside
240/// its declaration or in a separate module in the same crate.
241///
242/// ```
243/// use vihaco_runtime::dialect;
244///
245/// mod framework {
246///     pub use vihaco_runtime::*;
247/// }
248///
249/// #[dialect]
250/// #[vihaco(crate = crate::framework)]
251/// pub mod arithmetic {
252///     #[instruction]
253///     pub struct Add(pub i64);
254/// }
255///
256/// fn main() {
257///     use framework::{Parse, chumsky::Parser};
258///     assert_eq!(arithmetic::Add::parser().parse("add 2")
259///         .into_result().unwrap().0, 2);
260/// }
261/// ```
262///
263/// Differing operand types are retained until explicit lowering, even when
264/// Rust already provides a conversion between them:
265///
266/// ```
267/// use vihaco_runtime::{dialect, Lower, Parse, Syntax, chumsky::Parser};
268/// #[dialect]
269/// # #[vihaco(crate = ::vihaco_runtime)]
270/// mod control {
271///     #[instruction]
272///     #[pattern = "'call $0:u64"]
273///     pub struct Call(pub u32);
274/// }
275/// impl<C: ?Sized> Lower<C> for control::Call<Syntax> {
276///     type Runtime = control::Call;
277///     fn lower(self, _: &mut C) -> vihaco_runtime::eyre::Result<Self::Runtime> {
278///         Ok(control::Call(self.0.try_into()?))
279///     }
280/// }
281/// let source = control::Call::<Syntax>::parser().parse("call 4294967296")
282///     .into_result().unwrap();
283/// assert_eq!(source.0, 4294967296);
284/// assert!(source.lower(&mut ()).is_err());
285/// ```
286#[cfg(feature = "typed-declarations")]
287pub use vihaco_runtime_derive::dialect;
288
289/// Declare a component's complete dialect capabilities.
290///
291/// Available with `typed-declarations`. Apply to any struct with exactly one
292/// nonempty `#[instructions { dialect_paths, ... }]` helper. Paths name whole
293/// dialect modules, including imported aliases. Implement [`Execute`] for every
294/// instruction in every listed dialect under the struct's original bounds.
295/// Each implementation may choose its own message, effect, and error types.
296/// The declaration preserves the struct and implements [`Component`] without
297/// requiring an aggregate instruction set. Canonical instruction overlaps are
298/// rejected even on unused generic components. `#[vihaco(crate = path)]`
299/// selects an explicit framework root in the struct's authored scope.
300///
301/// ```
302/// use vihaco_runtime::{component, dialect, Execute, NoMessage};
303/// #[dialect]
304/// # #[vihaco(crate = ::vihaco_runtime)]
305/// mod control {
306///     #[instruction]
307///     pub struct Halt;
308/// }
309/// #[component]
310/// # #[vihaco(crate = ::vihaco_runtime)]
311/// #[instructions { control }]
312/// struct Cpu<T = u8>(T);
313/// impl<T> Execute<control::Halt> for Cpu<T> {
314///     type Message = NoMessage;
315///     type Effect = ();
316///     type Error = std::convert::Infallible;
317///     fn execute(&mut self, _: &control::Halt, _: NoMessage) -> Result<(), Self::Error> {
318///         Ok(())
319///     }
320/// }
321/// ```
322#[cfg(feature = "typed-declarations")]
323pub use vihaco_runtime_derive::component;
324
325/// Name a composite field or nested route as a marker type.
326///
327/// Write `field!(Machine::controller::cpu)` with the composite declaration name
328/// first, followed by Rust field names. The generated namespace must be in scope;
329/// renamed composite imports and root type aliases are not discovered automatically.
330/// For generic roots, supply their arguments: `field!(Machine<T>::controller::cpu)`.
331/// The macro checks the route through CheckedRoute before resolving to its
332/// unchanged nominal marker type. An unused type alias may defer that check.
333/// Nested routes compose nominal markers with FieldPath and project the final
334/// child. Route SOURCE describes the final field, not the full source prefix.
335/// Ordinary state and source aliases are not field targets.
336///
337/// Child namespaces follow their authored type paths. Alternate type spellings
338/// need matching companion namespace reexports. Inventory generation requires
339/// a named child declaration; it cannot infer bare generic or associated children.
340///
341/// ```
342/// use vihaco_runtime::{composite, field};
343/// use vihaco_runtime::Field;
344/// #[composite]
345/// # #[vihaco(crate = ::vihaco_runtime)]
346/// struct Leaf { state: u8 }
347/// #[composite]
348/// # #[vihaco(crate = ::vihaco_runtime)]
349/// struct Controller { #[device(1)] cpu: Leaf }
350/// #[composite]
351/// # #[vihaco(crate = ::vihaco_runtime)]
352/// struct Machine {
353///     #[device(7)] controller: Controller,
354/// }
355/// type Route = field!(Machine::controller::cpu);
356/// type Child = <Machine as Field<Route>>::Child;
357/// fn main() {
358///     let _: Child = Leaf { state: 0 };
359/// }
360/// ```
361#[cfg(feature = "typed-declarations")]
362pub use vihaco_runtime_derive::field;
363
364#[cfg(feature = "program-image-execution")]
365mod stack;
366
367#[cfg(feature = "program-image-execution")]
368pub use stack::{Apply, HasOperandStack, InputCount, PopFromStack, PushToStack, StackInputCount};
369
370#[cfg(feature = "program-image-execution")]
371mod stack_batch;
372
373#[cfg(feature = "program-image-execution")]
374pub use stack_batch::{StackBatch, StackBatchIntoIter};
375
376#[cfg(feature = "program-image-execution")]
377pub use vihaco_module::{PopStack, PushStack, StackValue};
378
379#[cfg(feature = "program-image-execution")]
380mod execution;
381
382#[cfg(feature = "program-image-execution")]
383pub use execution::HasProgram;