use crate::{
iter::{ConstIntoIter, IsIteratorKind},
string::{self, str_from, str_up_to, Pattern, PatternNorm},
};
use konst_kernel::iterator_shared;
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))]
pub const fn split_terminator<'a, 'p, P>(this: &'a str, delim: P) -> SplitTerminator<'a, 'p, P>
where
P: Pattern<'p>,
{
let delim = PatternNorm::new(delim);
SplitTerminator {
this,
state: if delim.as_str().is_empty() {
State::Empty(EmptyState::Start)
} else {
State::Normal { delim }
},
}
}
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))]
pub const fn rsplit_terminator<'a, 'p, P>(this: &'a str, delim: P) -> RSplitTerminator<'a, 'p, P>
where
P: Pattern<'p>,
{
let SplitTerminator { this, state } = split_terminator(this, delim);
RSplitTerminator { this, state }
}
#[derive(Copy, Clone)]
enum State<'p, P: Pattern<'p>> {
Normal { delim: PatternNorm<'p, P> },
Empty(EmptyState),
}
#[derive(Copy, Clone)]
enum EmptyState {
Start,
Continue,
}
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))]
pub struct SplitTerminator<'a, 'p, P: Pattern<'p>> {
this: &'a str,
state: State<'p, P>,
}
impl<'a, 'p, P: Pattern<'p>> ConstIntoIter for SplitTerminator<'a, 'p, P> {
type Kind = IsIteratorKind;
type IntoIter = Self;
type Item = &'a str;
}
impl<'a, 'p, P: Pattern<'p>> SplitTerminator<'a, 'p, P> {
iterator_shared! {
is_forward = true,
item = &'a str,
iter_forward = SplitTerminator<'a, 'p, P>,
next(self){
let Self {
this,
state,
} = self;
match state {
State::Empty(EmptyState::Start) => {
self.state = State::Empty(EmptyState::Continue);
Some(("", self))
}
_ if this.is_empty() => {
None
}
State::Normal{delim} => {
let delim = delim.as_str();
let (next, ret) = match string::find(this, delim) {
Some(pos) => (pos + delim.len(), pos),
None => (this.len(), this.len()),
};
self.this = str_from(this, next);
Some((str_up_to(this, ret), self))
}
State::Empty(EmptyState::Continue) => {
use konst_kernel::string::__find_next_char_boundary;
let next_char = __find_next_char_boundary(self.this.as_bytes(), 0);
let (next_char, rem) = string::split_at(self.this, next_char);
self.this = rem;
Some((next_char, self))
}
}
},
fields = {this, state},
}
pub const fn remainder(&self) -> &'a str {
self.this
}
}
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))]
pub struct RSplitTerminator<'a, 'p, P: Pattern<'p>> {
this: &'a str,
state: State<'p, P>,
}
impl<'a, 'p, P: Pattern<'p>> ConstIntoIter for RSplitTerminator<'a, 'p, P> {
type Kind = IsIteratorKind;
type IntoIter = Self;
type Item = &'a str;
}
impl<'a, 'p, P: Pattern<'p>> RSplitTerminator<'a, 'p, P> {
iterator_shared! {
is_forward = true,
item = &'a str,
iter_forward = RSplitTerminator<'a, 'p>,
next(self){
let Self {
this,
state,
} = self;
match state {
State::Empty(EmptyState::Start) => {
self.state = State::Empty(EmptyState::Continue);
Some(("", self))
}
_ if this.is_empty() => {
None
}
State::Normal{delim} => {
let delim = delim.as_str();
let (next, ret) = match string::rfind(this, delim) {
Some(pos) => (pos, pos + delim.len()),
None => (0, 0),
};
self.this = str_up_to(this, next);
Some((str_from(this, ret), self))
}
State::Empty(EmptyState::Continue) => {
use konst_kernel::string::__find_prev_char_boundary;
let bytes = self.this.as_bytes();
let next_char = __find_prev_char_boundary(bytes, bytes.len());
let (rem, next_char) = string::split_at(self.this, next_char);
self.this = rem;
Some((next_char, self))
}
}
},
fields = {this, state},
}
pub const fn remainder(&self) -> &'a str {
self.this
}
}