peeking_iter/
parser.rs

1//! Parsing-specific iterator, with full peeking support.
2
3use crate::peeking::{Peeking, PeekingIter};
4
5/// An iterator implementing [`Peeking`], but designed specifically for parsing
6/// string input.
7///
8/// **NOTE:** By convention, line numbers start at `1`, while column numbers
9/// start at `0`.
10pub struct Parser<I>
11where
12    I: Iterator,
13{
14    peeking: PeekingIter<I>,
15    line: u16,
16    col: u16,
17}
18
19impl<I: Iterator<Item = char> + Clone> Peeking for Parser<I> {
20    fn peek(&mut self) -> Option<Self::Item> {
21        self.peeking.peek()
22    }
23
24    fn rewind_peeking(&mut self) {
25        self.peeking.rewind_peeking();
26    }
27
28    fn advance_to_peeked(&mut self) {
29        self.peeking.advance_to_peeked();
30    }
31}
32
33// TODO?: Implement whitespace-skipping
34impl<I: Iterator<Item = char> + Clone> Parser<I> {
35    /// Wraps the given iterator.
36    pub fn new(iter: I) -> Self {
37        Self {
38            peeking: PeekingIter::new(iter),
39            line: 1,
40            col: 0,
41        }
42    }
43
44    /// Returns the next item in the inner iterator.
45    ///
46    /// Resets the peeking iterator.
47    ///
48    /// ```rust
49    /// # use peeking_iter::peeking::Peeking;
50    /// # use peeking_iter::parser::Parser;
51    /// let mut parser = Parser::new("abcd".chars());
52    ///
53    /// assert_eq!(parser.peek(), Some('a'));
54    /// assert_eq!(parser.next(), Some('a'));
55    /// assert_eq!(parser.peek(), Some('b'));
56    /// assert_eq!(parser.next(), Some('b'));
57    /// ```
58    pub fn next(&mut self) -> Option<char> {
59        let next = self.peeking.next();
60
61        // NOTE: This assumes that all characters (except newline)
62        // advance the col by 1.
63        match next {
64            None => (),
65            Some('\n') => {
66                self.line += 1;
67                self.col = 0;
68            }
69            _ => {
70                self.col += 1;
71            }
72        }
73
74        next
75    }
76
77    /// Consumes `self` and returns the inner iterator.
78    pub fn into_inner(self) -> I {
79        PeekingIter::into_inner(self.peeking)
80    }
81
82    /// Returns the line number.
83    ///
84    /// ```rust
85    /// # use peeking_iter::parser::Parser;
86    /// let mut it = Parser::new("ab\nc".chars());
87    ///
88    /// it.next();
89    /// it.next();
90    /// it.next();
91    ///
92    /// assert_eq!(it.line(), 2);
93    /// ```
94    pub fn line(&self) -> u16 {
95        self.line
96    }
97
98    /// Returns the column number.
99    ///
100    /// **NOTE:** Every _character_ is considered to have the column size of 1.
101    pub fn col(&self) -> u16 {
102        self.col
103    }
104}
105
106impl<I: Iterator<Item = char> + Clone> Iterator for Parser<I> {
107    type Item = char;
108
109    fn next(&mut self) -> Option<char> {
110        Parser::next(self)
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use crate::parser::Parser;
117    use crate::peeking::Peeking;
118
119    fn next_while() {
120        let mut it = Parser::new("ABc".chars());
121
122        assert_eq!(
123            it.next_while(|c| c.is_uppercase()),
124            "AB".chars().collect::<Vec<_>>()
125        );
126        assert_eq!(it.peek(), Some('c'));
127        assert_eq!(it.next(), Some('c'));
128    }
129}