use std::default::Default;
use std::io::{Read, Write};
use std::num::Wrapping;
use common::{BfResult, Error};
use traits::IntoUsize;
pub const DEFAULT_CAPACITY: usize = 30_000;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct State {
memory: Box<[Wrapping<u8>]>,
pointer: usize,
}
impl State {
pub fn new() -> Self {
Self::with_capacity(DEFAULT_CAPACITY)
}
pub fn with_capacity(memory_size: usize) -> Self {
State {
memory: vec![Wrapping(0); memory_size].into_boxed_slice(),
pointer: 0,
}
}
#[inline]
pub fn left<C: IntoUsize>(&mut self, count: C) -> BfResult<()> {
self.pointer = self.neg_offset(count)?;
Ok(())
}
#[inline]
pub fn right<C: IntoUsize>(&mut self, count: C) -> BfResult<()> {
self.pointer = self.pos_offset(count)?;
Ok(())
}
#[inline]
fn pos_offset<C: IntoUsize>(&self, offset: C) -> BfResult<usize> {
let offset = offset.into_usize();
if self.pointer + offset < self.memory.len() {
Ok(self.pointer + offset)
} else {
Err(Error::PointerOverflow)
}
}
#[inline]
fn neg_offset<C: IntoUsize>(&self, offset: C) -> BfResult<usize> {
let offset = offset.into_usize();
if self.pointer >= offset {
Ok(self.pointer - offset)
} else {
Err(Error::PointerUnderflow)
}
}
#[inline]
pub fn up(&mut self, count: u8) {
self.memory[self.pointer] += Wrapping(count);
}
#[inline]
pub fn down(&mut self, count: u8) {
self.memory[self.pointer] -= Wrapping(count);
}
#[inline]
pub fn load(&self) -> u8 {
self.memory[self.pointer].0
}
#[inline]
pub fn store(&mut self, value: u8) {
self.memory[self.pointer] = Wrapping(value);
}
#[inline]
pub fn up_pos_offset<C: IntoUsize>(&mut self, offset: C, value: u8) -> BfResult<()> {
let address = self.pos_offset(offset)?;
self.memory[address] += Wrapping(value);
Ok(())
}
#[inline]
pub fn up_neg_offset<C: IntoUsize>(&mut self, offset: C, value: u8) -> BfResult<()> {
let address = self.neg_offset(offset)?;
self.memory[address] += Wrapping(value);
Ok(())
}
#[inline]
pub fn read<R: Read>(&mut self, input: &mut R) {
let mut byte = [0];
let _ = input.read_exact(&mut byte);
self.store(byte[0]);
}
#[inline]
pub fn write<W: Write>(&self, output: &mut W) {
let _ = output.write_all(&[self.load()]);
}
pub fn capacity(&self) -> usize {
self.memory.len()
}
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.memory.as_mut_ptr() as *mut u8
}
}
impl Default for State {
fn default() -> Self {
State::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn right_moves_right() {
let mut actual = make(&[0, 0, 0], 0);
let expected = make(&[0, 0, 0], 1);
actual.right(1usize).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn right_then_left_restores() {
let mut actual = make(&[0, 0, 0], 0);
let expected = make(&[0, 0, 0], 0);
actual.right(1usize).unwrap();
actual.left(1usize).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn up_goes_to_1() {
let mut actual = make(&[0, 0, 0], 0);
actual.up(1);
assert_eq!(actual, make(&[1, 0, 0], 0))
}
#[test]
fn down_goes_to_255() {
let mut actual = make(&[0, 0, 0], 0);
actual.down(1);
assert_eq!(actual, make(&[255, 0, 0], 0))
}
#[test]
fn load_reads() {
assert_eq!(make(&[0, 0, 0], 0).load(), 0);
assert_eq!(make(&[1, 0, 0], 0).load(), 1);
assert_eq!(make(&[1, 2, 0], 1).load(), 2);
}
#[test]
fn store_writes() {
let mut actual = make(&[0, 0, 0], 0);
actual.store(5);
assert_eq!(actual, make(&[5, 0, 0], 0));
actual.right(1usize).unwrap();
actual.store(8);
assert_eq!(actual, make(&[5, 8, 0], 1));
}
#[test]
fn longer_sequence_of_actions() {
let mut actual = make(&[0, 0, 0], 0);
actual.up(1);
assert_eq!(actual, make(&[1, 0, 0], 0));
actual.up(1);
assert_eq!(actual, make(&[2, 0, 0], 0));
actual.right(1usize).unwrap();
assert_eq!(actual, make(&[2, 0, 0], 1));
actual.down(1);
assert_eq!(actual, make(&[2, 255, 0], 1));
actual.down(1);
assert_eq!(actual, make(&[2, 254, 0], 1));
actual.right(1usize).unwrap();
assert_eq!(actual, make(&[2, 254, 0], 2));
actual.store(77);
assert_eq!(actual, make(&[2, 254, 77], 2));
}
#[test]
fn right_to_right_edge_is_okay() {
let mut actual = make(&[0, 0, 0], 0);
actual.right(1usize).unwrap();
actual.right(1usize).unwrap();
assert_eq!(actual, make(&[0, 0, 0], 2));
}
#[test]
#[should_panic]
fn right_past_edge_is_error() {
let mut actual = make(&[0, 0, 0], 0);
actual.right(1usize).unwrap();
actual.right(1usize).unwrap();
actual.right(1usize).unwrap();
}
#[test]
#[should_panic]
fn move_left_is_error() {
let mut machine = make(&[0, 0, 0], 0);
machine.left(1usize).unwrap();
}
fn make(memory: &[u8], pointer: usize) -> State {
State {
memory: memory.iter().map(|&b| Wrapping(b)).collect::<Vec<_>>().into_boxed_slice(),
pointer: pointer,
}
}
}