3 /// Peekable iterator over a char sequence.
5 /// Next characters can be peeked via `first` method,
6 /// and position can be shifted forward via `bump` method.
7 pub(crate) struct Cursor<'a> {
9 /// Iterator over chars. Slightly faster than a &str.
11 #[cfg(debug_assertions)]
15 pub(crate) const EOF_CHAR: char = '\0';
18 pub(crate) fn new(input: &'a str) -> Cursor<'a> {
20 initial_len: input.len(),
22 #[cfg(debug_assertions)]
27 /// Returns the last eaten symbol (or `'\0'` in release builds).
28 /// (For debug assertions only.)
29 pub(crate) fn prev(&self) -> char {
30 #[cfg(debug_assertions)]
35 #[cfg(not(debug_assertions))]
41 /// Peeks the next symbol from the input stream without consuming it.
42 /// If requested position doesn't exist, `EOF_CHAR` is returned.
43 /// However, getting `EOF_CHAR` doesn't always mean actual end of file,
44 /// it should be checked with `is_eof` method.
45 pub(crate) fn first(&self) -> char {
46 // `.next()` optimizes better than `.nth(0)`
47 self.chars.clone().next().unwrap_or(EOF_CHAR)
50 /// Peeks the second symbol from the input stream without consuming it.
51 pub(crate) fn second(&self) -> char {
52 // `.next()` optimizes better than `.nth(1)`
53 let mut iter = self.chars.clone();
55 iter.next().unwrap_or(EOF_CHAR)
58 /// Checks if there is nothing more to consume.
59 pub(crate) fn is_eof(&self) -> bool {
60 self.chars.as_str().is_empty()
63 /// Returns amount of already consumed symbols.
64 pub(crate) fn len_consumed(&self) -> usize {
65 self.initial_len - self.chars.as_str().len()
68 /// Resets the number of bytes consumed to 0.
69 pub(crate) fn reset_len_consumed(&mut self) {
70 self.initial_len = self.chars.as_str().len();
73 /// Moves to the next character.
74 pub(crate) fn bump(&mut self) -> Option<char> {
75 let c = self.chars.next()?;
77 #[cfg(debug_assertions)]
85 /// Eats symbols while predicate returns true or until the end of file is reached.
86 pub(crate) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
87 // It was tried making optimized version of this for eg. line comments, but
88 // LLVM can inline all of this and compile it down to fast iteration over bytes.
89 while predicate(self.first()) && !self.is_eof() {