mod many;
mod many_err;
mod sep_by;
mod sep_by_all;
mod sep_by_all_err;
mod sep_by_err;
mod slice;
mod take;
mod take_while;
use core::borrow::Borrow;
use core::ops::Deref;
use core::str::FromStr;
pub use many::Many;
pub use many_err::ManyErr;
pub use sep_by::SepBy;
pub use sep_by_all::SepByAll;
pub use sep_by_all_err::SepByAllErr;
pub use sep_by_err::SepByErr;
pub use slice::Slice;
pub use take::Take;
pub use take_while::TakeWhile;
use crate::types::{WithContext, WithContextMut};
pub trait Tokens: Sized {
type Item;
type Location: TokenLocation + PartialEq + core::fmt::Debug + Clone;
fn next(&mut self) -> Option<Self::Item>;
fn location(&self) -> Self::Location;
fn set_location(&mut self, location: Self::Location);
fn is_at_location(&self, location: &Self::Location) -> bool;
fn as_iter(&'_ mut self) -> TokensAsIter<'_, Self> {
TokensAsIter { tokens: self }
}
fn into_iter(self) -> TokensIntoIter<Self> {
TokensIntoIter { tokens: self }
}
fn parse<Out, Buf>(&mut self) -> Result<Out, <Out as FromStr>::Err>
where
Out: FromStr,
Buf: FromIterator<Self::Item> + Deref<Target = str>,
{
self.optional_err(|toks| toks.collect::<Buf>().parse::<Out>())
}
#[doc(hidden)]
fn parse_slice<Out, Buf>(
&mut self,
from: Self::Location,
to: Self::Location,
) -> Result<Out, <Out as FromStr>::Err>
where
Out: FromStr,
Buf: FromIterator<Self::Item> + Deref<Target = str>,
{
self.slice(from, to).collect::<Buf>().parse::<Out>()
}
#[doc(hidden)]
fn parse_take_while<Out, Buf, F>(&mut self, take_while: F) -> Result<Out, <Out as FromStr>::Err>
where
Out: FromStr,
Buf: FromIterator<Self::Item> + Deref<Target = str>,
F: FnMut(&Self::Item) -> bool,
{
self.optional_err(|toks| toks.take_while(take_while).collect::<Buf>().parse::<Out>())
}
#[doc(hidden)]
fn parse_take<Out, Buf>(&mut self, n: usize) -> Result<Out, <Out as FromStr>::Err>
where
Out: FromStr,
Buf: FromIterator<Self::Item> + Deref<Target = str>,
{
self.optional_err(|toks| toks.take(n).collect::<Buf>().parse::<Out>())
}
fn with_context<C>(self, context: C) -> WithContext<Self, C> {
WithContext::new(self, context)
}
fn with_context_mut<C>(&mut self, context: C) -> WithContextMut<&mut Self, C> {
WithContextMut::new(self, context)
}
fn slice(&'_ mut self, from: Self::Location, to: Self::Location) -> Slice<'_, Self> {
Slice::new(self, self.location(), from, to)
}
fn offset(&self) -> usize {
self.location().offset()
}
fn peek(&mut self) -> Option<Self::Item> {
let location = self.location();
let item = self.next();
self.set_location(location);
item
}
fn token<I>(&mut self, t: I) -> bool
where
Self::Item: PartialEq,
I: Borrow<Self::Item>,
{
let location = self.location();
match self.next() {
Some(item) if &item == t.borrow() => true,
_ => {
self.set_location(location);
false
}
}
}
fn tokens<It>(&mut self, ts: It) -> bool
where
Self::Item: PartialEq,
It: IntoIterator,
It::Item: Borrow<Self::Item>,
{
let location = self.location();
let ts_iter = ts.into_iter();
for expected in ts_iter {
match self.next() {
Some(actual) => {
if &actual != expected.borrow() {
self.set_location(location);
return false;
}
}
None => {
self.set_location(location);
return false;
}
}
}
true
}
fn one_of_tokens<It>(&mut self, ts: It) -> Option<Self::Item>
where
Self::Item: PartialEq,
It: IntoIterator,
It::Item: Borrow<Self::Item>,
{
for expected in ts.into_iter() {
let location = self.location();
match self.next() {
Some(token) if &token == expected.borrow() => return Some(token),
_ => {
self.set_location(location);
}
}
}
None
}
fn take(&'_ mut self, n: usize) -> Take<'_, Self> {
Take::new(self, n)
}
fn take_while<F>(&'_ mut self, f: F) -> TakeWhile<'_, Self, F>
where
F: FnMut(&Self::Item) -> bool,
{
TakeWhile::new(self, f)
}
fn skip_while<F>(&mut self, f: F) -> usize
where
F: FnMut(&Self::Item) -> bool,
{
self.take_while(f).as_iter().count()
}
fn many<F, Output>(&mut self, parser: F) -> Many<Self, F>
where
F: FnMut(&mut Self) -> Option<Output>,
{
Many::new(self, parser)
}
fn many_err<F, Output, E>(&'_ mut self, parser: F) -> ManyErr<'_, Self, F>
where
F: FnMut(&mut Self) -> Result<Output, E>,
{
ManyErr::new(self, parser)
}
fn skip_many<F>(&mut self, mut parser: F) -> usize
where
F: FnMut(&mut Self) -> bool,
{
self.many(|t| parser(t).then_some(())).as_iter().count()
}
fn skip_many1<F, E, Ignored>(&mut self, parser: F) -> Result<usize, E>
where
F: FnMut(&mut Self) -> Result<Ignored, E>,
{
let mut toks = self.many_err(parser);
if let Some(Err(e)) = toks.next() {
return Err(e);
}
let n_skipped = toks.as_iter().count();
Ok(n_skipped)
}
fn sep_by<F, S, Output>(&'_ mut self, parser: F, separator: S) -> SepBy<'_, Self, F, S>
where
F: FnMut(&mut Self) -> Option<Output>,
S: FnMut(&mut Self) -> bool,
{
SepBy::new(self, parser, separator)
}
fn sep_by_err<F, S, E, Output>(
&'_ mut self,
parser: F,
separator: S,
) -> SepByErr<'_, Self, F, S>
where
F: FnMut(&mut Self) -> Result<Output, E>,
S: FnMut(&mut Self) -> bool,
{
SepByErr::new(self, parser, separator)
}
fn sep_by_all<F, S, Output>(
&'_ mut self,
parser: F,
separator: S,
) -> SepByAll<'_, Self, F, S, Output>
where
F: FnMut(&mut Self) -> Option<Output>,
S: FnMut(&mut Self) -> Option<Output>,
{
SepByAll::new(self, parser, separator)
}
fn sep_by_all_err<F, S, Output, E>(
&'_ mut self,
parser: F,
separator: S,
) -> SepByAllErr<'_, Self, F, S, Output>
where
F: FnMut(&mut Self) -> Result<Output, E>,
S: FnMut(&mut Self) -> Option<Output>,
{
SepByAllErr::new(self, parser, separator)
}
fn surrounded_by<F, S, Output>(&mut self, parser: F, mut surrounding: S) -> Output
where
F: FnOnce(&mut Self) -> Output,
S: FnMut(&mut Self),
{
surrounding(self);
let res = parser(self);
surrounding(self);
res
}
fn optional<F, Output>(&mut self, f: F) -> Output
where
F: FnOnce(&mut Self) -> Output,
Output: crate::one_of::IsMatch,
{
let location = self.location();
if let Some(output) = f(self).into_match() {
output
} else {
self.set_location(location);
crate::one_of::IsMatch::match_failure()
}
}
fn optional_err<F, Output, Error>(&mut self, f: F) -> Result<Output, Error>
where
F: FnOnce(&mut Self) -> Result<Output, Error>,
{
let location = self.location();
match f(self) {
Ok(output) => Ok(output),
Err(err) => {
self.set_location(location);
Err(err)
}
}
}
fn eof(&mut self) -> bool {
self.optional(|t| t.next().is_none().then_some(()))
.is_some()
}
fn consume(&mut self) {
self.as_iter().for_each(drop)
}
fn collect<B: FromIterator<Self::Item>>(&mut self) -> B {
self.as_iter().collect()
}
}
pub trait TokenLocation {
fn offset(&self) -> usize;
}
pub trait IntoTokens<Item> {
type Tokens: Tokens<Item = Item>;
fn into_tokens(self) -> Self::Tokens;
}
pub struct TokensAsIter<'a, T> {
tokens: &'a mut T,
}
impl<'a, T: Tokens> Iterator for TokensAsIter<'a, T> {
type Item = T::Item;
fn next(&mut self) -> Option<Self::Item> {
self.tokens.next()
}
}
pub struct TokensIntoIter<T> {
tokens: T,
}
impl<T: Tokens> Iterator for TokensIntoIter<T> {
type Item = T::Item;
fn next(&mut self) -> Option<Self::Item> {
self.tokens.next()
}
}
#[cfg(all(test, feature = "std"))]
mod test {
use crate::types::IterTokens;
use super::*;
#[derive(Debug, PartialEq)]
struct AB;
fn parse_ab(t: &mut impl Tokens<Item = char>) -> Option<AB> {
let a = t.next()?;
let b = t.next()?;
if a == 'a' && b == 'b' {
Some(AB)
} else {
None
}
}
fn parse_ab_err(t: &mut impl Tokens<Item = char>) -> Result<AB, ABErr> {
let a = t.next().ok_or(ABErr::NotEnoughTokens)?;
let b = t.next().ok_or(ABErr::NotEnoughTokens)?;
if a != 'a' {
Err(ABErr::IsNotA)
} else if b != 'b' {
Err(ABErr::IsNotB)
} else {
Ok(AB)
}
}
#[derive(Debug, PartialEq)]
enum ABErr {
NotEnoughTokens,
IsNotA,
IsNotB,
}
#[test]
fn test_tokens_fails_if_eof() {
let mut t = "hi".into_tokens();
assert!(!t.tokens("hip".chars()));
}
#[test]
#[allow(clippy::needless_collect)]
fn test_many() {
let mut t = "".into_tokens();
let abs: Vec<_> = t.many(parse_ab).collect();
let rest: Vec<char> = t.collect();
assert_eq!(abs.len(), 0);
assert_eq!(rest, vec![]);
let mut t = "acabab".into_tokens();
let abs: Vec<_> = t.many(parse_ab).collect();
let rest: Vec<char> = t.collect();
assert_eq!(abs.len(), 0);
assert_eq!(rest, vec!['a', 'c', 'a', 'b', 'a', 'b']);
let mut t = "abababaa".into_tokens();
let abs: Vec<_> = t.many(parse_ab).collect();
let rest: Vec<char> = t.collect();
assert_eq!(abs.len(), 3);
assert_eq!(rest, vec!['a', 'a']);
let mut t = "abababa".into_tokens();
let abs: Vec<_> = t.many(parse_ab).collect();
let rest: Vec<char> = t.collect();
assert_eq!(abs.len(), 3);
assert_eq!(rest, vec!['a']);
}
#[test]
#[allow(clippy::needless_collect)]
fn test_many_err() {
let mut t = "".into_tokens();
let abs: Vec<_> = t.many_err(parse_ab_err).collect();
let rest: Vec<char> = t.collect();
assert_eq!(abs, vec![Err(ABErr::NotEnoughTokens)]);
assert_eq!(rest, vec![]);
let mut t = "ccabab".into_tokens();
let abs: Vec<_> = t.many_err(parse_ab_err).collect();
let rest: Vec<char> = t.collect();
assert_eq!(abs, vec![Err(ABErr::IsNotA)]);
assert_eq!(rest, vec!['c', 'c', 'a', 'b', 'a', 'b']);
let mut t = "acabab".into_tokens();
let abs: Vec<_> = t.many_err(parse_ab_err).collect();
let rest: Vec<char> = t.collect();
assert_eq!(abs, vec![Err(ABErr::IsNotB)]);
assert_eq!(rest, vec!['a', 'c', 'a', 'b', 'a', 'b']);
let mut t = "abababaa".into_tokens();
let abs: Vec<_> = t.many_err(parse_ab_err).collect();
let rest: Vec<char> = t.collect();
assert_eq!(abs, vec![Ok(AB), Ok(AB), Ok(AB), Err(ABErr::IsNotB)]);
assert_eq!(rest, vec!['a', 'a']);
let mut t = "abababa".into_tokens();
let abs: Vec<_> = t.many_err(parse_ab_err).collect();
let rest: Vec<char> = t.collect();
assert_eq!(
abs,
vec![Ok(AB), Ok(AB), Ok(AB), Err(ABErr::NotEnoughTokens)]
);
assert_eq!(rest, vec!['a']);
}
#[test]
fn test_skip_many() {
let mut t = "".into_tokens();
let n_skipped = t.skip_many(|t| parse_ab(t).is_some());
let rest: Vec<char> = t.collect();
assert_eq!(n_skipped, 0);
assert_eq!(rest, vec![]);
let mut t = "acabab".into_tokens();
let n_skipped = t.skip_many(|t| parse_ab(t).is_some());
let rest: Vec<char> = t.collect();
assert_eq!(n_skipped, 0);
assert_eq!(rest, vec!['a', 'c', 'a', 'b', 'a', 'b']);
let mut t = "ababaab".into_tokens();
let n_skipped = t.skip_many(|t| parse_ab(t).is_some());
let rest: Vec<char> = t.collect();
assert_eq!(n_skipped, 2);
assert_eq!(rest, vec!['a', 'a', 'b']);
}
#[test]
fn test_skip_many1() {
let mut t = "".into_tokens();
let res = t.skip_many1(parse_ab_err);
let rest: String = t.collect();
assert_eq!(res, Err(ABErr::NotEnoughTokens));
assert_eq!(&*rest, "");
let mut t = "acabab".into_tokens();
let res = t.skip_many1(parse_ab_err);
let rest: String = t.collect();
assert_eq!(res, Err(ABErr::IsNotB));
assert_eq!(&*rest, "acabab");
let mut t = "abcbab".into_tokens();
let res = t.skip_many1(parse_ab_err);
let rest: String = t.collect();
assert_eq!(res, Ok(1));
assert_eq!(&*rest, "cbab");
let mut t = "ababcbab".into_tokens();
let res = t.skip_many1(parse_ab_err);
let rest: String = t.collect();
assert_eq!(res, Ok(2));
assert_eq!(&*rest, "cbab");
}
#[test]
fn test_parse_optimisations() {
const S: &str = "345abc456";
fn parse_slice(mut tokens: impl Tokens<Item = char>) {
let from = tokens.location();
tokens.take_while(|t| t.is_numeric()).consume();
let to = tokens.location();
tokens.set_location(from.clone());
let n = tokens
.parse_slice::<u16, String>(from.clone(), to.clone())
.unwrap();
assert_eq!(n, 345);
assert_eq!(tokens.collect::<String>(), S);
tokens.set_location(from.clone());
tokens.parse_slice::<u8, String>(from, to).unwrap_err();
assert_eq!(tokens.collect::<String>(), S);
}
fn parse_take_while(mut tokens: impl Tokens<Item = char>) {
let start = tokens.location();
let n = tokens
.parse_take_while::<u16, String, _>(|t| t.is_numeric())
.unwrap();
assert_eq!(n, 345);
assert_eq!(tokens.collect::<String>(), "abc456");
tokens.set_location(start);
tokens
.parse_take_while::<u8, String, _>(|t| t.is_numeric())
.unwrap_err();
assert_eq!(tokens.collect::<String>(), "345abc456");
}
fn parse_take(mut tokens: impl Tokens<Item = char>) {
let start = tokens.location();
let n = tokens.parse_take::<u16, String>(3).unwrap();
assert_eq!(n, 345);
assert_eq!(tokens.collect::<String>(), "abc456");
tokens.set_location(start);
tokens.parse_take::<u8, String>(3).unwrap_err();
assert_eq!(tokens.collect::<String>(), "345abc456");
}
parse_slice(IterTokens::new(S.chars()));
parse_slice(S.into_tokens());
parse_take_while(IterTokens::new(S.chars()));
parse_take_while(S.into_tokens());
parse_take(IterTokens::new(S.chars()));
parse_take(S.into_tokens());
}
}