]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_lexer/src/cursor.rs
New upstream version 1.59.0+dfsg1
[rustc.git] / compiler / rustc_lexer / src / cursor.rs
CommitLineData
416331ca
XL
1use std::str::Chars;
2
e74abb32
XL
3/// Peekable iterator over a char sequence.
4///
a2a8927a 5/// Next characters can be peeked via `first` method,
e74abb32 6/// and position can be shifted forward via `bump` method.
416331ca
XL
7pub(crate) struct Cursor<'a> {
8 initial_len: usize,
a2a8927a 9 /// Iterator over chars. Slightly faster than a &str.
416331ca
XL
10 chars: Chars<'a>,
11 #[cfg(debug_assertions)]
12 prev: char,
13}
14
15pub(crate) const EOF_CHAR: char = '\0';
16
17impl<'a> Cursor<'a> {
18 pub(crate) fn new(input: &'a str) -> Cursor<'a> {
19 Cursor {
20 initial_len: input.len(),
21 chars: input.chars(),
22 #[cfg(debug_assertions)]
23 prev: EOF_CHAR,
24 }
25 }
e74abb32 26
f035d41b
XL
27 /// Returns the last eaten symbol (or `'\0'` in release builds).
28 /// (For debug assertions only.)
416331ca
XL
29 pub(crate) fn prev(&self) -> char {
30 #[cfg(debug_assertions)]
31 {
32 self.prev
33 }
34
35 #[cfg(not(debug_assertions))]
36 {
5869c6ff 37 EOF_CHAR
416331ca
XL
38 }
39 }
e74abb32 40
a2a8927a 41 /// Peeks the next symbol from the input stream without consuming it.
e74abb32
XL
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.
60c5eb7d 45 pub(crate) fn first(&self) -> char {
a2a8927a
XL
46 // `.next()` optimizes better than `.nth(0)`
47 self.chars.clone().next().unwrap_or(EOF_CHAR)
60c5eb7d
XL
48 }
49
50 /// Peeks the second symbol from the input stream without consuming it.
51 pub(crate) fn second(&self) -> char {
a2a8927a
XL
52 // `.next()` optimizes better than `.nth(1)`
53 let mut iter = self.chars.clone();
54 iter.next();
55 iter.next().unwrap_or(EOF_CHAR)
60c5eb7d
XL
56 }
57
e74abb32 58 /// Checks if there is nothing more to consume.
416331ca
XL
59 pub(crate) fn is_eof(&self) -> bool {
60 self.chars.as_str().is_empty()
61 }
e74abb32
XL
62
63 /// Returns amount of already consumed symbols.
416331ca
XL
64 pub(crate) fn len_consumed(&self) -> usize {
65 self.initial_len - self.chars.as_str().len()
66 }
e74abb32 67
a2a8927a
XL
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();
416331ca 71 }
e74abb32 72
416331ca
XL
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 }
a2a8927a
XL
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 }
416331ca 93}