use crate::{types::Stack, Event};
use super::{
stack_wrapper::{StackEntryItemLike, StackEntryItemLikeContainer, StackWrapper},
StackEntry,
};
pub enum State {
Expecting(Expecting),
Exiting(Exiting),
Ended,
}
impl From<Expecting> for State {
fn from(value: Expecting) -> Self {
Self::Expecting(value)
}
}
impl From<Exiting> for State {
fn from(value: Exiting) -> Self {
Self::Exiting(value)
}
}
#[derive(Clone, Copy)]
pub enum Expecting {
ItemLikeOpening,
BracedOpening,
LeafContent,
}
pub struct Exiting {
pub until: ExitingUntil,
pub and_then: Option<ExitingAndThen>,
}
pub enum ExitingUntil {
OnlyNItemLikesRemain {
n: usize,
should_also_exit_containee_in_last_container: bool,
},
TopIsTable {
should_also_exit_table: bool,
},
TopIsAwareOfDoublePipes,
StackIsEmpty,
}
pub enum ExitingAndThen {
EnterItemLikeAndExpectItemLike {
container: Option<StackEntryItemLikeContainer>,
item_like: StackEntryItemLike,
},
ExpectBracedOpening,
YieldAndExpectBracedOpening(Event),
YieldBasedOnContextAndExpectBracedOpening,
End,
}
impl Exiting {
pub fn new(until: ExitingUntil, and_then: ExitingAndThen) -> Self {
Self {
until,
and_then: Some(and_then),
}
}
}
#[derive(Clone)]
pub enum ItemLikesState {
MatchingLastLine(ItemLikesStateMatchingLastLine),
ProcessingNew,
}
impl From<ItemLikesStateMatchingLastLine> for ItemLikesState {
fn from(value: ItemLikesStateMatchingLastLine) -> Self {
Self::MatchingLastLine(value)
}
}
impl ItemLikesState {
pub fn has_unprocessed_item_likes_at_current_line(&self) -> bool {
matches!(&self, ItemLikesState::MatchingLastLine(_))
}
}
#[derive(Clone)]
pub struct ItemLikesStateMatchingLastLine {
last_total: usize,
current_last_accessed: LastAccessedItemLikeAtCurrentLine,
}
impl ItemLikesStateMatchingLastLine {
pub fn new(last_total: usize) -> Self {
debug_assert!(last_total > 0);
Self {
last_total,
current_last_accessed: LastAccessedItemLikeAtCurrentLine::new(),
}
}
pub fn processed_item_likes(&self) -> usize {
self.current_last_accessed.nth
}
pub fn first_unprocessed_item_like<'a, TStack: Stack<StackEntry>>(
&mut self,
stack: &'a StackWrapper<TStack>,
) -> &'a StackEntryItemLikeContainer {
self.update_last_accessed_item_like_next_index(stack)
}
pub fn mark_first_unprocessed_item_like_as_processed_at_current_line<
TStack: Stack<StackEntry>,
>(
&mut self,
stack: &StackWrapper<TStack>,
) -> bool {
self.current_last_accessed.nth += 1;
self.update_last_accessed_item_like_next_index(stack);
self.current_last_accessed.next_index += 1;
self.processed_item_likes() == self.last_total
}
fn update_last_accessed_item_like_next_index<'a, TStack: Stack<StackEntry>>(
&mut self,
stack: &'a StackWrapper<TStack>,
) -> &'a StackEntryItemLikeContainer {
let slice = stack.as_slice();
loop {
match &slice[self.current_last_accessed.next_index] {
StackEntry::ItemLikeContainer(stack_entry) => break stack_entry,
_ => self.current_last_accessed.next_index += 1,
}
}
}
}
#[derive(Clone)]
pub struct LastAccessedItemLikeAtCurrentLine {
nth: usize,
next_index: usize,
}
impl LastAccessedItemLikeAtCurrentLine {
fn new() -> Self {
Self {
nth: 0,
next_index: 0,
}
}
}