quint_connect/driver/mod.rs
1mod nondet;
2mod state;
3mod step;
4
5pub use state::State;
6pub use step::Step;
7
8/// A convenience type alias for [`anyhow::Result`] used throughout this crate.
9///
10/// This type defaults to `Result<()>` when no type parameter is provided, making it
11/// ergonomic for functions that return success/failure without a value.
12pub type Result<A = ()> = anyhow::Result<A>;
13
14/// A static path used to navigate nested structures in Quint specifications.
15///
16/// Paths are represented as static string slices and are used in [`Config`] to specify
17/// where to find state and nondeterministic picks within the specification's state space.
18///
19/// # Examples
20///
21/// ```rust
22/// use quint_connect::Config;
23///
24/// let config = Config {
25/// state: &["global_var", "nested_record", "my_state"],
26/// nondet: &["nondet_choices"],
27/// };
28/// ```
29pub type Path = &'static [&'static str];
30
31/// Configuration for a [`Driver`] that specifies where to find state and nondeterministic
32/// picks within a Quint specification.
33///
34/// By default, both paths are empty (`&[]`). Empty paths indicate that:
35/// - State is extracted from the top level of the specification's state space
36/// - Nondeterministic picks are extracted from Quint's builtin `mbt::actionTaken` and
37/// `mbt::nondetPicks` variables
38///
39/// Override these paths when your specification nests the relevant state within a larger
40/// structure, or when tracking nondeterminism manually rather than using Quint's builtin
41/// variables.
42///
43/// # Examples
44///
45/// Specifying custom paths for nested state:
46///
47/// ```rust
48/// use quint_connect::{Driver, Config};
49/// # use quint_connect::{Step, Result, State};
50/// #
51/// # #[derive(Debug, PartialEq, serde::Deserialize)]
52/// # struct MyState;
53/// #
54/// # impl State<MyDriver> for MyState {
55/// # fn from_driver(driver: &MyDriver) -> Result<Self> { Ok(MyState) }
56/// # }
57/// #
58/// # struct MyDriver;
59///
60/// impl Driver for MyDriver {
61/// type State = MyState;
62///
63/// fn config() -> Config {
64/// Config {
65/// state: &["global_var", "nested_record", "my_state"],
66/// nondet: &["global_var", "nondet_choices"],
67/// }
68/// }
69///
70/// fn step(&mut self, step: &Step) -> Result {
71/// // ...
72/// # Ok(())
73/// }
74/// }
75/// ```
76#[derive(Default)]
77pub struct Config {
78 /// Path to the state within the Quint specification's state space.
79 ///
80 /// An empty path (`&[]`) indicates the state is at the top level.
81 pub state: Path,
82
83 /// Path to nondeterministic picks within the Quint specification's state space.
84 ///
85 /// An empty path (`&[]`) uses Quint's builtin `mbt::actionTaken` and `mbt::nondetPicks`
86 /// variables.
87 pub nondet: Path,
88}
89
90/// Core trait for connecting Rust implementations to Quint specifications.
91///
92/// Implementations of this trait define how to execute steps from a Quint trace against
93/// a Rust implementation, enabling model-based testing. The framework automatically
94/// generates traces from your Quint specification and replays them through your driver,
95/// verifying that the implementation state matches the specification state after each step.
96///
97/// See the [Quick Start](crate#quick-start) and [Examples](crate#examples) sections in the
98/// crate docs for examples.
99///
100/// # Associated Types
101///
102/// - [`State`]: The state type that can be extracted from both the driver implementation
103/// and the Quint specification for comparison.
104///
105/// # Required Methods
106///
107/// - [`step`](Driver::step): Processes a single step from the trace, typically by
108/// pattern-matching on the action name and nondeterministic picks, then executing the
109/// corresponding implementation code.
110///
111/// # Optional Methods
112///
113/// - [`config`](Driver::config): Returns configuration specifying where to find state
114/// and nondeterministic picks in the specification. Defaults to top-level paths.
115pub trait Driver: Sized {
116 /// The state type that can be extracted from both the driver and the specification.
117 ///
118 /// This type must implement [`State`] to provide state extraction and comparison logic.
119 /// Note that stateless drivers can set `State = ()` to disable state checking.
120 type State: State<Self>;
121
122 /// Processes a single step from a Quint trace.
123 ///
124 /// This method is called for each step in a generated trace. Implementations typically
125 /// use the [`switch!`](crate::switch) macro to pattern-match on the action name and
126 /// execute the corresponding implementation code.
127 fn step(&mut self, step: &Step) -> Result;
128
129 /// Returns configuration for this driver.
130 ///
131 /// Override this method to specify custom paths for extracting state and
132 /// nondeterministic picks from nested structures in the specification.
133 fn config() -> Config {
134 Config::default()
135 }
136}