use crate::DEFAULT_MAX_HISTORY_SIZE;
use crate::callbacks::CallbackRegistry;
use crate::core::StateMachine;
use std::collections::VecDeque;
#[derive(Debug)]
pub struct StateMachineInstance<SM: StateMachine> {
current_state: SM::State,
history: VecDeque<(SM::State, SM::Input)>,
max_history_size: usize,
callback_registry: CallbackRegistry<SM>,
}
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,
callback_registry: CallbackRegistry::new(),
}
}
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,
callback_registry: CallbackRegistry::new(),
}
}
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) => {
let old_state = self.current_state.clone();
if old_state != new_state {
self.callback_registry.trigger_state_exit(&old_state);
}
self.callback_registry
.trigger_transition(&old_state, &input, &new_state);
self.history.push_back((old_state, input));
if self.history.len() > self.max_history_size {
self.history.pop_front();
}
self.current_state = new_state.clone();
if self.current_state != self.history.back().unwrap().0 {
self.callback_registry.trigger_state_entry(&new_state);
}
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()
}
pub fn callback_registry(&mut self) -> &mut CallbackRegistry<SM> {
&mut self.callback_registry
}
pub fn callback_registry_ref(&self) -> &CallbackRegistry<SM> {
&self.callback_registry
}
pub fn on_state_entry<F>(&mut self, state: SM::State, callback: F)
where
F: Fn(&SM::State) + Send + Sync + 'static,
{
self.callback_registry.on_state_entry(state, callback);
}
pub fn on_state_exit<F>(&mut self, state: SM::State, callback: F)
where
F: Fn(&SM::State) + Send + Sync + 'static,
{
self.callback_registry.on_state_exit(state, callback);
}
pub fn on_transition<F>(&mut self, from_state: SM::State, input: SM::Input, callback: F)
where
F: Fn(&SM::State, &SM::Input, &SM::State) + Send + Sync + 'static,
{
self.callback_registry
.on_transition(from_state, input, callback);
}
pub fn on_any_state_entry<F>(&mut self, callback: F)
where
F: Fn(&SM::State) + Send + Sync + 'static,
{
self.callback_registry.on_any_state_entry(callback);
}
pub fn on_any_state_exit<F>(&mut self, callback: F)
where
F: Fn(&SM::State) + Send + Sync + 'static,
{
self.callback_registry.on_any_state_exit(callback);
}
pub fn on_any_transition<F>(&mut self, callback: F)
where
F: Fn(&SM::State, &SM::Input, &SM::State) + Send + Sync + 'static,
{
self.callback_registry.on_any_transition(callback);
}
pub fn clear_callbacks(&mut self) {
self.callback_registry.clear();
}
pub fn callback_count(&self) -> usize {
self.callback_registry.callback_count()
}
}
impl<SM: StateMachine> Default for StateMachineInstance<SM> {
fn default() -> Self {
Self::new()
}
}