I am just beginning to learn Rust and I’m struggling to handle the lifetimes.
I’d like to have a struct with a String
in it which will be used to buffer lines from stdin. Then I’d like to have a method on the struct which returns the next character from the buffer, or if all of the characters from the line have been consumed it will read the next line from stdin.
The documentation says that Rust strings aren’t indexable by character because that is inefficient with UTF-8. As I’m accessing the characters sequentially it should be fine to use an iterator. However, as far as I understand, iterators in Rust are tied to the lifetime of the thing they’re iterating and I can’t work out how I could store this iterator in the struct alongside the String
.
Here is the pseudo-Rust that I’d like to achieve. Obviously it doesn’t compile.
struct CharGetter {
/* Buffer containing one line of input at a time */
input_buf: String,
/* The position within input_buf of the next character to
* return. This needs a lifetime parameter. */
input_pos: std::str::Chars
}
impl CharGetter {
fn next(&mut self) -> Result<char, io::Error> {
loop {
match self.input_pos.next() {
/* If there is still a character left in the input
* buffer then we can just return it immediately. */
Some(n) => return Ok(n),
/* Otherwise get the next line */
None => {
io::stdin().read_line(&mut self.input_buf)?;
/* Reset the iterator to the beginning of the
* line. Obviously this doesn’t work because it’s
* not obeying the lifetime of input_buf */
self.input_pos = self.input_buf.chars();
}
}
}
}
}
I am trying to do the Synacor challenge. This involves implementing a virtual machine where one of the opcodes reads a character from stdin and stores it in a register. I have this part working fine. The documentation states that whenever the program inside the VM reads a character it will keep reading until it reads a whole line. I wanted to take advantage of this to add a “save” command to my implementation. That means that whenever the program asks for a character, I will read a line from the input. If the line is “save”, I will save the state of the VM and then continue to get another line to feed to the VM. Each time the VM executes the input opcode, I need to be able to give it one character at a time from the buffered line until the buffer is depleted.
My current implementation is here. My plan was to add input_buf
and input_pos
to the Machine
struct which represents the state of the VM.