[2016][rust][12.1] Break out Assembunny into a module
change qtzzzwymyrporrusyvqwszpqrrsysopw
commit fa74bd9db9a42099f83e8a17c396adfe7b10b1d3
author Alpha Chen <alpha.chen@gmail.com>
date
parent pqmptwmq
diff --git a/2016/rust/src/assembunny.rs b/2016/rust/src/assembunny.rs
new file mode 100644
index 0000000..0013bb3
--- /dev/null
+++ b/2016/rust/src/assembunny.rs
@@ -0,0 +1,243 @@
+use std::collections::HashMap;
+use std::str;
+
+use errors::*;
+
+pub struct Assembunny {
+    pub registers: HashMap<Register, isize>,
+    pub instructions: Instructions,
+}
+
+impl Assembunny {
+    fn value<V: Into<Variable>>(&self, v: V) -> isize {
+        let v: Variable = v.into();
+        match v {
+            Variable::Register(r) => {
+                self.registers.get(&r).cloned().unwrap_or(0)
+            }
+            Variable::Value(i) => i,
+        }
+    }
+}
+
+impl Iterator for Assembunny {
+    type Item = HashMap<Register, isize>;
+    fn next(&mut self) -> Option<HashMap<Register, isize>> {
+        let pc = self.value(Register::PC) as usize;
+        let instruction = match self.instructions.0.get(pc) {
+            Some(i) => i,
+            None => {
+                return None;
+            }
+        };
+
+        match *instruction {
+            Instruction::Cpy(v, r) => {
+                let value = self.value(v);
+                self.registers.insert(r, value);
+                *self.registers.entry(Register::PC).or_insert(0) += 1;
+            }
+            Instruction::Inc(r) => {
+                *self.registers.entry(r).or_insert(0) += 1;
+                *self.registers.entry(Register::PC).or_insert(0) += 1;
+            }
+            Instruction::Dec(r) => {
+                *self.registers.entry(r).or_insert(0) -= 1;
+                *self.registers.entry(Register::PC).or_insert(0) += 1;
+            }
+            Instruction::Jnz(v, i) => {
+                let delta = if self.value(v) == 0 { 1 } else { i };
+                let pc = self.value(Register::PC) + delta;
+                self.registers.insert(Register::PC, pc);
+            }
+        }
+
+        Some(self.registers.clone())
+    }
+}
+
+pub struct Instructions(Vec<Instruction>);
+
+#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+pub enum Register {
+    PC,
+    A,
+    B,
+    C,
+    D,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum Instruction {
+    Cpy(Variable, Register),
+    Inc(Register),
+    Dec(Register),
+    Jnz(Variable, isize),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum Variable {
+    Register(Register),
+    Value(isize),
+}
+
+impl From<Register> for Variable {
+    fn from(r: Register) -> Self {
+        Variable::Register(r)
+    }
+}
+
+// Parsing
+
+impl str::FromStr for Instructions {
+    type Err = Error;
+    fn from_str(s: &str) -> Result<Self> {
+        s.lines()
+            .map(|line| line.parse())
+            .collect::<Result<Vec<_>>>()
+            .map(Instructions)
+    }
+}
+
+impl str::FromStr for Register {
+    type Err = Error;
+    fn from_str(s: &str) -> Result<Self> {
+        match s {
+            "a" => Ok(Register::A),
+            "b" => Ok(Register::B),
+            "c" => Ok(Register::C),
+            "d" => Ok(Register::D),
+            _ => Err(format!("invalid register '{}'", s).into()),
+        }
+    }
+}
+
+impl str::FromStr for Instruction {
+    type Err = Error;
+    fn from_str(s: &str) -> Result<Self> {
+        let mut tokens = s.split_whitespace();
+        match tokens.next() {
+            Some("cpy") => {
+                let v = tokens.read_variable()?;
+                let r = tokens.read_register()?;
+                Ok(Instruction::Cpy(v, r))
+            }
+            Some("inc") => {
+                let r = tokens.read_register()?;
+                Ok(Instruction::Inc(r))
+            }
+            Some("dec") => {
+                let r = tokens.read_register()?;
+                Ok(Instruction::Dec(r))
+            }
+            Some("jnz") => {
+                let var = tokens.read_variable()?;
+                let val = tokens.read_value()?;
+                Ok(Instruction::Jnz(var, val))
+            }
+            Some(inst) => Err(format!("invalid instruction '{}'", inst).into()),
+            None => Err("no instruction".into()),
+        }
+    }
+}
+
+impl str::FromStr for Variable {
+    type Err = Error;
+    fn from_str(s: &str) -> Result<Self> {
+        s.parse::<Register>()
+            .map(Variable::Register)
+            .or_else(|_| s.parse::<isize>().map(Variable::Value))
+            .map_err(|_| format!("invalid variable '{}'", s).into())
+    }
+}
+
+trait SplitWhitespaceExt {
+    fn read_variable(&mut self) -> Result<Variable>;
+    fn read_register(&mut self) -> Result<Register>;
+    fn read_value(&mut self) -> Result<isize>;
+}
+
+impl<'a> SplitWhitespaceExt for str::SplitWhitespace<'a> {
+    fn read_variable(&mut self) -> Result<Variable> {
+        self.next()
+            .ok_or("missing variable".into())
+            .and_then(|v| v.parse::<Variable>())
+    }
+
+    fn read_register(&mut self) -> Result<Register> {
+        self.next()
+            .ok_or("missing register".into())
+            .and_then(|v| v.parse::<Register>())
+    }
+
+    fn read_value(&mut self) -> Result<isize> {
+        self.next()
+            .ok_or("missing value".into())
+            .and_then(|v| v.parse::<isize>().chain_err(|| ""))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{Assembunny, Instructions, Instruction, Register, Variable};
+    use std::collections::HashMap;
+    use std::str::FromStr;
+
+    #[test]
+    fn test_assembunny() {
+        let instructions: Instructions = "cpy 41 a
+inc a
+inc a
+dec a
+jnz a 2
+dec a"
+            .parse()
+            .unwrap();
+        let mut assembunny = Assembunny {
+            registers: HashMap::new(),
+            instructions: instructions,
+        };
+
+        let registers = assembunny.next().unwrap();
+        assert_eq!(registers.get(&Register::A), Some(&41));
+        assert_eq!(registers.get(&Register::B), None);
+
+        let registers = assembunny.next().unwrap();
+        assert_eq!(registers.get(&Register::A), Some(&42));
+        assert_eq!(registers.get(&Register::C), None);
+
+        let registers = assembunny.last().unwrap();
+        assert_eq!(registers.get(&Register::A), Some(&42));
+        assert_eq!(registers.get(&Register::PC), Some(&6));
+    }
+
+    #[test]
+    fn test_instructions_from_str() {
+        let i: Instructions = "cpy 41 a
+inc a
+inc a
+dec a
+jnz a 2
+dec a"
+            .parse()
+            .unwrap();
+        assert_eq!(i.0.len(), 6);
+        assert_eq!(i.0[0], Instruction::from_str("cpy 41 a").unwrap());
+    }
+
+    #[test]
+    fn test_instruction_from_str() {
+        assert!(Instruction::from_str("").is_err());
+        assert!(Instruction::from_str("omg").is_err());
+        assert!(Instruction::from_str("inc 5").is_err());
+
+        assert_eq!(Instruction::from_str("cpy 41 a").unwrap(),
+                   Instruction::Cpy(Variable::Value(41), Register::A));
+        assert_eq!(Instruction::from_str("inc a").unwrap(),
+                   Instruction::Inc(Register::A));
+        assert_eq!(Instruction::from_str("dec b").unwrap(),
+                   Instruction::Dec(Register::B));
+        assert_eq!(Instruction::from_str("jnz c 2").unwrap(),
+                   Instruction::Jnz(Variable::Register(Register::C), 2));
+    }
+}
diff --git a/2016/rust/src/day_12.rs b/2016/rust/src/day_12.rs
index b14f9e0..080ab4d 100644
--- a/2016/rust/src/day_12.rs
+++ b/2016/rust/src/day_12.rs
@@ -1,6 +1,4 @@
-use std::collections::HashMap;
-use std::str;
-
+use assembunny::*;
 use errors::*;
 
 pub fn solve(input: &str) -> Result<String> {
@@ -12,243 +10,3 @@ pub fn solve(input: &str) -> Result<String> {
     let a = registers.get(&Register::A).ok_or("")?;
     Ok(a.to_string())
 }
-
-struct Assembunny {
-    registers: HashMap<Register, isize>,
-    instructions: Instructions,
-}
-
-impl Assembunny {
-    fn new(instructions: Instructions) -> Self {
-        Assembunny {
-            registers: HashMap::new(),
-            instructions: instructions,
-        }
-    }
-
-    fn value<V: Into<Variable>>(&self, v: V) -> isize {
-        let v: Variable = v.into();
-        match v {
-            Variable::Register(r) => self.registers.get(&r).cloned().unwrap_or(0),
-            Variable::Value(i) => i,
-        }
-    }
-}
-
-impl Iterator for Assembunny {
-    type Item = HashMap<Register, isize>;
-    fn next(&mut self) -> Option<HashMap<Register, isize>> {
-        let pc = self.value(Register::PC) as usize;
-        let instruction = match self.instructions.0.get(pc) {
-            Some(i) => i,
-            None => {
-                return None;
-            }
-        };
-
-        match *instruction {
-            Instruction::Cpy(v, r) => {
-                let value = self.value(v);
-                self.registers.insert(r, value);
-                *self.registers.entry(Register::PC).or_insert(0) += 1;
-            }
-            Instruction::Inc(r) => {
-                *self.registers.entry(r).or_insert(0) += 1;
-                *self.registers.entry(Register::PC).or_insert(0) += 1;
-            }
-            Instruction::Dec(r) => {
-                *self.registers.entry(r).or_insert(0) -= 1;
-                *self.registers.entry(Register::PC).or_insert(0) += 1;
-            }
-            Instruction::Jnz(v, i) => {
-                let delta = if self.value(v) == 0 { 1 } else { i };
-                let pc = self.value(Register::PC) + delta;
-                self.registers.insert(Register::PC, pc);
-            }
-        }
-
-        Some(self.registers.clone())
-    }
-}
-
-struct Instructions(Vec<Instruction>);
-
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
-enum Register {
-    PC,
-    A,
-    B,
-    C,
-    D,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum Instruction {
-    Cpy(Variable, Register),
-    Inc(Register),
-    Dec(Register),
-    Jnz(Variable, isize),
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum Variable {
-    Register(Register),
-    Value(isize),
-}
-
-impl From<Register> for Variable {
-    fn from(r: Register) -> Self {
-        Variable::Register(r)
-    }
-}
-
-// Parsing
-
-impl str::FromStr for Instructions {
-    type Err = Error;
-    fn from_str(s: &str) -> Result<Self> {
-        s.lines()
-            .map(|line| line.parse())
-            .collect::<Result<Vec<_>>>()
-            .map(Instructions)
-    }
-}
-
-impl str::FromStr for Register {
-    type Err = Error;
-    fn from_str(s: &str) -> Result<Self> {
-        match s {
-            "a" => Ok(Register::A),
-            "b" => Ok(Register::B),
-            "c" => Ok(Register::C),
-            "d" => Ok(Register::D),
-            _ => Err(format!("invalid register '{}'", s).into()),
-        }
-    }
-}
-
-impl str::FromStr for Instruction {
-    type Err = Error;
-    fn from_str(s: &str) -> Result<Self> {
-        let mut tokens = s.split_whitespace();
-        match tokens.next() {
-            Some("cpy") => {
-                let v = tokens.read_variable()?;
-                let r = tokens.read_register()?;
-                Ok(Instruction::Cpy(v, r))
-            }
-            Some("inc") => {
-                let r = tokens.read_register()?;
-                Ok(Instruction::Inc(r))
-            }
-            Some("dec") => {
-                let r = tokens.read_register()?;
-                Ok(Instruction::Dec(r))
-            }
-            Some("jnz") => {
-                let var = tokens.read_variable()?;
-                let val = tokens.read_value()?;
-                Ok(Instruction::Jnz(var, val))
-            }
-            Some(inst) => Err(format!("invalid instruction '{}'", inst).into()),
-            None => Err("no instruction".into()),
-        }
-    }
-}
-
-impl str::FromStr for Variable {
-    type Err = Error;
-    fn from_str(s: &str) -> Result<Self> {
-        s.parse::<Register>()
-            .map(Variable::Register)
-            .or_else(|_| s.parse::<isize>().map(Variable::Value))
-            .map_err(|_| format!("invalid variable '{}'", s).into())
-    }
-}
-
-trait SplitWhitespaceExt {
-    fn read_variable(&mut self) -> Result<Variable>;
-    fn read_register(&mut self) -> Result<Register>;
-    fn read_value(&mut self) -> Result<isize>;
-}
-
-impl<'a> SplitWhitespaceExt for str::SplitWhitespace<'a> {
-    fn read_variable(&mut self) -> Result<Variable> {
-        self.next()
-            .ok_or("missing variable".into())
-            .and_then(|v| v.parse::<Variable>())
-    }
-
-    fn read_register(&mut self) -> Result<Register> {
-        self.next()
-            .ok_or("missing register".into())
-            .and_then(|v| v.parse::<Register>())
-    }
-
-    fn read_value(&mut self) -> Result<isize> {
-        self.next()
-            .ok_or("missing value".into())
-            .and_then(|v| v.parse::<isize>().chain_err(|| ""))
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{Assembunny, Instructions, Instruction, Register, Variable};
-    use std::str::FromStr;
-
-    #[test]
-    fn test_assembunny() {
-        let instructions: Instructions = "cpy 41 a
-inc a
-inc a
-dec a
-jnz a 2
-dec a"
-            .parse()
-            .unwrap();
-        let mut assembunny = Assembunny::new(instructions);
-
-        let registers = assembunny.next().unwrap();
-        assert_eq!(registers.get(&Register::A), Some(&41));
-        assert_eq!(registers.get(&Register::B), None);
-
-        let registers = assembunny.next().unwrap();
-        assert_eq!(registers.get(&Register::A), Some(&42));
-        assert_eq!(registers.get(&Register::C), None);
-
-        let registers = assembunny.last().unwrap();
-        assert_eq!(registers.get(&Register::A), Some(&42));
-        assert_eq!(registers.get(&Register::PC), Some(&6));
-    }
-
-    #[test]
-    fn test_instructions_from_str() {
-        let i: Instructions = "cpy 41 a
-inc a
-inc a
-dec a
-jnz a 2
-dec a"
-            .parse()
-            .unwrap();
-        assert_eq!(i.0.len(), 6);
-        assert_eq!(i.0[0], Instruction::from_str("cpy 41 a").unwrap());
-    }
-
-    #[test]
-    fn test_instruction_from_str() {
-        assert!(Instruction::from_str("").is_err());
-        assert!(Instruction::from_str("omg").is_err());
-        assert!(Instruction::from_str("inc 5").is_err());
-
-        assert_eq!(Instruction::from_str("cpy 41 a").unwrap(),
-                   Instruction::Cpy(Variable::Value(41), Register::A));
-        assert_eq!(Instruction::from_str("inc a").unwrap(),
-                   Instruction::Inc(Register::A));
-        assert_eq!(Instruction::from_str("dec b").unwrap(),
-                   Instruction::Dec(Register::B));
-        assert_eq!(Instruction::from_str("jnz c 2").unwrap(),
-                   Instruction::Jnz(Variable::Register(Register::C), 2));
-    }
-}
diff --git a/2016/rust/src/lib.rs b/2016/rust/src/lib.rs
index 8963715..1130314 100644
--- a/2016/rust/src/lib.rs
+++ b/2016/rust/src/lib.rs
@@ -6,6 +6,7 @@ extern crate error_chain;
 extern crate regex;
 extern crate crypto;
 
+mod assembunny;
 pub mod errors;
 pub mod day_01;
 pub mod day_02;