use crate::DEFAULT_MAX_HISTORY_SIZE;
use crate::core::StateMachine;
use std::collections::VecDeque;
#[derive(Debug, Clone)]
pub struct StateMachineInstance<SM: StateMachine> {
current_state: SM::State,
history: VecDeque<(SM::State, SM::Input)>,
max_history_size: usize,
}
impl<SM: StateMachine> StateMachineInstance<SM> {
pub fn new() -> Self {
Self {
current_state: SM::initial_state(),
history: VecDeque::new(),
max_history_size: DEFAULT_MAX_HISTORY_SIZE,
}
}
pub fn with_max_history(max_size: usize) -> Self {
Self {
current_state: SM::initial_state(),
history: VecDeque::with_capacity(max_size),
max_history_size: max_size,
}
}
pub fn max_history_size(&self) -> usize {
self.max_history_size
}
pub fn current_state(&self) -> &SM::State {
&self.current_state
}
pub fn history(&self) -> &VecDeque<(SM::State, SM::Input)> {
&self.history
}
pub fn can_accept(&self, input: &SM::Input) -> bool {
SM::valid_inputs(&self.current_state).contains(input)
}
pub fn valid_inputs(&self) -> Vec<SM::Input> {
SM::valid_inputs(&self.current_state)
}
pub fn transition(&mut self, input: SM::Input) -> Result<SM::State, String> {
if !self.can_accept(&input) {
return Err(format!(
"Invalid input {:?} for state {:?}",
input, self.current_state
));
}
let next_state = SM::next_state(&self.current_state, &input);
match next_state {
Some(new_state) => {
self.history.push_back((self.current_state.clone(), input));
if self.history.len() > self.max_history_size {
self.history.pop_front();
}
self.current_state = new_state.clone();
Ok(new_state)
}
None => Err(format!(
"No valid transition from state {:?} with input {:?}",
self.current_state, input
)),
}
}
pub fn reset(&mut self) {
self.current_state = SM::initial_state();
self.history.clear();
}
pub fn history_len(&self) -> usize {
self.history.len()
}
pub fn history_is_empty(&self) -> bool {
self.history.is_empty()
}
}
impl<SM: StateMachine> Default for StateMachineInstance<SM> {
fn default() -> Self {
Self::new()
}
}