#![doc = include_str!("./README.md")]
use std::fmt::{self, Display};
pub use derive_finite_automaton_derive::FiniteAutomataConstructor;
pub trait FiniteAutomata<T>: Sized {
type State;
type Item: std::fmt::Debug + PartialEq + Eq + 'static;
fn get_next(self, c: Self::Item) -> GetNextResult<T, Self>;
}
pub trait FiniteAutomataConstructor: Sized {
type FiniteAutomata: FiniteAutomata<Self>;
fn new_automaton() -> Self::FiniteAutomata;
}
#[derive(Debug, PartialEq, Eq)]
pub enum GetNextResult<T, FA: FiniteAutomata<T>> {
Result {
result: T,
ate_item: bool,
},
NewState(FA),
InvalidItem(InvalidItem<FA::Item>),
}
pub type GetAutomataStateForValue<T> =
<<T as FiniteAutomataConstructor>::FiniteAutomata as FiniteAutomata<T>>::State;
#[derive(Debug, PartialEq, Eq)]
pub struct InvalidItem<T>
where
T: std::fmt::Debug + PartialEq + Eq + 'static,
{
pub received: T,
pub expected: &'static [T],
}
impl<T> Display for InvalidItem<T>
where
T: std::fmt::Debug + PartialEq + Eq,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Expected ")?;
match self.expected {
[] => unreachable!(),
[a] => f.write_fmt(format_args!("{a:?}")),
[head @ .., end] => f.write_fmt(format_args!(
"{head} or {end:?}",
head = head
.iter()
.map(|chr| format!("{chr:?}"))
.reduce(|mut a, b| {
a.push_str(", ");
a.push_str(&b);
a
})
.unwrap(),
)),
}?;
write!(f, " found {:?}", self.received)
}
}
impl<T> std::error::Error for InvalidItem<T> where T: std::fmt::Debug + PartialEq + Eq + 'static {}