udled 0.6.2

Tokenizer and parser
Documentation
use core::marker::PhantomData;

use alloc::{boxed::Box, vec::Vec};

use crate::{
    tokenizers::{AsDigits, Many, Opt, Or, Puntuated, Sliced, Spanned, Until},
    AsSlice, Buffer, Error, Item, Reader, Span, Tokenizer,
};

pub trait TokenizerExt<'input, B>: Tokenizer<'input, B>
where
    B: Buffer<'input>,
{
    fn map_ok<F, U>(self, func: F) -> MapOk<Self, F, B>
    where
        F: Fn(Self::Token) -> U,
        Self: Sized,
    {
        MapOk {
            tokenizer: self,
            func,
            ph: PhantomData,
        }
    }

    fn map_err<F, U>(self, func: F) -> MapErr<Self, F, B>
    where
        F: Fn(usize, &B) -> U,
        U: Into<Box<dyn core::error::Error + Send + Sync>>,
        Self: Sized,
    {
        MapErr {
            tokenizer: self,
            func,
            ph: PhantomData,
        }
    }

    fn repeat(self, count: i32) -> Repeat<Self, B>
    where
        Self: Sized,
    {
        Repeat {
            tokenizer: self,
            count,
            ph: PhantomData,
        }
    }

    fn many(self) -> Many<Self, B>
    where
        Self: Sized,
    {
        Many::new(self)
    }

    fn until<U>(self, until: U) -> Until<Self, U, B>
    where
        Self: Sized,
        U: Tokenizer<'input, B>,
    {
        Until::new(self, until)
    }

    fn or<T>(self, other: T) -> Or<Self, T, B>
    where
        Self: Sized,
        T: Tokenizer<'input, B>,
    {
        Or::new(self, other)
    }

    fn optional(self) -> Opt<Self, B>
    where
        Self: Sized,
    {
        Opt::new(self)
    }

    fn spanned(self) -> Spanned<Self, B>
    where
        Self: Sized,
    {
        Spanned::new(self)
    }

    fn into_integer(self, base: u32) -> IntoInteger<Self, B>
    where
        Self: Sized,
        Self::Token: AsDigits,
    {
        IntoInteger {
            tokenizer: self,
            base,
            ph: PhantomData,
        }
    }

    fn punctuated<P>(self, punct: P) -> Puntuated<Self, P>
    where
        Self: Sized,
        P: Tokenizer<'input, B>,
    {
        Puntuated::new(self, punct)
    }

    fn slice(self) -> Sliced<Self, B>
    where
        Self: Sized,
        B: Buffer<'input>,
        B::Source: AsSlice<'input>,
    {
        Sliced::new(self)
    }

    fn parse(&self, reader: &mut Reader<'_, 'input, B>) -> Result<Self::Token, Error>
    where
        Self: Sized,
    {
        reader.parse(self)
    }
}

impl<'input, T, B> TokenizerExt<'input, B> for T
where
    B: Buffer<'input>,
    T: Tokenizer<'input, B>,
{
}

pub struct MapOk<T, F, B> {
    tokenizer: T,
    func: F,
    ph: PhantomData<fn(&B)>,
}

impl<'input, T, F, U, B> Tokenizer<'input, B> for MapOk<T, F, B>
where
    B: Buffer<'input>,
    T: Tokenizer<'input, B>,
    F: Fn(T::Token) -> U,
{
    type Token = U;

    fn eat(&self, reader: &mut crate::Reader<'_, 'input, B>) -> Result<(), crate::Error> {
        self.tokenizer.eat(reader)
    }

    fn peek(&self, reader: &mut crate::Reader<'_, 'input, B>) -> bool {
        self.tokenizer.peek(reader)
    }

    fn to_token(
        &self,
        reader: &mut crate::Reader<'_, 'input, B>,
    ) -> Result<Self::Token, crate::Error> {
        match self.tokenizer.to_token(reader) {
            Ok(ret) => Ok((self.func)(ret)),
            Err(err) => Err(err),
        }
    }
}

pub struct MapErr<T, F, B> {
    tokenizer: T,
    func: F,
    ph: PhantomData<fn(&B)>,
}

impl<'input, T, F, U, B> Tokenizer<'input, B> for MapErr<T, F, B>
where
    B: Buffer<'input>,
    T: Tokenizer<'input, B>,
    F: Fn(usize, &B) -> U,
    U: Into<Box<dyn core::error::Error + Send + Sync>>,
{
    type Token = T::Token;

    fn eat(&self, reader: &mut crate::Reader<'_, 'input, B>) -> Result<(), crate::Error> {
        self.tokenizer
            .eat(reader)
            .map_err(|err| Error::new(err.position(), (self.func)(err.position(), reader.buffer())))
    }

    fn peek(&self, reader: &mut crate::Reader<'_, 'input, B>) -> bool {
        self.tokenizer.peek(reader)
    }

    fn to_token(
        &self,
        reader: &mut crate::Reader<'_, 'input, B>,
    ) -> Result<Self::Token, crate::Error> {
        self.tokenizer
            .to_token(reader)
            .map_err(|err| Error::new(err.position(), (self.func)(err.position(), reader.buffer())))
    }
}

pub struct IntoInteger<T, B> {
    tokenizer: T,
    base: u32,
    ph: PhantomData<fn(&B)>,
}

impl<'input, T, B> Tokenizer<'input, B> for IntoInteger<T, B>
where
    B: Buffer<'input>,
    T: Tokenizer<'input, B>,
    T::Token: AsDigits,
{
    type Token = Item<i128>;

    fn eat(&self, reader: &mut crate::Reader<'_, 'input, B>) -> Result<(), crate::Error> {
        self.tokenizer.eat(reader)
    }

    fn peek(&self, reader: &mut crate::Reader<'_, 'input, B>) -> bool {
        self.tokenizer.peek(reader)
    }

    fn to_token(
        &self,
        reader: &mut crate::Reader<'_, 'input, B>,
    ) -> Result<Self::Token, crate::Error> {
        let start = reader.position();
        let digits = self.tokenizer.to_token(reader)?;
        let end = reader.position();
        let mut val = 0i128;

        for digit in digits.digits() {
            val = (self.base as i128) * val + (digit as i128);
        }

        Ok(Item::new(Span::new(start, end), val))
    }
}

pub struct Repeat<T, B> {
    tokenizer: T,
    count: i32,
    ph: PhantomData<fn(&B)>,
}

impl<'input, T, B> Tokenizer<'input, B> for Repeat<T, B>
where
    B: Buffer<'input>,
    T: Tokenizer<'input, B>,
{
    type Token = Item<Vec<T::Token>>;

    fn eat(&self, reader: &mut crate::Reader<'_, 'input, B>) -> Result<(), crate::Error> {
        let mut count = 0;
        loop {
            self.tokenizer.eat(reader)?;
            count += 1;
            if count == self.count as usize {
                break;
            }
        }

        Ok(())
    }

    fn peek(&self, reader: &mut crate::Reader<'_, 'input, B>) -> bool {
        self.tokenizer.peek(reader)
    }

    fn to_token(
        &self,
        reader: &mut crate::Reader<'_, 'input, B>,
    ) -> Result<Self::Token, crate::Error> {
        let start = reader.position();

        let mut output = Vec::with_capacity(self.count as _);
        loop {
            let next = self.tokenizer.parse(reader)?;
            output.push(next);
            if output.len() == self.count as usize {
                break;
            }
        }

        let end = reader.position();

        Ok(Item::new(Span::new(start, end), output))
    }
}