]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_lexer/src/cursor.rs
Auto merge of #102935 - ajtribick:display-float-0.5-fixed-0, r=scottmcm
[rust.git] / compiler / rustc_lexer / src / cursor.rs
1 use std::str::Chars;
2
3 /// Peekable iterator over a char sequence.
4 ///
5 /// Next characters can be peeked via `first` method,
6 /// and position can be shifted forward via `bump` method.
7 pub struct Cursor<'a> {
8     len_remaining: usize,
9     /// Iterator over chars. Slightly faster than a &str.
10     chars: Chars<'a>,
11     #[cfg(debug_assertions)]
12     prev: char,
13 }
14
15 pub(crate) const EOF_CHAR: char = '\0';
16
17 impl<'a> Cursor<'a> {
18     pub fn new(input: &'a str) -> Cursor<'a> {
19         Cursor {
20             len_remaining: input.len(),
21             chars: input.chars(),
22             #[cfg(debug_assertions)]
23             prev: EOF_CHAR,
24         }
25     }
26
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)]
31         {
32             self.prev
33         }
34
35         #[cfg(not(debug_assertions))]
36         {
37             EOF_CHAR
38         }
39     }
40
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)
48     }
49
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();
54         iter.next();
55         iter.next().unwrap_or(EOF_CHAR)
56     }
57
58     /// Checks if there is nothing more to consume.
59     pub(crate) fn is_eof(&self) -> bool {
60         self.chars.as_str().is_empty()
61     }
62
63     /// Returns amount of already consumed symbols.
64     pub(crate) fn pos_within_token(&self) -> u32 {
65         (self.len_remaining - self.chars.as_str().len()) as u32
66     }
67
68     /// Resets the number of bytes consumed to 0.
69     pub(crate) fn reset_pos_within_token(&mut self) {
70         self.len_remaining = self.chars.as_str().len();
71     }
72
73     /// Moves to the next character.
74     pub(crate) fn bump(&mut self) -> Option<char> {
75         let c = self.chars.next()?;
76
77         #[cfg(debug_assertions)]
78         {
79             self.prev = c;
80         }
81
82         Some(c)
83     }
84
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() {
90             self.bump();
91         }
92     }
93 }