derive_finite_automaton/
lib.rs

1#![doc = include_str!("./README.md")]
2
3use std::fmt::{self, Display};
4
5pub use derive_finite_automaton_derive::FiniteAutomataConstructor;
6
7pub trait FiniteAutomata<T>: Sized {
8    /// A data type which holds state under the trie
9    type State;
10    type Item: std::fmt::Debug + PartialEq + Eq + 'static;
11
12    fn get_next(self, c: Self::Item) -> GetNextResult<T, Self>;
13}
14
15/// A type for which a stateful trie can be built
16pub trait FiniteAutomataConstructor: Sized {
17    type FiniteAutomata: FiniteAutomata<Self>;
18
19    fn new_automaton() -> Self::FiniteAutomata;
20}
21
22/// Where 'T' is the type the stateful trie returns
23/// TODO the result should be only on the first result not the second ...
24#[derive(Debug, PartialEq, Eq)]
25pub enum GetNextResult<T, FA: FiniteAutomata<T>> {
26    Result {
27        result: T,
28        /// Whether the item was consumed by the action
29        ate_item: bool,
30    },
31    NewState(FA),
32    InvalidItem(InvalidItem<FA::Item>),
33}
34
35/// Helper for getting the state item used in the automata
36pub type GetAutomataStateForValue<T> =
37    <<T as FiniteAutomataConstructor>::FiniteAutomata as FiniteAutomata<T>>::State;
38
39/// Item found initially which does that have transition
40#[derive(Debug, PartialEq, Eq)]
41pub struct InvalidItem<T>
42where
43    T: std::fmt::Debug + PartialEq + Eq + 'static,
44{
45    pub received: T,
46    pub expected: &'static [T],
47}
48
49impl<T> Display for InvalidItem<T>
50where
51    T: std::fmt::Debug + PartialEq + Eq,
52{
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        f.write_str("Expected ")?;
55        match self.expected {
56            [] => unreachable!(),
57            [a] => f.write_fmt(format_args!("{a:?}")),
58            [head @ .., end] => f.write_fmt(format_args!(
59                "{head} or {end:?}",
60                head = head
61                    .iter()
62                    .map(|chr| format!("{chr:?}"))
63                    .reduce(|mut a, b| {
64                        a.push_str(", ");
65                        a.push_str(&b);
66                        a
67                    })
68                    .unwrap(),
69            )),
70        }?;
71        write!(f, " found {:?}", self.received)
72    }
73}
74
75impl<T> std::error::Error for InvalidItem<T> where T: std::fmt::Debug + PartialEq + Eq + 'static {}