noa_parser/
separated_list.rs

1use crate::errors::{ParseError, ParseResult};
2use crate::scanner::Scanner;
3use crate::visitor::Visitor;
4use std::marker::PhantomData;
5
6#[derive(Debug)]
7pub struct SeparatedList<T, V, S> {
8    pub data: Vec<V>,
9    separator: PhantomData<(S, T)>,
10}
11
12enum YieldResult<V> {
13    Last(V),
14    MaybeNext(V),
15}
16
17impl<T, V, S> SeparatedList<T, V, S> {
18    /// Consume the `SeparatedList` and return an iterator over the elements.
19    ///
20    /// # Returns
21    ///
22    /// An iterator over the elements of the `SeparatedList`.
23    pub fn into_iter(self) -> impl Iterator<Item = V> {
24        self.data.into_iter()
25    }
26}
27
28/// Yield the next element in the list and tell if it's the last one.
29///
30/// # Type Parameters
31///
32/// * `T` - The type of the data to scan.
33/// * `V` - The type of the element to yield.
34/// * `S` - The type of the separator to consume.
35///
36/// # Arguments
37///
38/// * `scanner` - The scanner to use.
39///
40/// # Returns
41///
42/// A `YieldResult` containing the element and whether it's the last one.
43///
44/// # Errors
45///
46/// Any error the visitor for the element or the separator returns.
47fn yield_element<'a, T, V, S>(scanner: &mut Scanner<'a, T>) -> ParseResult<YieldResult<V>>
48where
49    V: Visitor<'a, T>,
50    S: Visitor<'a, T>,
51{
52    let cursor = scanner.current_position();
53    let element = match scanner.visit::<V>() {
54        Ok(element) => element,
55        Err(err) => {
56            scanner.jump_to(cursor);
57            return Err(err);
58        }
59    };
60
61    if scanner.remaining().is_empty() {
62        return Ok(YieldResult::Last(element));
63    }
64
65    // consume the separator if not the end of the slice
66    scanner.visit::<S>()?;
67
68    Ok(YieldResult::MaybeNext(element))
69}
70
71impl<'a, T, V, S> Visitor<'a, T> for SeparatedList<T, V, S>
72where
73    V: Visitor<'a, T>,
74    S: Visitor<'a, T>,
75{
76    /// Accept a list of elements separated by a separator.
77    ///
78    /// # Arguments
79    ///
80    /// * `scanner` - The scanner to use.
81    ///
82    /// # Returns
83    ///
84    /// A `ParseResult` containing the accepted `SeparatedList` on success, or
85    /// an error on failure.
86    ///
87    /// # Errors
88    ///
89    /// Any error the visitor for the element or the separator returns, or
90    /// `ParseError::UnexpectedToken` if the scanner is empty when attempting
91    /// to parse the separator.
92    fn accept(scanner: &mut Scanner<'a, T>) -> ParseResult<Self> {
93        let mut elements = vec![];
94        let cursor = scanner.current_position();
95
96        // if the scanner is empty, return an empty list
97        if scanner.remaining().is_empty() {
98            return Ok(SeparatedList {
99                data: elements,
100                separator: PhantomData,
101            });
102        }
103
104        loop {
105            if let Ok(result) = yield_element::<T, V, S>(scanner) {
106                let element: YieldResult<V> = result;
107
108                match element {
109                    YieldResult::Last(element) => {
110                        elements.push(element);
111                        break;
112                    }
113                    YieldResult::MaybeNext(element) => {
114                        elements.push(element);
115                    }
116                }
117            } else {
118                scanner.jump_to(cursor);
119                return Err(ParseError::UnexpectedToken);
120            }
121        }
122
123        Ok(SeparatedList {
124            data: elements,
125            separator: PhantomData,
126        })
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use crate::bytes::primitives::number::Number;
133    use crate::bytes::token::Token;
134    use crate::errors::ParseResult;
135    use crate::recognizer::recognize;
136    use crate::scanner::Scanner;
137    use crate::separated_list::SeparatedList;
138    use crate::visitor::Visitor;
139
140    struct SeparatorComma;
141
142    impl<'a> Visitor<'a, u8> for SeparatorComma {
143        fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
144            recognize(Token::Comma, scanner)?;
145            Ok(SeparatorComma)
146        }
147    }
148
149    /// Tests parsing a list of `Number`s separated by commas.
150    ///
151    /// Input: `b"12,4,78,22"`
152    /// Output: `vec![Number(12), Number(4), Number(78), Number(22)]`
153    /// Final position: 10
154    #[test]
155    fn test_parse_number_list() {
156        let data = b"12,4,78,22";
157        let mut scanner = Scanner::new(data);
158        let result = scanner
159            .visit::<SeparatedList<u8, Number<usize>, SeparatorComma>>()
160            .expect("failed to parse");
161        assert_eq!(
162            result.data,
163            vec![Number(12), Number(4), Number(78), Number(22)]
164        );
165        assert_eq!(scanner.current_position(), 10);
166
167        let data = b"";
168        let mut scanner = Scanner::new(data);
169        let result = scanner
170            .visit::<SeparatedList<u8, Number<usize>, SeparatorComma>>()
171            .expect("failed to parse");
172        assert_eq!(result.data, vec![]);
173    }
174}