Skip to main content

clt_database/
state_machine.rs

1use crate::{
2    types::{IOCompletions, IOResult},
3    Result,
4};
5
6pub enum TransitionResult<Result> {
7    Io(IOCompletions),
8    Continue,
9    Done(Result),
10}
11
12/// A generic trait for state machines.
13pub trait StateTransition {
14    type Context;
15    type SMResult;
16
17    /// Transition the state machine to the next state.
18    ///
19    /// Returns `TransitionResult::Io` if the state machine needs to perform an IO operation.
20    /// Returns `TransitionResult::Continue` if the state machine needs to continue.
21    /// Returns `TransitionResult::Done` if the state machine is done.
22    fn step(&mut self, context: &Self::Context) -> Result<TransitionResult<Self::SMResult>>;
23
24    /// Finalize the state machine.
25    ///
26    /// This is called when the state machine is done.
27    fn finalize(&mut self, context: &Self::Context) -> Result<()>;
28
29    /// Check if the state machine is finalized.
30    fn is_finalized(&self) -> bool;
31}
32
33#[derive(Debug)]
34pub struct StateMachine<State: StateTransition> {
35    state: State,
36    is_finalized: bool,
37}
38
39impl<State: StateTransition> StateTransition for Box<State> {
40    type Context = State::Context;
41    type SMResult = State::SMResult;
42
43    fn step(&mut self, context: &Self::Context) -> Result<TransitionResult<Self::SMResult>> {
44        self.as_mut().step(context)
45    }
46
47    fn finalize(&mut self, context: &Self::Context) -> Result<()> {
48        self.as_mut().finalize(context)
49    }
50
51    fn is_finalized(&self) -> bool {
52        self.as_ref().is_finalized()
53    }
54}
55
56/// A generic state machine that loops calling `transition` until it returns `TransitionResult::Done` or `TransitionResult::Io`.
57impl<State: StateTransition> StateMachine<State> {
58    pub fn new(state: State) -> Self {
59        Self {
60            state,
61            is_finalized: false,
62        }
63    }
64
65    pub fn step(&mut self, context: &State::Context) -> Result<IOResult<State::SMResult>> {
66        loop {
67            if self.is_finalized {
68                unreachable!("StateMachine::transition: state machine is finalized");
69            }
70            match self.state.step(context)? {
71                TransitionResult::Io(io) => {
72                    return Ok(IOResult::IO(io));
73                }
74                TransitionResult::Continue => {
75                    continue;
76                }
77                TransitionResult::Done(result) => {
78                    assert!(self.state.is_finalized());
79                    self.is_finalized = true;
80                    return Ok(IOResult::Done(result));
81                }
82            }
83        }
84    }
85
86    pub fn finalize(&mut self, context: &State::Context) -> Result<()> {
87        self.state.finalize(context)?;
88        self.is_finalized = true;
89        Ok(())
90    }
91
92    pub(crate) fn inner_mut(&mut self) -> &mut State {
93        &mut self.state
94    }
95
96    pub fn is_finalized(&self) -> bool {
97        self.is_finalized
98    }
99}