use super::StreamTokensBuffer;
use crate::StreamTokens;
use alloc::string::String;
use yap::Tokens;
#[derive(Debug)]
pub struct StrStreamTokens<
I: Iterator,
Buffer: StreamTokensBuffer<I::Item> + core::ops::Deref<Target = str>,
>(StreamTokens<I, Buffer>);
impl StreamTokensBuffer<char> for String {
fn drain_front(&mut self, n: usize) {
if n > self.len() {
self.clear()
} else {
self.drain(..n).for_each(drop);
}
}
fn push(&mut self, item: char) {
self.push(item)
}
fn get(&self, idx: usize) -> Option<char> {
self.chars().nth(idx)
}
}
impl<I> StrStreamTokens<I, String>
where
I: Iterator<Item = char>,
I::Item: Clone,
{
pub fn new(iter: I) -> Self {
Self(StreamTokens::_new(iter))
}
}
impl<I, Buffer> Tokens for StrStreamTokens<I, Buffer>
where
I: Iterator,
I::Item: Clone,
Buffer: StreamTokensBuffer<I::Item> + core::ops::Deref<Target = str>,
{
type Item = <StreamTokens<I, Buffer> as Tokens>::Item;
type Location = <StreamTokens<I, Buffer> as Tokens>::Location;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn location(&self) -> Self::Location {
self.0.location()
}
fn set_location(&mut self, location: Self::Location) {
self.0.set_location(location)
}
fn is_at_location(&self, location: &Self::Location) -> bool {
self.0.is_at_location(location)
}
fn parse<Out, Buf>(&mut self) -> Result<Out, <Out as core::str::FromStr>::Err>
where
Out: core::str::FromStr,
Buf: FromIterator<Self::Item> + core::ops::Deref<Target = str>,
{
let from = self.location();
while self.0.next().is_some() {}
let res = self.0.buffer.elements[from.cursor - self.0.buffer.oldest_elem_cursor..].parse();
if res.is_err() {
self.set_location(from)
};
res
}
fn parse_slice<Out, Buf>(
&mut self,
from: Self::Location,
to: Self::Location,
) -> Result<Out, <Out as core::str::FromStr>::Err>
where
Out: core::str::FromStr,
Buf: FromIterator<Self::Item> + core::ops::Deref<Target = str>,
{
self.0.buffer.elements[from.cursor - self.0.buffer.oldest_elem_cursor
..to.cursor - self.0.buffer.oldest_elem_cursor]
.parse()
}
fn parse_take<Out, Buf>(&mut self, n: usize) -> Result<Out, <Out as core::str::FromStr>::Err>
where
Out: core::str::FromStr,
Buf: FromIterator<Self::Item> + core::ops::Deref<Target = str>,
{
let from = self.location();
self.take(n).consume();
let res = self.0.buffer.elements[from.cursor - self.0.buffer.oldest_elem_cursor
..self.0.cursor - self.0.buffer.oldest_elem_cursor]
.parse();
if res.is_err() {
self.set_location(from);
}
res
}
fn parse_take_while<Out, Buf, F>(
&mut self,
take_while: F,
) -> Result<Out, <Out as core::str::FromStr>::Err>
where
Out: core::str::FromStr,
Buf: FromIterator<Self::Item> + core::ops::Deref<Target = str>,
F: FnMut(&Self::Item) -> bool,
{
let from = self.location();
self.take_while(take_while).consume();
let res = self.0.buffer.elements[from.cursor - self.0.buffer.oldest_elem_cursor
..self.0.cursor - self.0.buffer.oldest_elem_cursor]
.parse();
if res.is_err() {
self.set_location(from);
}
res
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn str_tokens_parse_optimizations_work() {
struct BadBuffer;
impl core::iter::FromIterator<char> for BadBuffer {
fn from_iter<T: IntoIterator<Item = char>>(_: T) -> Self {
panic!("FromIterator impl shouldn't be used")
}
}
impl core::ops::Deref for BadBuffer {
type Target = str;
fn deref(&self) -> &Self::Target {
panic!("Deref impl shouldn't be used")
}
}
let mut tokens = StrStreamTokens::new("123".chars());
assert_eq!(tokens.parse::<_, BadBuffer>(), Ok(123));
let mut tokens = StrStreamTokens::new("123abc".chars());
let from = tokens.location();
tokens.take_while(|t| t.is_numeric()).consume();
let to = tokens.location();
let n = tokens
.slice(from, to)
.parse::<u16, BadBuffer>()
.expect("parse worked (1)");
assert_eq!(n, 123);
assert_eq!(tokens.collect::<String>(), "abc");
let mut tokens = StrStreamTokens::new("123abc".chars());
let n = tokens
.take(3)
.parse::<u16, BadBuffer>()
.expect("parse worked (2)");
assert_eq!(n, 123);
assert_eq!(tokens.collect::<String>(), "abc");
let mut tokens = StrStreamTokens::new("123abc".chars());
let n = tokens
.take_while(|t| t.is_numeric())
.parse::<u16, BadBuffer>()
.expect("parse worked (3)");
assert_eq!(n, 123);
assert_eq!(tokens.collect::<String>(), "abc");
let mut tokens = StrStreamTokens::new("123ab+=".chars());
let n = tokens
.take(6)
.take(5)
.take_while(|t| t.is_alphanumeric())
.take_while(|t| t.is_numeric())
.take(2)
.parse::<u16, BadBuffer>()
.expect("parse worked (4)");
assert_eq!(n, 12);
assert_eq!(tokens.collect::<String>(), "3ab+=");
}
}