parseme/
source.rs

1extern crate alloc;
2
3use alloc::collections::VecDeque;
4use core::str::Chars;
5
6use crate::iter::Peek;
7
8/// An iterator through the characters in a string.
9pub struct Source<'a> {
10    iter: Chars<'a>,
11    src: &'a str,
12    pos: usize,
13    peeked: VecDeque<char>,
14}
15
16impl<'a> Source<'a> {
17    /// Creates a new [Source] from the provided string.
18    pub fn new(src: &'a str) -> Self {
19        Self {
20            iter: src.chars(),
21            src,
22            pos: 0,
23            peeked: VecDeque::new(),
24        }
25    }
26
27    /// Returns the current position offset (in bytes) from the start of the source string.
28    #[inline]
29    pub fn pos(&self) -> usize {
30        self.pos
31    }
32
33    /// Returns the source string which is being iterated through.
34    #[inline]
35    pub fn src(&self) -> &'a str {
36        self.src
37    }
38
39    /// Returns the next character in the iterator without advancing it.
40    #[inline]
41    pub fn peek(&mut self) -> Option<char> {
42        self.peek_nth(0)
43    }
44
45    /// Returns the *nth* future character in the iterator.
46    ///
47    /// Uses zero-based indexing (i.e. `0` returns the next character, `1` the character after
48    /// that, and so on).
49    pub fn peek_nth(&mut self, nth: usize) -> Option<char> {
50        self.peeked.extend(
51            self.iter
52                .by_ref()
53                .take((nth + 1).saturating_sub(self.peeked.len())),
54        );
55        self.peeked.get(nth).copied()
56    }
57}
58
59impl<'a> Iterator for Source<'a> {
60    type Item = char;
61
62    fn next(&mut self) -> Option<Self::Item> {
63        self.peeked
64            .pop_front()
65            .or_else(|| self.iter.next())
66            .map(|c| {
67                self.pos += c.len_utf8();
68                c
69            })
70    }
71}
72
73impl<'a> Peek for Source<'a> {
74    type Item = char;
75
76    #[inline]
77    fn peek(&mut self) -> Option<Self::Item> {
78        self.peek()
79    }
80}