proclet/
punctuated.rs

1use crate::{
2    Error, IntoTokens, Parse, Parser, ToTokenStream, TokenStream, TokenTree, TokenTreeExt,
3};
4use std::{marker::PhantomData, ops::Deref};
5
6/// Parsed punctuated values.
7#[derive(Clone, Default, Debug)]
8pub struct Punctuated<M, D>(Vec<(M, Option<D>)>);
9
10impl<M, D> Punctuated<M, D> {
11    /// Create a new empty set of punctuated values.
12    #[inline]
13    pub const fn new() -> Self {
14        Self(Vec::new())
15    }
16
17    /// Get the contents as a slice.
18    #[inline]
19    pub fn as_slice(&self) -> &[(M, Option<D>)] {
20        &self.0
21    }
22}
23
24impl<M, D> Deref for Punctuated<M, D> {
25    type Target = [(M, Option<D>)];
26
27    #[inline]
28    fn deref(&self) -> &Self::Target {
29        &self.0
30    }
31}
32
33impl<M, D> IntoIterator for Punctuated<M, D> {
34    type Item = (M, Option<D>);
35    type IntoIter = <Vec<(M, Option<D>)> as IntoIterator>::IntoIter;
36
37    #[inline]
38    fn into_iter(self) -> Self::IntoIter {
39        self.0.into_iter()
40    }
41}
42
43impl<T: TokenTreeExt, M: Parse<T>, D: Parse<T>> Parse<T> for Punctuated<M, D> {
44    #[inline]
45    fn parse(buf: &mut &crate::TokenBuf<T>) -> Result<Self, Error<T::Span>> {
46        punctuated(M::parser(), D::parser()).parse(buf)
47    }
48}
49
50impl<T: TokenTree, M: IntoTokens<T>, D: IntoTokens<T>> IntoTokens<T> for Punctuated<M, D> {
51    #[inline]
52    fn into_tokens(self) -> impl Iterator<Item = T>
53    where
54        Self: Sized,
55    {
56        self.0.into_iter().flat_map(|i| i.into_tokens())
57    }
58}
59
60impl<T: TokenStream, M: ToTokenStream<T>, D: ToTokenStream<T>> ToTokenStream<T>
61    for Punctuated<M, D>
62{
63    #[inline]
64    fn extend_token_stream(&self, token_stream: &mut T) {
65        for (m, d) in self.0.iter() {
66            m.extend_token_stream(token_stream);
67            d.extend_token_stream(token_stream);
68        }
69    }
70}
71
72/// Parser for punctuated values.
73#[derive(Clone, Debug)]
74pub struct PunctuatedParser<T: TokenTree, M, D>(M, D, PhantomData<fn() -> T>);
75
76impl<T: TokenTreeExt, M: Parser<T>, D: Parser<T>> PunctuatedParser<T, M, D> {
77    /// Create a new `PunctuatedParser` using `main` as the parser for the main part and
78    /// `delim` as the parser for the delimiter.
79    #[inline]
80    pub const fn new(main: M, delim: D) -> Self {
81        Self(main, delim, PhantomData)
82    }
83}
84
85impl<T: TokenTreeExt, M: Parser<T>, D: Parser<T>> Parser<T> for PunctuatedParser<T, M, D> {
86    type Output<'p, 'b> = Punctuated<M::Output<'p, 'b>, D::Output<'p, 'b>> where Self: 'p;
87
88    #[inline]
89    fn parse<'p, 'b>(
90        &'p self,
91        buf: &mut &'b crate::TokenBuf<T>,
92    ) -> Result<Self::Output<'p, 'b>, Error<T::Span>> {
93        let mut vec = Vec::new();
94        let main = self.0.parse(buf)?;
95        let delim = self.1.parse(buf).ok();
96        let got_delim = delim.is_some();
97        vec.push((main, delim));
98        if got_delim {
99            while let Ok(main) = self.0.parse(buf) {
100                let delim = self.1.parse(buf).ok();
101                let got_delim = delim.is_some();
102                vec.push((main, delim));
103                if !got_delim {
104                    break;
105                }
106            }
107        }
108        Ok(Punctuated(vec))
109    }
110}
111
112/// Create a new parser for parsing things with `main` punctuated by `delim`.
113/// Convenience function for calling [`PunctuatedParser::new`].
114#[inline]
115pub const fn punctuated<T: TokenTreeExt, M: Parser<T>, D: Parser<T>>(
116    main: M,
117    delim: D,
118) -> PunctuatedParser<T, M, D> {
119    PunctuatedParser::new(main, delim)
120}