use log::trace;
use super::LetterCasing::{Lower, Upper};
use super::SpecialCharacter::{Eszett, Umlaut};
use super::Umlaut::{Ae, Oe, Ue};
use super::{SpecialCharacter, Word};
#[derive(Default, Debug)]
enum State {
#[default]
Other,
Word(Option<Potential>),
}
#[derive(Debug)]
struct Potential(SpecialCharacter);
#[derive(Debug, Clone)]
pub(super) enum Transition {
Entered,
Exited,
Internal,
External,
}
impl Transition {
const fn from_states(from: &State, to: &State) -> Self {
match (from, to) {
(State::Word(_), State::Other) => Self::Exited,
(State::Other, State::Word(_)) => Self::Entered,
(State::Word(_), State::Word(_)) => Self::Internal,
(State::Other, State::Other) => Self::External,
}
}
}
type MachineInput = char;
#[derive(Debug)]
pub(super) struct StateMachine {
state: State,
word: Word,
transition: Option<Transition>,
}
impl StateMachine {
pub(super) fn new() -> Self {
Self {
state: State::default(),
word: Word::default(),
transition: None,
}
}
pub(super) const fn current_word(&self) -> &Word {
&self.word
}
fn pre_transition(&mut self) {
if matches!(self.state, State::Other) {
self.word.clear();
trace!("Cleared current word, machine now is: {self:?}.");
}
}
pub(super) fn transition(&mut self, input: MachineInput) -> Transition {
self.pre_transition();
let next = match (&self.state, input) {
(State::Word(Some(Potential(Umlaut(umlaut)))), c @ ('e' | 'E')) => {
const LENGTH_OF_PREVIOUS_CHARACTER: usize = 1;
let pos = self.word.len();
debug_assert!(
'o'.len_utf8() == LENGTH_OF_PREVIOUS_CHARACTER
&& 'u'.len_utf8() == LENGTH_OF_PREVIOUS_CHARACTER
&& 'a'.len_utf8() == LENGTH_OF_PREVIOUS_CHARACTER
);
let start = pos - LENGTH_OF_PREVIOUS_CHARACTER;
let end = pos + c.len_utf8();
self.word.add_replacement(start, end, Umlaut(*umlaut));
trace!("Added replacement at position {pos}, machine now is: {self:?}.");
State::Word(None)
}
(State::Word(Some(Potential(Eszett(casing)))), c @ ('s' | 'S')) => {
let pos = self.word.len();
let start = pos - c.len_utf8(); let end = pos + c.len_utf8();
self.word.add_replacement(start, end, Eszett(*casing));
trace!("Added replacement at position {pos}, machine now is: {self:?}.");
State::Word(None)
}
(_, 'a') => State::Word(Some(Potential(Umlaut(Ae(Lower))))),
(_, 'A') => State::Word(Some(Potential(Umlaut(Ae(Upper))))),
(_, 'o') => State::Word(Some(Potential(Umlaut(Oe(Lower))))),
(_, 'O') => State::Word(Some(Potential(Umlaut(Oe(Upper))))),
(_, 'u') => State::Word(Some(Potential(Umlaut(Ue(Lower))))),
(_, 'U') => State::Word(Some(Potential(Umlaut(Ue(Upper))))),
(_, 's') => State::Word(Some(Potential(Eszett(Lower)))),
(_, 'S') => State::Word(Some(Potential(Eszett(Upper)))),
(_, c) if c.is_alphabetic() => State::Word(None),
_ => State::Other,
};
let transition = Transition::from_states(&self.state, &next);
self.state = next;
self.transition = Some(transition.clone());
self.post_transition(input);
transition
}
fn post_transition(&mut self, input: MachineInput) {
if let Some(Transition::Entered | Transition::Internal) = self.transition {
self.word.push(input);
trace!(
"Appending {:?} to current word due to transition {:?}.",
input, self.transition
);
}
trace!("After transition, machine is: {self:?}.");
}
}