A simple register VM written in Rust I'm teaching myself Rust, and to do this I've written a toy register based virtual machine. I hope the code is easy to follow - I just want to know if there are any mistakes I am making with the language philosophy or if there are syntax tricks I could be using. For example, the program counter pc and the register fields reg_field are mutable. I feel like this is the right thing to do in this case as it better reflects processor architecture. But  of course, I might be wrong...

const NUMBER_OF_REGISTERS: usize = 3;

enum Instruction {
    Halt,
    Load { reg: usize, value: u16 },
    Swap { reg1: usize, reg2: usize, reg3: usize },
    Add { reg1: usize, reg2: usize, reg3: usize },
    Branch { offset: usize }
}

fn main() {
    let encoded_instructions = &amp;[0x1110, 0x2100, 0x3010, 0x0];

    cpu(encoded_instructions);
}

fn cpu(encoded_instructions: &amp;[u16]) {
    let mut pc = 0;
    let mut reg_field = [0; NUMBER_OF_REGISTERS];

    loop {
        let encoded_instruction = fetch(pc, encoded_instructions);
        let decoded_instruction = decode(encoded_instruction);

        match decoded_instruction {
            Some(Instruction::Load { reg, value })
                =&gt; load(reg, value, &amp;mut reg_field, &amp;mut pc),
            Some(Instruction::Swap { reg1, reg2, reg3 })
                =&gt; swap(reg1, reg2, reg3, &amp;mut reg_field, &amp;mut pc),
            Some(Instruction::Add { reg1, reg2, reg3 })
                =&gt; add(reg1, reg2, reg3, &amp;mut reg_field, &amp;mut pc),
            Some(Instruction::Branch { offset })
                =&gt; branch(offset, &amp;mut pc),
            Some(Instruction::Halt)
                =&gt; { halt(&amp;reg_field); break }
            None =&gt; break,
        }
    }
}

fn fetch(pc: usize, instructions: &amp;[u16]) -&gt; u16 {
    instructions[pc]
}

fn halt(register_field: &amp;[u16]) {
    println!("{:?}", register_field[0]);
}

fn load(register: usize, value: u16, register_field: &amp;mut [u16], pc: &amp;mut usize) {
    register_field[register] = value;
    *pc += 1;
}

fn swap(reg1: usize, reg2: usize, reg3: usize, register_field: &amp;mut [u16], pc: &amp;mut usize) {
    register_field[reg3] = register_field[reg1];
    register_field[reg1] = register_field[reg2];
    register_field[reg2] = register_field[reg3];
    *pc += 1;
}

fn add(reg1: usize, reg2: usize, reg3: usize, register_field: &amp;mut [u16], pc: &amp;mut usize) {
    register_field[reg3] = register_field[reg1] + register_field[reg2];
    *pc += 1;
}

fn branch(offset: usize, pc: &amp;mut usize) {
    *pc -= offset;
}

fn decode(encoded_instruction: u16) -&gt; Option&lt;Instruction&gt; {
    let operator = encoded_instruction &gt;&gt; 12;
    let reg1 = ((encoded_instruction &gt;&gt; 8) &amp; 0xF) as usize;
    let reg2 = ((encoded_instruction &gt;&gt; 4) &amp; 0xF) as usize;
    let reg3 = (encoded_instruction &amp; 0xF) as usize;
    let offset = (encoded_instruction &amp; 0xFFF) as usize;
    let value = encoded_instruction &amp; 0xFF;

    match operator {
        0 =&gt; Some(Instruction::Halt),
        1 =&gt; Some(Instruction::Load { reg: reg1, value: value }),
        2 =&gt; Some(Instruction::Swap { reg1: reg1, reg2: reg2, reg3: reg3 }),
        3 =&gt; Some(Instruction::Add { reg1: reg1, reg2: reg2, reg3: reg3 }),
        4 =&gt; Some(Instruction::Branch { offset: offset }),
        _ =&gt; None,
    }
}
Your code was very readable and easy to follow. Most of my suggestions center around trying to showcase some more Rust idioms and features. 


