Given is a struct which holds a struct with some byte code and an instruction pointer. It implements the pattern of fetch, decode, and execute:
use std::convert::TryFrom;
/// Trait for a virtual machine.
pub struct VirtualMachine {
code: CodeMemory,
instruction_pointer: usize,
}
impl VirtualMachine {
pub fn new(byte_code: Vec<u8>) -> VirtualMachine {
VirtualMachine {
code: CodeMemory::new(byte_code),
instruction_pointer: 0,
}
}
/// Run a given program.
pub fn run(&mut self) -> Result<(), &str> {
loop {
let opcode = self.fetch();
if opcode.is_err() {
return Err(opcode.unwrap_err());
}
let instruction = self.decode(opcode.unwrap());
if instruction.is_err() {
return Err("Bad opcode!");
}
let instruction = instruction.unwrap();
if instruction == Instruction::Halt {
return Ok(());
}
self.execute(instruction);
}
}
fn fetch(&mut self) -> Result<u8, &str> {
self.code.fetch(self.instruction_pointer)
}
fn decode(&mut self, opcode: u8) -> Result<Instruction, Error> {
Instruction::try_from(opcode)
}
fn execute(&mut self, instruction: Instruction) {
self.inc_instruction_pointer();
match instruction {
Instruction::Nop => (),
Instruction::Halt => panic!("The opcode 'halt' should exit the loop before execute!"),
}
}
fn inc_instruction_pointer(&mut self) {
self.instruction_pointer += 1;
}
}
struct CodeMemory {
byte_code: Vec<u8>,
}
impl CodeMemory {
fn new(byte_code: Vec<u8>) -> CodeMemory {
CodeMemory { byte_code }
}
fn fetch(&self, index: usize) -> Result<u8, &str> {
if index < self.byte_code.len() {
Ok(self.byte_code[index])
} else {
Err("Index out of bounds!")
}
}
}
#[derive(Debug, PartialEq)]
pub enum Error {
UnknownInstruction(u8),
UnknownMnemonic(String),
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Instruction {
Nop,
// ...
Halt,
}
impl TryFrom<u8> for Instruction {
type Error = Error;
fn try_from(original: u8) -> Result<Self, Self::Error> {
match original {
0x01 => Ok(Instruction::Nop),
0x0c => Ok(Instruction::Halt),
n => Err(Error::UnknownInstruction(n)),
}
}
}
The compiler complains that:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:20:26
|
18 | pub fn run(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
19 | loop {
20 | let opcode = self.fetch();
| ^^^^ mutable borrow starts here in previous iteration of loop
...
23 | return Err(opcode.unwrap_err());
| ------------------------ returning this value requires that `*self` is borrowed for `'1`
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:26:31
|
18 | pub fn run(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
19 | loop {
20 | let opcode = self.fetch();
| ---- first mutable borrow occurs here
...
23 | return Err(opcode.unwrap_err());
| ------------------------ returning this value requires that `*self` is borrowed for `'1`
...
26 | let instruction = self.decode(opcode.unwrap());
| ^^^^ second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:38:13
|
18 | pub fn run(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
19 | loop {
20 | let opcode = self.fetch();
| ---- first mutable borrow occurs here
...
23 | return Err(opcode.unwrap_err());
| ------------------------ returning this value requires that `*self` is borrowed for `'1`
...
38 | self.execute(instruction);
| ^^^^ second mutable borrow occurs here
I think I understand the problem described by the compiler, but I can't find a solution or pattern how to implement this in Rust in a safe way. Is it possible to mutate a struct field inside a loop?
I'm using Rust 1.34 to use the TryFrom
trait.