sim_lib_control/backtrack.rs
1use sim_kernel::Ref;
2
3/// Result of advancing a [`Backtracker`]: the next alternative, or failure.
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub enum BacktrackStep {
6 /// The next untried alternative to commit to.
7 Choice(Ref),
8 /// No alternatives remain; the search has exhausted this point.
9 Failed,
10}
11
12/// A linear backtracking choice point over a fixed list of alternatives.
13///
14/// Models the choose/fail surface of non-deterministic control: each
15/// [`Backtracker::choose`] or [`Backtracker::fail`] commits to the next
16/// alternative, yielding [`BacktrackStep::Failed`] once they run out.
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct Backtracker {
19 alternatives: Vec<Ref>,
20 index: usize,
21}
22
23impl Backtracker {
24 /// Builds a backtracker that walks `alternatives` in order.
25 pub fn new(alternatives: Vec<Ref>) -> Self {
26 Self {
27 alternatives,
28 index: 0,
29 }
30 }
31
32 /// Commits to the next alternative, or [`BacktrackStep::Failed`] if none
33 /// remain.
34 pub fn choose(&mut self) -> BacktrackStep {
35 let Some(choice) = self.alternatives.get(self.index).cloned() else {
36 return BacktrackStep::Failed;
37 };
38 self.index += 1;
39 BacktrackStep::Choice(choice)
40 }
41
42 /// Backtracks the current choice and advances to the next alternative;
43 /// equivalent to [`Backtracker::choose`].
44 pub fn fail(&mut self) -> BacktrackStep {
45 self.choose()
46 }
47}