I am trying to make a simple lexer that works on Peekable
iterators. When there are no more characters left to iterate I return EOF instead using unwrap_or()
.
Instead of constantly typing out iter.peek().unwrap_or(&EOF)
, I have a function peek_or_eof
. I try and use the function like this:
use std::iter::Peekable;
const EOF: char = '\0';
enum Token {
Identifier(String),
}
pub struct Lexer<I>
where
I: Iterator<Item = char>,
{
stream: Peekable<I>,
}
impl<I> Lexer<I>
where
I: Iterator<Item = char>,
{
fn peek_or_eof(stream: &mut Peekable<I>) -> &char {
stream.peek().unwrap_or(&EOF)
}
fn read_identifier(stream: &mut Peekable<I>) -> Option<Token> {
// ...
let mut identifier = String::new();
let mut next = Lexer::peek_or_eof(stream);
while next.is_alphanumeric() || next == &'_' {
identifier.push(stream.next().unwrap());
next = Lexer::peek_or_eof(stream);
}
// ...
None
}
}
fn main() {
println!("Hello, world!");
}
The above code results in the error:
error[E0499]: cannot borrow `*stream` as mutable more than once at a time
--> src/main.rs:31:29
|
29 | let mut next = Lexer::peek_or_eof(stream);
| ------ first mutable borrow occurs here
30 | while next.is_alphanumeric() || next == &'_' {
31 | identifier.push(stream.next().unwrap());
| ^^^^^^ second mutable borrow occurs here
...
37 | }
| - first borrow ends here
If I understand correctly, the borrow lifetime is the same as the returned character reference, which in this case is next
. However, I don't actually use next after checking the condition in the while loop and next
will be overwritten with a new value before the next iteration of the loop.
Am I making a larger mistake? How do I let the compiler know that the mutable borrow on stream is done and that it is safe to allow another mutable borrow?