use std::{marker::PhantomData, rc::Rc};
use crate::automaton_state::SharedAutomatonState;
pub enum NextState<'a, Id, D, E> {
Continue(SharedAutomatonState<'a, Id, D, E>),
ProcessEnded,
NotFound,
}
pub struct Automaton<'a, Id, D, E> {
start_state: SharedAutomatonState<'a, Id, D, E>,
_data_phantom: PhantomData<D>,
_error_phantom: PhantomData<E>,
}
pub enum AutomatonResult<Id, E> {
EmptyIter(
Id
),
CouldNotFindNextState(
Id
),
Error(
E
)
}
impl <Id, E> AutomatonResult<Id, E> {
pub fn is_empty_iter(&self) -> bool {
return matches!(self, AutomatonResult::EmptyIter(_))
}
pub fn is_could_not_find_next_state(&self) -> bool {
return matches!(self, AutomatonResult::CouldNotFindNextState(_))
}
pub fn is_error(&self) -> bool {
return matches!(self, AutomatonResult::Error(_))
}
pub fn expect_empty_iter(self) -> Result<Id, AutomatonResult<Id, E>> {
if let AutomatonResult::EmptyIter(id) = self {
Result::Ok(id)
} else {
Result::Err(self)
}
}
pub fn expect_could_not_find_next_state(self) -> Result<Id, AutomatonResult<Id, E>> {
if let AutomatonResult::CouldNotFindNextState(id) = self {
Result::Ok(id)
} else {
Result::Err(self)
}
}
pub fn expect_error(&self) -> Result<&E, &AutomatonResult<Id, E>> {
if let AutomatonResult::Error(err) = self {
Result::Ok(err)
} else {
Result::Err(self)
}
}
}
impl <'a, Id, D, E> Automaton<'a, Id, D, E> {
pub fn new_init_fn<FInit: Fn() -> SharedAutomatonState<'a, Id, D, E>>(f_state_graph_init: FInit) -> Self {
Self::new(f_state_graph_init())
}
pub fn new(graph_root_state: SharedAutomatonState<'a, Id, D, E>) -> Self {
Self {start_state: graph_root_state, _data_phantom: PhantomData{}, _error_phantom: PhantomData{}}
}
pub fn run(&mut self, data: &mut D) -> AutomatonResult<Id, E> {
let mut current_state = Rc::clone(&self.start_state);
loop {
let connection_execute_result = current_state.borrow().execute_next_connection(data);
match connection_execute_result {
Err(err) => {
return AutomatonResult::Error(err);
},
Ok(next_state_result) => {
match next_state_result {
NextState::Continue(next_state) => current_state = next_state,
NextState::NotFound => return AutomatonResult::CouldNotFindNextState(current_state.borrow().get_id_owned()),
NextState::ProcessEnded => return AutomatonResult::EmptyIter(current_state.borrow().get_id_owned()),
};
},
};
};
}
}
#[cfg(test)]
pub mod test {
use std::rc::Rc;
use crate::{automaton::AutomatonResult, automaton_state::{new_shared_automaton_state, AutomatonState, SharedAutomatonState}};
use super::{Automaton, NextState};
pub struct TestNodeHello<'a> {
next_state: Option<SharedAutomatonState<'a, u8, String, String>>
}
impl<'a> TestNodeHello <'a> {
pub fn new(next_state: Option<SharedAutomatonState<'a, u8, String, String>>) -> Self {
Self { next_state }
}
}
impl <'a> AutomatonState<'a, u8, String, String> for TestNodeHello<'a> {
fn get_id_owned(&self) -> u8 {
1
}
fn get_id(&self) -> &u8 {
&1
}
fn execute_next_connection(&self, data: &mut String) -> Result<NextState<'a, u8, String, String>, String> {
data.push_str("Hello");
if let Option::Some(nxt_state) = &self.next_state {
Result::Ok(NextState::Continue(Rc::clone(nxt_state)))
} else {
Result::Ok(NextState::NotFound)
}
}
}
pub struct TestNodeWorld {
}
impl TestNodeWorld {
pub fn new() -> Self {
Self { }
}
}
impl <'a> AutomatonState<'a, u8, String, String> for TestNodeWorld {
fn get_id_owned(&self) -> u8 {
2
}
fn get_id(&self) -> &u8 {
&2
}
fn execute_next_connection(&self, data: &mut String) -> Result<NextState<'a, u8, String, String>, String> {
data.push_str(" world");
Result::Ok(NextState::ProcessEnded)
}
}
#[test]
fn automaton_2_nodes_works() -> () {
let mut data = String::with_capacity(11);
let mut automaton = Automaton::new({
let world_state: SharedAutomatonState<u8, String, _> = new_shared_automaton_state(TestNodeWorld::new());
let hello_state: SharedAutomatonState<u8, String, _> = new_shared_automaton_state(TestNodeHello::new(Option::Some(Rc::clone(&world_state))));
hello_state
});
let run_res = automaton.run(&mut data);
assert!(matches!(run_res, AutomatonResult::EmptyIter(2)));
assert_eq!(data, "Hello world");
}
#[test]
fn automaton_result_is_empty_iter() -> () {
assert!(AutomatonResult::<u8, String>::EmptyIter(1).is_empty_iter());
assert!(!AutomatonResult::<u8, String>::CouldNotFindNextState(1).is_empty_iter());
assert!(!AutomatonResult::<u8, String>::Error(String::from("Test error")).is_empty_iter());
}
#[test]
fn automaton_result_is_could_not_find_next_state() -> () {
assert!(!AutomatonResult::<u8, String>::EmptyIter(1).is_could_not_find_next_state());
assert!(AutomatonResult::<u8, String>::CouldNotFindNextState(1).is_could_not_find_next_state());
assert!(!AutomatonResult::<u8, String>::Error(String::from("Test error")).is_could_not_find_next_state());
}
#[test]
fn automaton_result_is_error() -> () {
assert!(!AutomatonResult::<u8, String>::EmptyIter(1).is_error());
assert!(!AutomatonResult::<u8, String>::CouldNotFindNextState(1).is_error());
assert!(AutomatonResult::<u8, String>::Error(String::from("Test error")).is_error());
}
}