use crate::Tokens;
pub struct Slice<'a, T: Tokens> {
tokens: &'a mut T,
original: T::Location,
from: T::Location,
to: T::Location,
}
impl<'a, T: Tokens> Slice<'a, T> {
pub(crate) fn new(
tokens: &'a mut T,
current: T::Location,
from: T::Location,
to: T::Location,
) -> Slice<'a, T> {
tokens.set_location(from.clone());
Slice {
tokens,
from,
original: current,
to,
}
}
}
impl<'a, T: Tokens> Tokens for Slice<'a, T> {
type Item = T::Item;
type Location = T::Location;
fn next(&mut self) -> Option<Self::Item> {
if self.tokens.is_at_location(&self.to) {
None
} else {
self.tokens.next()
}
}
fn location(&self) -> Self::Location {
self.tokens.location()
}
fn set_location(&mut self, location: Self::Location) {
self.tokens.set_location(location)
}
fn is_at_location(&self, location: &Self::Location) -> bool {
self.tokens.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 res = self
.tokens
.parse_slice::<Out, Buf>(self.from.clone(), self.to.clone());
if res.is_ok() {
self.set_location(self.to.clone());
}
res
}
}
impl<'a, T: Tokens> Drop for Slice<'a, T> {
fn drop(&mut self) {
self.tokens.set_location(self.original.clone());
}
}
#[cfg(test)]
mod test {
use crate::{IntoTokens, Tokens};
#[test]
fn test_parse_success() {
let mut toks = "345abc".into_tokens();
let from = toks.location();
toks.take_while(|t| t.is_numeric()).consume();
let to = toks.location();
toks.take(1).consume();
let mut s = toks.slice(from, to);
let n = s.parse::<u16, String>().unwrap();
assert_eq!(n, 345);
assert_eq!(s.collect::<String>(), "");
drop(s);
assert_eq!(toks.collect::<String>(), "bc");
}
#[test]
fn test_parse_failure() {
let mut toks = "345abc".into_tokens();
let from = toks.location();
toks.take_while(|t| t.is_numeric()).consume();
let to = toks.location();
toks.take(1).consume();
let mut s = toks.slice(from, to);
s.parse::<u8, String>().unwrap_err();
assert_eq!(s.collect::<String>(), "345");
drop(s);
assert_eq!(toks.collect::<String>(), "bc");
}
}