aoc_2018_state_machine 0.1.1

registers & opcodes for advent of code 2018 state machine
Documentation
use self::OpCode::*;
#[cfg(test)]
mod tests;
pub type Args = (u32, u32, u32);

pub trait Register: std::ops::IndexMut<u32, Output = u32> + Sized {
    fn exec_copy(&self, op: OpCode, (a, b, c): Args) -> Self
    where
        Self: Clone,
    {
        let mut copy = self.clone();
        copy[c] = copy.exec_binop(op, a, b);
        copy
    }
    fn exec(&mut self, op: OpCode, (a, b, c): Args) {
        self[c] = self.exec_binop(op, a, b)
    }

    fn exec_binop(&self, op: OpCode, a: u32, b: u32) -> u32 {
        let reg = |i| self[i];
        match op {
            OpCode::AddI => reg(a) + b,
            OpCode::AddR => reg(a) + reg(b),

            OpCode::MulI => reg(a) * b,
            OpCode::MulR => reg(a) * reg(b),

            OpCode::BAnI => reg(a) & b,
            OpCode::BAnR => reg(a) & reg(b),

            OpCode::BOrI => reg(a) | b,
            OpCode::BOrR => reg(a) | reg(b),

            OpCode::SetI => a,
            OpCode::SetR => reg(a),

            OpCode::GtIR => {
                if a > reg(b) {
                    1
                } else {
                    0
                }
            }
            OpCode::GtRI => {
                if reg(a) > b {
                    1
                } else {
                    0
                }
            }
            OpCode::GtRR => {
                if reg(a) > reg(b) {
                    1
                } else {
                    0
                }
            }

            OpCode::EqIR => {
                if a == reg(b) {
                    1
                } else {
                    0
                }
            }
            OpCode::EqRI => {
                if reg(a) == b {
                    1
                } else {
                    0
                }
            }
            OpCode::EqRR => {
                if reg(a) == reg(b) {
                    1
                } else {
                    0
                }
            }
        }
    }
}

impl OpCode {
    pub const OPCODES: [OpCode; 16] = [
        AddI, AddR, //
        MulI, MulR, //
        BAnI, BAnR, //
        BOrI, BOrR, //
        SetI, SetR, //
        GtIR, GtRI, GtRR, //
        EqIR, EqRI, EqRR, //
    ];

    pub fn iter() -> impl Iterator<Item = OpCode> {
        Self::OPCODES.iter().cloned()
    }
}

#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
pub enum OpCode {
    /// addr (add register) stores into register C the result of adding register A and register B.
    AddR,
    /// addi (add immediate) stores into register C the result of adding register A and value B.
    AddI,
    /// mulr (multiply register) stores into register C the result of multiplying register A and register B.
    MulR,
    /// muli (multiply immediate) stores into register C the result of multiplying register A and value B.
    MulI,
    /// banr (bitwise AND reigster) stores into register C the result of the bitwise AND register A and register B.
    BAnR,
    /// bani (bitwise AND immediate) stores into register C the result of the bitwise AND of register A and value B.
    BAnI,
    /// borr (bitwise OR register) stores into register C the result of the bitwise OR of register A and register B.
    BOrR,
    /// bori (bitwise OR immediate) stores into register C the result of the bitwise OR of register A and value B.
    BOrI,
    /// setr (set register) copies the contents of register A into register C. (Input B is ignored.)
    SetR,
    /// seti (set immediate) stores value A into register C. (Input B is ignored.)
    SetI,
    ///gtir (greater-than immediate/register) sets register C to 1 if value A is greater than register B. Otherwise, register C is set to 0.
    GtIR,
    ///gtri (greater-than register/immediate) sets register C to 1 if register A is greater than value B. Otherwise, register C is set to 0.
    GtRI,
    ///gtrr (greater-than register/register) sets register C to 1 if register A is greater than register B. Otherwise, register C is set to 0.
    GtRR,
    ///eqir (equal immediate/register) sets register C to 1 if value A is equal to register B. Otherwise, register C is set to 0
    EqIR,
    ///eqri (equal register/immediate) sets register C to 1 if register A is equal to value B. Otherwise, register C is set to 0.
    EqRI,
    ///eqrr (equal register/register) sets register C to 1 if register A is equal to register B. Otherwise, register C is set to 0.
    EqRR,
}

impl OpCode {
    pub fn from_name(s: &str) -> Option<Self> {
        Some(match s {
            "addi" => AddI,
            "addr" => AddR,

            "muli" => MulI,
            "mulr" => MulR,

            "bani" => BAnI,
            "banr" => BAnR,

            "bori" => BOrI,
            "borr" => BOrR,

            "seti" => SetI,
            "setr" => SetR,

            "gtir" => GtIR,
            "gtri" => GtRI,
            "gtrr" => GtRR,

            "eqir" => EqIR,
            "eqri" => EqRI,
            "eqrr" => EqRR,
            _ => return None,
        })
    }
}

impl Into<&'static str> for OpCode {
    fn into(self) -> &'static str {
        match self {
            AddI => "addi",
            AddR => "addr",

            MulI => "muli",
            MulR => "mulr",

            BAnI => "bani",
            BAnR => "banr",

            BOrI => "bori",
            BOrR => "borr",

            SetI => "seti",
            SetR => "setr",

            GtIR => "gtir",
            GtRI => "gtri",
            GtRR => "gtrr",

            EqIR => "eqir",
            EqRI => "eqri",
            EqRR => "eqrr",
        }
    }
}