A collection of registers in normally called a register file.
Since the constant for the number of registers is only used to declare the register file, create a type alias and use that. This sets you up nicely to make it a standalone type in the future.
I'm glad to see names for registers in Instruction, but maybe give them more meaningful names? Add is a great example - which registers are the inputs and which is the output?
You almost always want to derive Debug for a type. Copy and Clone are also very common. Implementing PartialEq will allow easier test writing.
There's a distinct lack of types and methods, overall the code feels pretty C-like. I'd associate functions with types, making them methods. For example, decode is the most obvious change to me.
Returning an Option from decode is iffy. Failing to decode an instruction doesn't seem like the absence of a value, it feels like a failure, which is normally reserved for Result.
When splitting match arms onto a different line from the pattern, use braces.
Consider inlining some of the instruction implementations into execute as many are only one line long anyway.
In a processor, it's very typical to automatically increment the program counter every instruction. Branch offsets take that automatic increment into account. This is nice here because it removes pc from all the non-branching methods. I just subtracted 1 when applying the jump, but it's probably better to fixup the offsets.
Create a type for sequences of instructions, I used Program. This will give you somewhere to hang fetch.




type RegisterFile = [u16; 3];

#[derive(Debug, Copy, Clone)]
enum Instruction {
    Halt,
    Load { reg: usize, value: u16 },
    Swap { reg1: usize, reg2: usize, reg3: usize },
    Add { reg1: usize, reg2: usize, reg3: usize },
    Branch { offset: usize }
}

impl Instruction {
    fn decode(encoded_instruction: u16) -&gt; Option&lt;Self&gt; {
        let operator = encoded_instruction &gt;&gt; 12;
        let reg1 = ((encoded_instruction &gt;&gt; 8) &amp; 0xF) as usize;
        let reg2 = ((encoded_instruction &gt;&gt; 4) &amp; 0xF) as usize;
        let reg3 = (encoded_instruction &amp; 0xF) as usize;
        let offset = (encoded_instruction &amp; 0xFFF) as usize;
        let value = encoded_instruction &amp; 0xFF;

        match operator {
            0 =&gt; Some(Instruction::Halt),
            1 =&gt; Some(Instruction::Load { reg: reg1, value: value }),
            2 =&gt; Some(Instruction::Swap { reg1: reg1, reg2: reg2, reg3: reg3 }),
            3 =&gt; Some(Instruction::Add { reg1: reg1, reg2: reg2, reg3: reg3 }),
            4 =&gt; Some(Instruction::Branch { offset: offset }),
            _ =&gt; None,
        }
    }

    fn execute(&amp;self, registers: &amp;mut [u16], pc: &amp;mut usize) -&gt; bool {
        match *self {
            Instruction::Load { reg, value } =&gt; {
                load(reg, value, registers);
            },
            Instruction::Swap { reg1, reg2, reg3 } =&gt; {
                swap(reg1, reg2, reg3, registers);
            },
            Instruction::Add { reg1, reg2, reg3 } =&gt; {
                add(reg1, reg2, reg3, registers);
            },
            Instruction::Branch { offset } =&gt; {
                branch(offset, pc);
            },
            Instruction::Halt =&gt; {
                halt(registers);
                return false;
            },
        }

        true
    }
}

fn halt(register_file: &amp;[u16]) {
    println!("{:?}", register_file[0]);
}

fn load(register: usize, value: u16, register_file: &amp;mut [u16]) {
    register_file[register] = value;
}

fn swap(reg1: usize, reg2: usize, reg3: usize, register_file: &amp;mut [u16]) {
    register_file[reg3] = register_file[reg1];
    register_file[reg1] = register_file[reg2];
    register_file[reg2] = register_file[reg3];
}

fn add(reg1: usize, reg2: usize, reg3: usize, register_file: &amp;mut [u16]) {
    register_file[reg3] = register_file[reg1] + register_file[reg2];
}

fn branch(offset: usize, pc: &amp;mut usize) {
    *pc -= offset - 1;
}

struct Program&lt;'a&gt; {
    instructions: &amp;'a [u16],
}

impl&lt;'a&gt; Program&lt;'a&gt; {
    fn fetch(&amp;self, pc: usize) -&gt; u16 {
        self.instructions[pc]
    }
}

fn cpu(program: Program) {
    let mut pc = 0;
    let mut registers = RegisterFile::default();

    loop {
        let encoded_instruction = program.fetch(pc);
        let decoded_instruction = Instruction::decode(encoded_instruction);

        match decoded_instruction {
            Some(instr) =&gt; {
                if !instr.execute(&amp;mut registers, &amp;mut pc) { break }
            }
            None =&gt; break,
        }

        pc += 1;
    }
}

fn main() {
    let encoded_instructions = Program { instructions: &amp;[0x1110, 0x2100, 0x3010, 0x0] };

    cpu(encoded_instructions);
}