udled 0.6.2

Tokenizer and parser
Documentation
use alloc::vec::Vec;

use crate::{tokenizers::Peek, Buffer, Error, Reader, Span, Tokenizer, WithSpan};

#[derive(Debug, Clone, Copy)]
pub enum PuntuatedItem<T, P> {
    Item(T),
    Punct(P),
}

impl<T: WithSpan, P: WithSpan> WithSpan for PuntuatedItem<T, P> {
    fn span(&self) -> Span {
        match self {
            PuntuatedItem::Item(item) => item.span(),
            PuntuatedItem::Punct(punct) => punct.span(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct PunctuatedList<T, P> {
    list: Vec<PuntuatedItem<T, P>>,
    span: Span,
}

impl<T, P> PunctuatedList<T, P> {
    pub fn items(&self) -> impl Iterator<Item = &T> {
        self.list.iter().filter_map(|m| match m {
            PuntuatedItem::Item(item) => Some(item),
            _ => None,
        })
    }

    pub fn into_items(self) -> impl Iterator<Item = T> {
        self.list.into_iter().filter_map(|m| match m {
            PuntuatedItem::Item(item) => Some(item),
            _ => None,
        })
    }

    pub fn iter(&self) -> core::slice::Iter<'_, PuntuatedItem<T, P>> {
        self.list.iter()
    }

    pub fn len(&self) -> usize {
        self.list.len()
    }

    pub fn is_empty(&self) -> bool {
        self.list.is_empty()
    }
}

impl<T, P> WithSpan for PunctuatedList<T, P> {
    fn span(&self) -> Span {
        self.span
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Puntuated<T, P> {
    item: T,
    punct: P,
    non_empty: bool,
}

impl<T, P> Puntuated<T, P> {
    pub const fn new(item: T, punct: P) -> Puntuated<T, P> {
        Puntuated {
            item,
            punct,
            non_empty: false,
        }
    }
}

impl<'input, T, P, B> Tokenizer<'input, B> for Puntuated<T, P>
where
    B: Buffer<'input>,
    T: Tokenizer<'input, B>,
    P: Tokenizer<'input, B>,
{
    type Token = PunctuatedList<T::Token, P::Token>;

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

        if self.non_empty {
            let item = reader.parse(&self.item)?;
            output.push(PuntuatedItem::Item(item));
            if reader.is(Peek((&self.punct, &self.item))) {
                let punct = reader.parse(&self.punct)?;
                output.push(PuntuatedItem::Punct(punct));
            }
        }

        loop {
            if !reader.is(&self.item) {
                break;
            }

            let item = reader.parse(&self.item)?;

            output.push(PuntuatedItem::Item(item));

            if reader.is(Peek((&self.punct, &self.item))) {
                let punct = reader.parse(&self.punct)?;
                output.push(PuntuatedItem::Punct(punct));
            }
        }

        let end = reader.position();

        Ok(PunctuatedList {
            list: output,
            span: Span::new(start, end),
        })
    }
}