use {
crate::pattern::Name,
alloc::collections::{BTreeMap, VecDeque},
core::mem,
log::warn,
};
pub(crate) type ByteLen = usize;
#[derive(Clone, Debug, Default)]
pub(crate) struct Progress<'s> {
search: &'s str,
traveled: ByteLen,
}
impl<'s> Progress<'s> {
const fn is_at_finish(&self) -> bool {
self.traveled == self.search.len()
}
fn traveled_str(&self) -> &'s str {
#[allow(unsafe_code)] unsafe {
self.search.get_unchecked(..self.traveled)
}
}
fn remaining_str(&self) -> &'s str {
#[allow(unsafe_code)] unsafe {
self.search.get_unchecked(self.traveled..)
}
}
#[allow(unsafe_code)] unsafe fn increment(&mut self, value: ByteLen) {
#[allow(clippy::integer_arithmetic)]
{
self.traveled += value;
}
}
}
impl<'s> From<&'s str> for Progress<'s> {
fn from(search: &'s str) -> Self {
Self {
search,
traveled: 0,
}
}
}
impl<'s> Iterator for Progress<'s> {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
let next_item = self.remaining_str().chars().next();
if let Some(next_char) = next_item {
let next_char_byte_len = next_char.len_utf8();
#[allow(unsafe_code)]
unsafe {
self.increment(next_char_byte_len);
}
}
next_item
}
}
#[derive(Clone, Debug)]
pub struct Find<'s> {
found: &'s str,
begin: ByteLen,
}
impl<'s> Find<'s> {
#[must_use]
pub const fn begin(&self) -> ByteLen {
self.begin
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.found.is_empty()
}
#[must_use]
pub const fn len(&self) -> ByteLen {
self.found.len()
}
#[must_use]
pub const fn end(&self) -> ByteLen {
#[allow(clippy::integer_arithmetic)]
{
self.begin() + self.len()
}
}
#[must_use]
pub const fn as_str(&self) -> &str {
self.found
}
#[allow(unsafe_code)] pub(crate) unsafe fn increment(&mut self, value: ByteLen) {
#[allow(clippy::integer_arithmetic)]
{
self.begin += value;
}
}
}
impl<'s> From<&Progress<'s>> for Find<'s> {
fn from(progress: &Progress<'s>) -> Self {
Self {
found: progress.traveled_str(),
begin: 0,
}
}
}
#[derive(Debug)]
pub(crate) enum ForkKind {
Stationary,
Growing,
}
#[derive(Debug)]
pub(crate) struct Fork<'s> {
progress_queue: VecDeque<Progress<'s>>,
kind: ForkKind,
}
impl<'s> Fork<'s> {
pub(crate) fn new(progress: Progress<'s>, kind: ForkKind) -> Self {
Self {
progress_queue: VecDeque::from([progress]),
kind,
}
}
pub(crate) fn process_haul(&mut self, haul: &Haul<'s>) {
if let ForkKind::Growing = self.kind {
self.progress_queue.push_back(haul.progress_cloned());
}
}
}
impl<'s> Iterator for Fork<'s> {
type Item = Progress<'s>;
fn next(&mut self) -> Option<Self::Item> {
match self.kind {
ForkKind::Stationary => self.progress_queue.front().cloned(),
ForkKind::Growing => self.progress_queue.pop_front(),
}
}
}
pub(crate) type Catch<'s> = BTreeMap<Name, Find<'s>>;
#[derive(Clone, Debug, Default)]
pub(crate) struct Haul<'s> {
progress: Progress<'s>,
catch: Catch<'s>,
}
impl<'s> Haul<'s> {
pub(crate) const fn len(&self) -> ByteLen {
self.progress.traveled
}
pub(crate) const fn matches_finish(&self) -> bool {
self.progress.is_at_finish()
}
pub(crate) fn remaining_str(&self) -> &'s str {
self.progress.remaining_str()
}
pub(crate) fn progress_cloned(&self) -> Progress<'s> {
self.progress.clone()
}
pub(crate) fn identify_as(&mut self, name: Name) {
if self
.catch
.insert(name, Find::from(&self.progress))
.is_some()
{
warn!("Found 2 Finds for Odors with the same Name.");
}
}
#[allow(unsafe_code)] pub(crate) unsafe fn append(&mut self, mut other: Haul<'s>) {
for find in other.catch.values_mut() {
find.increment(self.len());
}
self.catch.append(&mut other.catch);
self.progress.increment(other.len());
}
pub(crate) fn next_char(&mut self) -> Option<char> {
self.progress.next()
}
pub(crate) fn take_catch(&mut self) -> Catch<'s> {
mem::take(&mut self.catch)
}
}
impl<'s> From<Progress<'s>> for Haul<'s> {
fn from(progress: Progress<'s>) -> Self {
Self {
progress,
catch: Catch::new(),
}
}
}