use crate::{
info::Info,
separator::{Separator, SepInfo},
};
use core::num::NonZeroUsize;
pub struct Splitter<'a, T, I, S, F = fn(&'a [T]) -> NonZeroUsize>
where
I: Info<'a, T>,
S: Separator<T>,
F: Fn(&'a [T]) -> NonZeroUsize,
{
cursor: usize,
content: &'a [T],
sep: S,
ctx: I::Context,
next: Option<NonZeroUsize>,
increment: F,
}
impl<'a, T, S> Splitter<'a, T, &'a [T], S>
where
S: Separator<T>,
{
pub fn new(content: &'a [T], sep: S) -> Self {
const fn increment<T>(_: &[T]) -> NonZeroUsize {
unsafe { NonZeroUsize::new_unchecked(1) }
}
Self { cursor: 0, content, sep, ctx: (), next: None, increment }
}
}
impl<'a, T, H, S, E> Splitter<'a, T, H, S, E>
where
H: Info<'a, T>,
S: Separator<T>,
E: Fn(&'a [T]) -> NonZeroUsize,
{
pub fn with_info<I: Info<'a, T>>(self) -> Splitter<'a, T, I, S, E> {
Splitter {
cursor: self.cursor,
content: self.content,
sep: self.sep,
ctx: I::Context::default(),
next: self.next,
increment: self.increment,
}
}
pub(crate) fn with_increment<F>(self, increment: F) -> Splitter<'a, T, H, S, F>
where
F: Fn(&'a [T]) -> NonZeroUsize,
{
Splitter {
cursor: self.cursor,
content: self.content,
sep: self.sep,
ctx: self.ctx,
next: self.next,
increment,
}
}
}
impl<'a, T, I, S, F> Iterator for Splitter<'a, T, I, S, F>
where
I: Info<'a, T>,
S: Separator<T>,
F: Fn(&'a [T]) -> NonZeroUsize,
{
type Item = I;
fn next(&mut self) -> Option<Self::Item> {
let con = &self.content[self.cursor..];
self.next.take().map(|len| {
let len = len.get();
self.cursor += len;
I::generate(&mut self.ctx, &con[..len])
}).or_else(|| {
let con_len = con.len();
(con_len != 0).then(|| {
match self.sep.separate(con) {
Some(SepInfo { pos: 0, size }) => {
let size = NonZeroUsize::new(size)
.unwrap_or_else(|| (self.increment)(con))
.get();
self.cursor += size;
I::generate(&mut self.ctx, &con[..size])
}
Some(SepInfo { pos, size }) => {
self.cursor += pos;
self.next = Some(NonZeroUsize::new(size)
.unwrap_or_else(|| (self.increment)(con)));
I::generate(&mut self.ctx, &con[..pos])
},
None => {
self.cursor += con_len;
I::generate(&mut self.ctx, con)
}
}
})
})
}
}