use std::{cell::RefCell, marker::PhantomData, rc::Rc};
use crate::automaton_state::{convert_to_dyn_reference, AutomatonState, SharedAutomatonState};
pub type SharedSimpleState<'a, K, Id, D, E> = Rc<RefCell<SimpleStateImplementation<'a, K, Id, D, E>>>;
pub trait KeyProvidingData<K> {
fn next_key(&mut self) -> Option<K>;
}
pub struct SimpleInterStateConnection<'a, K, Id, D, E> where Id: Copy + 'a, K: 'a, D: 'a, E: 'a {
matcher: Box<dyn Fn(&K) -> bool + 'a>,
exec_function: Box<dyn Fn(&mut D, &K) -> Result<(), E> + 'a>,
connected_state: SharedAutomatonState<'a, Id, D, E>,
}
impl <'a, K, Id, D, E> SimpleInterStateConnection<'a, K, Id, D, E> where Id: Copy {
pub fn new<M: Fn(&K) -> bool + 'a, FExec: Fn(&mut D, &K) -> Result<(), E> + 'a, S: AutomatonState<'a, Id, D, E> + 'a>(matcher: M, exec_function: FExec, next_state: &Rc<RefCell<S>>) -> Self {
Self { matcher: Box::new(matcher), exec_function: Box::new(exec_function), connected_state: convert_to_dyn_reference(Rc::clone(next_state)) }
}
pub fn new_no_action<M: Fn(&K) -> bool + 'a, S: AutomatonState<'a, Id, D, E> + 'a>(matcher: M, next_state: &Rc<RefCell<S>>) -> Self {
Self::new(matcher, Self::do_nothing, next_state)
}
pub fn new_always_matched<S: AutomatonState<'a, Id, D, E> + 'a, FExec: Fn(&mut D, &K) -> Result<(), E> + 'a>(exec_function: FExec, next_state: &Rc<RefCell<S>>) -> Self {
Self::new(Self::always_match, exec_function, next_state)
}
pub fn new_no_action_always_matched<S: AutomatonState<'a, Id, D, E> + 'a>(next_state: &Rc<RefCell<S>>) -> Self {
Self::new_always_matched(Self::do_nothing,next_state)
}
fn always_match(_: &K) -> bool {
true
}
fn do_nothing(_:&mut D, _:&K) -> Result<(), E> {
Result::Ok(())
}
}
pub struct SimpleStateImplementation<'a, K, Id, D, E> where D: KeyProvidingData<K>, Id: Copy{
_phantom: PhantomData<D>,
id: Id,
next_states: Vec<SimpleInterStateConnection<'a, K, Id, D, E>>,
}
impl <'a, K, Id, D, E> SimpleStateImplementation<'a, K, Id, D, E> where D: KeyProvidingData<K>, Id: Copy {
pub fn new(id: Id) -> Self {
Self { _phantom: PhantomData{}, next_states: Vec::new(), id}
}
pub fn register_connection(&mut self, connection: SimpleInterStateConnection<'a, K, Id, D, E>) -> ()
{
self.next_states.push(connection);
}
}
impl<'a, K, Id, D, E> AutomatonState<'a, Id, D, E> for SimpleStateImplementation<'a, K, Id, D, E> where D: KeyProvidingData<K>, Id: Copy {
fn get_id_owned(&self) -> Id {
self.id
}
fn get_id(&self) -> &Id {
&self.id
}
fn execute_next_connection(&self, data: &mut D) -> Result<crate::automaton::NextState<'a, Id, D, E>, E> {
let next_key = data.next_key();
if let Option::Some(k) = next_key {
for c in &self.next_states {
if (c.matcher)(&k) {
(c.exec_function)(data, &k)?;
return Result::Ok(crate::automaton::NextState::Continue(Rc::clone(&c.connected_state)));
}
}
Result::Ok(crate::automaton::NextState::NotFound)
} else {
Result::Ok(crate::automaton::NextState::ProcessEnded)
}
}
}
#[cfg(test)]
mod test {
use super::KeyProvidingData;
struct TestData {
buffer: String,
end: u8,
current: u8,
}
impl TestData {
pub fn new(start: u8, end: u8) -> Self {
Self { buffer: String::new(), end, current: start }
}
pub fn append_text(&mut self, text: &str) -> () {
self.buffer.push_str(text);
}
pub fn data(&self) -> &String {
&self.buffer
}
}
impl KeyProvidingData<u8> for TestData {
fn next_key(&mut self) -> Option<u8> {
if self.current >= self.end {
return Option::None
}
let res = Option::Some(self.current);
self.current += 1;
return res;
}
}
mod automaton_test {
use crate::{automaton::{Automaton, AutomatonResult}, automaton_state::new_shared_concrete_state, simple_impl::simple_state::{test::TestData, SimpleInterStateConnection, SimpleStateImplementation}};
#[test]
fn automaton_with_simple_states_works() -> () {
let mut data = TestData::new(1, 4);
let mut automaton = Automaton::new({
let world_state = new_shared_concrete_state(SimpleStateImplementation::new(3));
let simple_state = new_shared_concrete_state(SimpleStateImplementation::new(2));
simple_state.borrow_mut().register_connection(SimpleInterStateConnection::new(|k| k == &2, |d: &mut TestData, _| {
d.append_text(" simple ");
let res: Result<(), String> = Result::Ok(());
res
}, &world_state));
let hello_state = new_shared_concrete_state(SimpleStateImplementation::new(1));
hello_state.borrow_mut().register_connection(SimpleInterStateConnection::new(|k| k == &1, |d: &mut TestData, _| {
d.append_text("Hello");
Result::Ok(())
}, &simple_state));
world_state.borrow_mut().register_connection(SimpleInterStateConnection::new(|k| k == &3, |d: &mut TestData, _| {
d.append_text("world!");
Result::Ok(())
}, &hello_state));
hello_state
});
let run_result = automaton.run(&mut data);
assert_eq!(data.data(), "Hello simple world!");
assert!(matches!(run_result, AutomatonResult::EmptyIter(1)));
}
#[test]
fn automaton_with_simple_states_works_no_next_state_found() -> () {
let mut data = TestData::new(2, 3);
let mut automaton = Automaton::new(new_shared_concrete_state(SimpleStateImplementation::new(1)));
let run_result: AutomatonResult<u32, String> = automaton.run(&mut data);
assert_eq!(data.data(), "");
assert!(matches!(run_result, AutomatonResult::CouldNotFindNextState(1)));
}
}
}