use crate::{
types::{IOCompletions, IOResult},
Result,
};
pub enum TransitionResult<Result> {
Io(IOCompletions),
Continue,
Done(Result),
}
pub trait StateTransition {
type Context;
type SMResult;
fn step(&mut self, context: &Self::Context) -> Result<TransitionResult<Self::SMResult>>;
fn finalize(&mut self, context: &Self::Context) -> Result<()>;
fn is_finalized(&self) -> bool;
}
#[derive(Debug)]
pub struct StateMachine<State: StateTransition> {
state: State,
is_finalized: bool,
}
impl<State: StateTransition> StateTransition for Box<State> {
type Context = State::Context;
type SMResult = State::SMResult;
fn step(&mut self, context: &Self::Context) -> Result<TransitionResult<Self::SMResult>> {
self.as_mut().step(context)
}
fn finalize(&mut self, context: &Self::Context) -> Result<()> {
self.as_mut().finalize(context)
}
fn is_finalized(&self) -> bool {
self.as_ref().is_finalized()
}
}
impl<State: StateTransition> StateMachine<State> {
pub fn new(state: State) -> Self {
Self {
state,
is_finalized: false,
}
}
pub fn step(&mut self, context: &State::Context) -> Result<IOResult<State::SMResult>> {
loop {
if self.is_finalized {
unreachable!("StateMachine::transition: state machine is finalized");
}
match self.state.step(context)? {
TransitionResult::Io(io) => {
return Ok(IOResult::IO(io));
}
TransitionResult::Continue => {
continue;
}
TransitionResult::Done(result) => {
assert!(self.state.is_finalized());
self.is_finalized = true;
return Ok(IOResult::Done(result));
}
}
}
}
pub fn finalize(&mut self, context: &State::Context) -> Result<()> {
self.state.finalize(context)?;
self.is_finalized = true;
Ok(())
}
pub(crate) fn inner_mut(&mut self) -> &mut State {
&mut self.state
}
pub fn is_finalized(&self) -> bool {
self.is_finalized
}
}