pub struct SplitPreserveWS<'a> {
string: Option<Token<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Token<'a> {
Whitespace(&'a str),
Other(&'a str),
}
impl<'a> SplitPreserveWS<'a> {
pub fn new(string: &'a str) -> Self {
if string.is_empty() {
Self { string: None }
} else if string.starts_with(char::is_whitespace) {
Self {
string: Some(Token::Whitespace(string)),
}
} else {
Self {
string: Some(Token::Other(string)),
}
}
}
pub fn map_words<S>(self, mut f: S) -> std::iter::Map<Self, impl FnMut(Token<'a>) -> String>
where
S: FnMut(&str) -> String,
{
self.map(move |t: Token<'a>| match t {
Token::Other(s) => f(s),
Token::Whitespace(s) => s.to_string(),
})
}
pub fn map_whitespace<S>(
self,
mut f: S,
) -> std::iter::Map<Self, impl FnMut(Token<'a>) -> String>
where
S: FnMut(&str) -> String,
{
self.map(move |t: Token<'a>| match t {
Token::Other(s) => s.to_string(),
Token::Whitespace(s) => f(s),
})
}
}
impl<'a> Iterator for SplitPreserveWS<'a> {
type Item = Token<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.string.take().map(|t| match t {
Token::Whitespace(s) => {
let (token, rest) = match s.find(|c: char| !c.is_whitespace()) {
Some(i) => {
let (a, b) = s.split_at(i);
(a, Some(Token::Other(b)))
}
None => (s, None),
};
self.string = rest;
Token::Whitespace(token)
}
Token::Other(s) => {
let (token, rest) = match s.find(char::is_whitespace) {
Some(i) => {
let (a, b) = s.split_at(i);
(a, Some(Token::Whitespace(b)))
}
None => (s, None),
};
self.string = rest;
Token::Other(token)
}
})
}
}