<commit_before>use definitions::{ExternalInterrupt, InternalInterrupt};
use definitions::Config;
use definitions::Instruction;
use definitions::Program;
use definitions::Signal;
use definitions::Target;
use definitions::Value;
use definitions::typedef::*;
use error::*;
use std::collections::{BTreeMap, HashMap, LinkedList};
use std::sync::mpsc::{Receiver, SyncSender, TrySendError};
use std::thread::{self, JoinHandle};

pub fn start(program: Program, sender: SyncSender<Frame>, receiver: Receiver<ExternalInterrupt>)
    -> JoinHandle<()> {
    thread::spawn(
        move || {
            if let Err(ref e) = VM::default().exec(program, sender, receiver) {
                println!("error: {}", e);

                for e in e.iter().skip(1) {
                    println!("caused by: {}", e);
                }

                // The backtrace is not always generated. Try to run this example
                // with `RUST_BACKTRACE=1`.
                if let Some(backtrace) = e.backtrace() {
                    println!("backtrace: {:?}", backtrace);
                }
            }
        },
    )
}

/// Since rusts `std:::cmp::Ordering` doesn't implement serialization, we have
/// to do this
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Ordering {
    Less,
    Greater,
    Equal,
}

/// The whole state of the VM
#[derive(Serialize, Deserialize, Default, Debug)]
struct VM {
    /// The instructions that are currently executed
    image_data: Vec<Instruction>,
    /// The current program counter
    pc: Address,
    stack: LinkedList<Value>,
    val_index: BTreeMap<Address, Value>,
    interrupt_register: HashMap<Signal, Address>,
    framebuffer: Frame,
    framebuffer_invalid: bool,
    /// A register for holding information about a recent comparison
    cmp_register: Option<Ordering>,
    /// A stack to hold the return addresses of function calls
    call_stack: LinkedList<Address>,
    /// A boolean used for locking the program counter
    pc_locked: bool,
    /// The configuration of the VM
    config: Config,
    halted: bool,
}

impl VM {
    // # Maintainance functions

    /// Executes the given program
    pub fn exec(
        &mut self, program: Program, sender: SyncSender<Frame>,
        receiver: Receiver<ExternalInterrupt>
    ) -> VMResult<()> {
        self.reset();
        self.load_program(program)?;
        self.build_framebuffer();

        while (self.pc < self.image_data.len()) && !self.halted {
            self.external_interrupt(&receiver)?;

            let current_instruction = self.image_data[self.pc].clone();
            self.handle_instruction(current_instruction)?;

            self.flush_framebuffer(&sender)?;

            self.advance_pc();

            thread::yield_now();
        }

        Ok(())
    }

    /// Handles a single instruction
    fn handle_instruction(&mut self, instruction: Instruction) -> VMResult<()> {
        match instruction {
            Instruction::Halt => self.halt(),
            Instruction::Int(interrupt) => self.int(&interrupt),
            Instruction::Ext(signal, addr) => self.ext(signal, addr),

            Instruction::Add(dest, src) => self.add(&dest, &src)?,
            Instruction::Sub(dest, src) => self.sub(&dest, &src)?,
            Instruction::Div(dest, src) => self.div(&dest, &src)?,
            Instruction::Mul(dest, src) => self.mul(&dest, &src)?,
            Instruction::Rem(dest, src) => self.rem(&dest, &src)?,

            Instruction::Cmp(target_a, target_b) => self.cmp(&target_a, &target_b)?,
            Instruction::Jmp(addr) => self.jmp(&addr),
            Instruction::JmpLt(addr) => self.jmp_lt(&addr),
            Instruction::JmpGt(addr) => self.jmp_gt(&addr),
            Instruction::JmpEq(addr) => self.jmp_eq(&addr),
            Instruction::JmpLtEq(addr) => self.jmp_lt_eq(&addr),
            Instruction::JmpGtEq(addr) => self.jmp_gt_eq(&addr),

            Instruction::Push(dest, value) => self.push(&dest, value)?,
            Instruction::Mov(dest, src) => self.mov(&dest, &src)?,
            Instruction::Swp(target_a, target_b) => self.swp(&target_a, &target_b)?,

            Instruction::Call(addr) => self.call(&addr),
            Instruction::Ret => self.ret()?,
        }

        Ok(())
    }

    /// Loads the instructions of the given program to the VM's state
    fn load_program(&mut self, program: Program) -> VMResult<()> {
        let orig_program = Program::default();
        if program.preamble != orig_program.preamble {
            bail!("invalid preamble");
        } else if program.version != orig_program.version {
            bail!("invalid version");
        } else {
            self.image_data = program.instructions;
            self.config = program.config;
            Ok(())
        }
    }

    /// Aborts the execution of the current image
    fn halt(&mut self) {
        self.halted = true;
    }

    /// Handles an internal interrupt
    fn int(&mut self, interrupt: &InternalInterrupt) {
        match interrupt {
            &InternalInterrupt::FlushFramebuffer => self.invalidate(),
        }
    }

    /// Registers an external interrupt for a specific signal
    fn ext(&mut self, signal: Signal, addr: Address) {
        self.interrupt_register.entry(signal).or_insert(addr);
    }

    /// Handles incoming interrupts or moves along
    fn external_interrupt(&mut self, receiver: &Receiver<ExternalInterrupt>) -> VMResult<()> {
        match receiver.try_recv() {
            Ok(interrupt) => {
                if interrupt.signal == Signal::Halt {
                    self.halt();
                    return Ok(());
                }

                let call_addr = if let Some(call_addr) = self.interrupt_register
                       .get(&interrupt.signal) {
                    call_addr.clone()
                } else {
                    bail!(
                        "no registered interrupt found at signal {:?}",
                        &interrupt.signal
                    );
                };

                for value in interrupt.args {
                    self.push(&Target::Stack, value)?;
                }

                self.call(&call_addr);

                Ok(())
            }
            _ => Ok(()),
        }
    }

    /// Flushes the internal framebuffer using the given sender
    fn flush_framebuffer(&mut self, sender: &SyncSender<Frame>) -> VMResult<()> {
        if self.framebuffer_invalid {
            if let Err(TrySendError::Disconnected(..)) = sender.try_send(self.framebuffer.clone()) {
                bail!("output channel disconnected");
            }

            self.framebuffer_invalid = false;
        }

        Ok(())
    }

    /// Allocates all the needed space in the framebuffer
    fn build_framebuffer(&mut self) {
        let ref resolution = self.config.display.resolution;
        let allocation_space = resolution.width * resolution.height;
        self.framebuffer = vec![Color::default(); allocation_space];
    }

    /// Resets the VM to a clean state
    fn reset(&mut self) {
        *self = VM::default();
    }

    /// Locks the program counter in place
    fn lock_pc(&mut self) {
        self.pc_locked = true;
    }

    /// Advances the program counter
    fn advance_pc(&mut self) {
        if self.pc_locked {
            self.pc_locked = false;
        } else {
            self.pc += 1;
        }
    }

    /// Invalidates the frambuffer causing it to be resent to the display
    /// receiver
    fn invalidate(&mut self) {
        self.framebuffer_invalid = true;
    }

    /// Return the value at the specified target. The value of the target will
    /// be consumed
    fn pop(&mut self, target: &Target) -> VMResult<Value> {
        match target {
            &Target::ValueIndex(index) => {
                if let Some(value) = self.val_index.remove(&index) {
                    Ok(value)
                } else {
                    bail!("no value found at index {}", index);
                }
            }
            &Target::Stack => {
                if let Some(value) = self.stack.pop_front() {
                    Ok(value)
                } else {
                    bail!("unable to pop value off an empty stack");
                }
            }
            &Target::Framebuffer(index) => {
                if let Some(&(r, g, b)) = self.framebuffer.get(index) {
                    Ok(Value::Color(r, g, b))
                } else {
                    bail!("no value found in framebuffer at index {}", index);
                }
            }
        }
    }

    // # Instruction functions

    /// Adds the value of the src target to the value of the dest target
    fn add(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value + src_value)?;

        Ok(())
    }

    /// Subtracts the value of the src target from the value of the dest target
    fn sub(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value - src_value)?;

        Ok(())
    }

    /// Divides the value of the dest target through the value of the src target
    fn div(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value / src_value)?;

        Ok(())
    }

    /// Multiplies the value of the dest target with the value of the src target
    fn mul(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value * src_value)?;

        Ok(())
    }

    /// Applies the modulo operator on the value of the dest target using the
    /// value of the src target
    fn rem(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value * src_value)?;

        Ok(())
    }

    /// Compares the top values of the two targets and saves the result to
    /// `self.cmp_register`
    fn cmp(&mut self, target_a: &Target, target_b: &Target) -> VMResult<()> {
        let target_a_value = self.pop(target_a)?;
        let target_b_value = self.pop(target_b)?;

        if target_a_value < target_b_value {
            self.cmp_register = Some(Ordering::Less);
        } else if target_a_value > target_b_value {
            self.cmp_register = Some(Ordering::Greater);
        } else if target_a_value == target_b_value {
            self.cmp_register = Some(Ordering::Equal);
        }

        Ok(())
    }

    /// Jumps unconditionally to the specified address
    fn jmp(&mut self, addr: &Address) {
        self.pc = *addr;
        self.lock_pc();
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)`
    fn jmp_lt(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Less) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)`
    fn jmp_gt(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Greater) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Equal)`
    fn jmp_eq(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Equal) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)` or
    /// `Some(Ordering::Equal)`
    fn jmp_lt_eq(&mut self, addr: &Address) {
        if (self.cmp_register == Some(Ordering::Less)) ||
           (self.cmp_register == Some(Ordering::Equal)) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)` or
    /// `Some(Ordering::Equal)`
    fn jmp_gt_eq(&mut self, addr: &Address) {
        if (self.cmp_register == Some(Ordering::Greater)) ||
           (self.cmp_register == Some(Ordering::Equal)) {
            self.jmp(addr);
        }
    }

    /// Pushes the given value to the given target
    fn push(&mut self, dest: &Target, value: Value) -> VMResult<()> {
        match dest {
            &Target::ValueIndex(index) => {
                self.val_index.entry(index).or_insert(value);
                Ok(())
            }
            &Target::Stack => {
                self.stack.push_front(value);
                Ok(())
            }
            &Target::Framebuffer(index) => {
                if let Value::Color(r, g, b) = value {
                    self.framebuffer[index] = (r, g, b);
                    Ok(())
                } else {
                    bail!("unable push a non-color value to the framebuffer");
                }
            }
        }
    }

    /// Moves the top value of the src target to the dest target
    fn mov(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let src_value = self.pop(src)?;
        self.push(dest, src_value)?;

        Ok(())
    }

    /// Swaps the top values of the targets
    fn swp(&mut self, target_a: &Target, target_b: &Target) -> VMResult<()> {
        let a_value = self.pop(target_a)?;
        let b_value = self.pop(target_b)?;

        self.push(target_a, b_value)?;
        self.push(target_b, a_value)?;

        Ok(())
    }

    /// Calls the function at the specified address saving the return address
    /// to the call stack
    fn call(&mut self, addr: &Address) {
        self.call_stack.push_front(self.pc + 1);
        self.jmp(addr);
    }

    /// Returns from an ongoing function call
    fn ret(&mut self) -> VMResult<()> {
        if let Some(retur_addr) = self.call_stack.pop_front() {
            self.jmp(&retur_addr);
        } else {
            bail!("unable to return from an empty call stack");
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn halt() {
        let mut vm = VM::default();
        vm.handle_instruction(Instruction::Halt).expect("handling instruction failed");

        assert!(vm.halted);
    }
}
<commit_msg>simplified test<commit_after>use definitions::{ExternalInterrupt, InternalInterrupt};
use definitions::Config;
use definitions::Instruction;
use definitions::Program;
use definitions::Signal;
use definitions::Target;
use definitions::Value;
use definitions::typedef::*;
use error::*;
use std::collections::{BTreeMap, HashMap, LinkedList};
use std::sync::mpsc::{Receiver, SyncSender, TrySendError};
use std::thread::{self, JoinHandle};

pub fn start(program: Program, sender: SyncSender<Frame>, receiver: Receiver<ExternalInterrupt>)
    -> JoinHandle<()> {
    thread::spawn(
        move || {
            if let Err(ref e) = VM::default().exec(program, sender, receiver) {
                println!("error: {}", e);

                for e in e.iter().skip(1) {
                    println!("caused by: {}", e);
                }

                // The backtrace is not always generated. Try to run this example
                // with `RUST_BACKTRACE=1`.
                if let Some(backtrace) = e.backtrace() {
                    println!("backtrace: {:?}", backtrace);
                }
            }
        },
    )
}

/// Since rusts `std:::cmp::Ordering` doesn't implement serialization, we have
/// to do this
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Ordering {
    Less,
    Greater,
    Equal,
}

/// The whole state of the VM
#[derive(Serialize, Deserialize, Default, Debug)]
struct VM {
    /// The instructions that are currently executed
    image_data: Vec<Instruction>,
    /// The current program counter
    pc: Address,
    stack: LinkedList<Value>,
    val_index: BTreeMap<Address, Value>,
    interrupt_register: HashMap<Signal, Address>,
    framebuffer: Frame,
    framebuffer_invalid: bool,
    /// A register for holding information about a recent comparison
    cmp_register: Option<Ordering>,
    /// A stack to hold the return addresses of function calls
    call_stack: LinkedList<Address>,
    /// A boolean used for locking the program counter
    pc_locked: bool,
    /// The configuration of the VM
    config: Config,
    halted: bool,
}

impl VM {
    // # Maintainance functions

    /// Executes the given program
    pub fn exec(
        &mut self, program: Program, sender: SyncSender<Frame>,
        receiver: Receiver<ExternalInterrupt>
    ) -> VMResult<()> {
        self.reset();
        self.load_program(program)?;
        self.build_framebuffer();

        while (self.pc < self.image_data.len()) && !self.halted {
            self.external_interrupt(&receiver)?;

            let current_instruction = self.image_data[self.pc].clone();
            self.handle_instruction(current_instruction)?;

            self.flush_framebuffer(&sender)?;

            self.advance_pc();

            thread::yield_now();
        }

        Ok(())
    }

    /// Handles a single instruction
    fn handle_instruction(&mut self, instruction: Instruction) -> VMResult<()> {
        match instruction {
            Instruction::Halt => self.halt(),
            Instruction::Int(interrupt) => self.int(&interrupt),
            Instruction::Ext(signal, addr) => self.ext(signal, addr),

            Instruction::Add(dest, src) => self.add(&dest, &src)?,
            Instruction::Sub(dest, src) => self.sub(&dest, &src)?,
            Instruction::Div(dest, src) => self.div(&dest, &src)?,
            Instruction::Mul(dest, src) => self.mul(&dest, &src)?,
            Instruction::Rem(dest, src) => self.rem(&dest, &src)?,

            Instruction::Cmp(target_a, target_b) => self.cmp(&target_a, &target_b)?,
            Instruction::Jmp(addr) => self.jmp(&addr),
            Instruction::JmpLt(addr) => self.jmp_lt(&addr),
            Instruction::JmpGt(addr) => self.jmp_gt(&addr),
            Instruction::JmpEq(addr) => self.jmp_eq(&addr),
            Instruction::JmpLtEq(addr) => self.jmp_lt_eq(&addr),
            Instruction::JmpGtEq(addr) => self.jmp_gt_eq(&addr),

            Instruction::Push(dest, value) => self.push(&dest, value)?,
            Instruction::Mov(dest, src) => self.mov(&dest, &src)?,
            Instruction::Swp(target_a, target_b) => self.swp(&target_a, &target_b)?,

            Instruction::Call(addr) => self.call(&addr),
            Instruction::Ret => self.ret()?,
        }

        Ok(())
    }

    /// Loads the instructions of the given program to the VM's state
    fn load_program(&mut self, program: Program) -> VMResult<()> {
        let orig_program = Program::default();
        if program.preamble != orig_program.preamble {
            bail!("invalid preamble");
        } else if program.version != orig_program.version {
            bail!("invalid version");
        } else {
            self.image_data = program.instructions;
            self.config = program.config;
            Ok(())
        }
    }

    /// Aborts the execution of the current image
    fn halt(&mut self) {
        self.halted = true;
    }

    /// Handles an internal interrupt
    fn int(&mut self, interrupt: &InternalInterrupt) {
        match interrupt {
            &InternalInterrupt::FlushFramebuffer => self.invalidate(),
        }
    }

    /// Registers an external interrupt for a specific signal
    fn ext(&mut self, signal: Signal, addr: Address) {
        self.interrupt_register.entry(signal).or_insert(addr);
    }

    /// Handles incoming interrupts or moves along
    fn external_interrupt(&mut self, receiver: &Receiver<ExternalInterrupt>) -> VMResult<()> {
        match receiver.try_recv() {
            Ok(interrupt) => {
                if interrupt.signal == Signal::Halt {
                    self.halt();
                    return Ok(());
                }

                let call_addr = if let Some(call_addr) = self.interrupt_register
                       .get(&interrupt.signal) {
                    call_addr.clone()
                } else {
                    bail!(
                        "no registered interrupt found at signal {:?}",
                        &interrupt.signal
                    );
                };

                for value in interrupt.args {
                    self.push(&Target::Stack, value)?;
                }

                self.call(&call_addr);

                Ok(())
            }
            _ => Ok(()),
        }
    }

    /// Flushes the internal framebuffer using the given sender
    fn flush_framebuffer(&mut self, sender: &SyncSender<Frame>) -> VMResult<()> {
        if self.framebuffer_invalid {
            if let Err(TrySendError::Disconnected(..)) = sender.try_send(self.framebuffer.clone()) {
                bail!("output channel disconnected");
            }

            self.framebuffer_invalid = false;
        }

        Ok(())
    }

    /// Allocates all the needed space in the framebuffer
    fn build_framebuffer(&mut self) {
        let ref resolution = self.config.display.resolution;
        let allocation_space = resolution.width * resolution.height;
        self.framebuffer = vec![Color::default(); allocation_space];
    }

    /// Resets the VM to a clean state
    fn reset(&mut self) {
        *self = VM::default();
    }

    /// Locks the program counter in place
    fn lock_pc(&mut self) {
        self.pc_locked = true;
    }

    /// Advances the program counter
    fn advance_pc(&mut self) {
        if self.pc_locked {
            self.pc_locked = false;
        } else {
            self.pc += 1;
        }
    }

    /// Invalidates the frambuffer causing it to be resent to the display
    /// receiver
    fn invalidate(&mut self) {
        self.framebuffer_invalid = true;
    }

    /// Return the value at the specified target. The value of the target will
    /// be consumed
    fn pop(&mut self, target: &Target) -> VMResult<Value> {
        match target {
            &Target::ValueIndex(index) => {
                if let Some(value) = self.val_index.remove(&index) {
                    Ok(value)
                } else {
                    bail!("no value found at index {}", index);
                }
            }
            &Target::Stack => {
                if let Some(value) = self.stack.pop_front() {
                    Ok(value)
                } else {
                    bail!("unable to pop value off an empty stack");
                }
            }
            &Target::Framebuffer(index) => {
                if let Some(&(r, g, b)) = self.framebuffer.get(index) {
                    Ok(Value::Color(r, g, b))
                } else {
                    bail!("no value found in framebuffer at index {}", index);
                }
            }
        }
    }

    // # Instruction functions

    /// Adds the value of the src target to the value of the dest target
    fn add(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value + src_value)?;

        Ok(())
    }

    /// Subtracts the value of the src target from the value of the dest target
    fn sub(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value - src_value)?;

        Ok(())
    }

    /// Divides the value of the dest target through the value of the src target
    fn div(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value / src_value)?;

        Ok(())
    }

    /// Multiplies the value of the dest target with the value of the src target
    fn mul(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value * src_value)?;

        Ok(())
    }

    /// Applies the modulo operator on the value of the dest target using the
    /// value of the src target
    fn rem(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value * src_value)?;

        Ok(())
    }

    /// Compares the top values of the two targets and saves the result to
    /// `self.cmp_register`
    fn cmp(&mut self, target_a: &Target, target_b: &Target) -> VMResult<()> {
        let target_a_value = self.pop(target_a)?;
        let target_b_value = self.pop(target_b)?;

        if target_a_value < target_b_value {
            self.cmp_register = Some(Ordering::Less);
        } else if target_a_value > target_b_value {
            self.cmp_register = Some(Ordering::Greater);
        } else if target_a_value == target_b_value {
            self.cmp_register = Some(Ordering::Equal);
        }

        Ok(())
    }

    /// Jumps unconditionally to the specified address
    fn jmp(&mut self, addr: &Address) {
        self.pc = *addr;
        self.lock_pc();
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)`
    fn jmp_lt(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Less) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)`
    fn jmp_gt(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Greater) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Equal)`
    fn jmp_eq(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Equal) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)` or
    /// `Some(Ordering::Equal)`
    fn jmp_lt_eq(&mut self, addr: &Address) {
        if (self.cmp_register == Some(Ordering::Less)) ||
           (self.cmp_register == Some(Ordering::Equal)) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)` or
    /// `Some(Ordering::Equal)`
    fn jmp_gt_eq(&mut self, addr: &Address) {
        if (self.cmp_register == Some(Ordering::Greater)) ||
           (self.cmp_register == Some(Ordering::Equal)) {
            self.jmp(addr);
        }
    }

    /// Pushes the given value to the given target
    fn push(&mut self, dest: &Target, value: Value) -> VMResult<()> {
        match dest {
            &Target::ValueIndex(index) => {
                self.val_index.entry(index).or_insert(value);
                Ok(())
            }
            &Target::Stack => {
                self.stack.push_front(value);
                Ok(())
            }
            &Target::Framebuffer(index) => {
                if let Value::Color(r, g, b) = value {
                    self.framebuffer[index] = (r, g, b);
                    Ok(())
                } else {
                    bail!("unable push a non-color value to the framebuffer");
                }
            }
        }
    }

    /// Moves the top value of the src target to the dest target
    fn mov(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let src_value = self.pop(src)?;
        self.push(dest, src_value)?;

        Ok(())
    }

    /// Swaps the top values of the targets
    fn swp(&mut self, target_a: &Target, target_b: &Target) -> VMResult<()> {
        let a_value = self.pop(target_a)?;
        let b_value = self.pop(target_b)?;

        self.push(target_a, b_value)?;
        self.push(target_b, a_value)?;

        Ok(())
    }

    /// Calls the function at the specified address saving the return address
    /// to the call stack
    fn call(&mut self, addr: &Address) {
        self.call_stack.push_front(self.pc + 1);
        self.jmp(addr);
    }

    /// Returns from an ongoing function call
    fn ret(&mut self) -> VMResult<()> {
        if let Some(retur_addr) = self.call_stack.pop_front() {
            self.jmp(&retur_addr);
        } else {
            bail!("unable to return from an empty call stack");
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn halt() {
        let mut vm = VM::default();
        vm.handle_instruction(Instruction::Halt);

        println!("{:#?}", vm);

        assert!(vm.halted);
    }
}
<|endoftext|>


<commit_before>// Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR.
// Compiling with `-Cpanic=abort` because PGO+unwinding isn't supported on all platforms.

// needs-profiler-support
// compile-flags: -Cprofile-generate -Ccodegen-units=1 -Cpanic=abort

// CHECK: @__llvm_profile_raw_version =
// CHECK: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = private global
// CHECK: @__profd_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = private global
// CHECK: @__profc_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = private global
// CHECK: @__profd_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = private global
// CHECK: @__llvm_profile_filename = {{.*}}"default_%m.profraw\00"{{.*}}

#![crate_type="lib"]

#[inline(never)]
fn some_function() {

}

pub fn some_other_function() {
    some_function();
}
<commit_msg>Relax checks in pgo-instrumentation codegen test<commit_after>// Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR.
// Compiling with `-Cpanic=abort` because PGO+unwinding isn't supported on all platforms.

// needs-profiler-support
// compile-flags: -Cprofile-generate -Ccodegen-units=1 -Cpanic=abort

// CHECK: @__llvm_profile_raw_version =
// CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global
// CHECK-DAG: @__profd_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global
// CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = {{.*}}global
// CHECK-DAG: @__profd_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = {{.*}}global
// CHECK: @__llvm_profile_filename = {{.*}}"default_%m.profraw\00"{{.*}}

#![crate_type="lib"]

#[inline(never)]
fn some_function() {

}

pub fn some_other_function() {
    some_function();
}
<|endoftext|>


<commit_before>use ron::ser::{to_string_pretty, PrettyConfig};
use ron::de::from_str;
use serde::Deserialize;
use serde::Serialize;
use std::{collections::HashMap, fs::File};
use std::env;
use std::fs;

#[derive(Debug, Deserialize, Serialize)]
struct Config {
    boolean: bool,
    float: f32,
    map: HashMap<u8, char>,
    nested: Nested,
    tuple: (u32, u32),
}

#[derive(Debug, Deserialize, Serialize)]
struct Nested {
    a: String,
    b: char,
}

fn read_original(source: &str) -> (String) {
    source.to_string()
}

fn make_roundtrip(source: &str) -> (String) {
    let config: Config = match from_str(source) {
        Ok(x) => x,
        Err(e) => {
            println!("Failed to load config: {}", e);
            std::process::exit(1);
        }
    };
    let pretty = PrettyConfig::new()
        .with_depth_limit(3)
        .with_separate_tuple_members(true)
        .with_enumerate_arrays(true);
    to_string_pretty(&config, pretty).expect("Serialization failed")
}

#[test]
fn test_sequence_ex1()
{
    let file = include_str!("preserve_sequence_ex1.ron");
    assert_eq!(
        read_original(file),
        make_roundtrip(file)
    );
}

#[test]
fn test_sequence_ex2()
{
    let file = include_str!("preserve_sequence_ex2.ron");
    assert_eq!(
        read_original(file),
        make_roundtrip(file)
    );
}
<commit_msg>Using BTreeMap i.s.o. HashMap preserves input sequence of map. Removed unused use-statements.<commit_after>use ron::ser::{to_string_pretty, PrettyConfig};
use ron::de::from_str;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;

#[derive(Debug, Deserialize, Serialize)]
struct Config {
    boolean: bool,
    float: f32,
    map: BTreeMap<u8, char>,
    nested: Nested,
    tuple: (u32, u32),
}

#[derive(Debug, Deserialize, Serialize)]
struct Nested {
    a: String,
    b: char,
}

fn read_original(source: &str) -> (String) {
    source.to_string()
}

fn make_roundtrip(source: &str) -> (String) {
    let config: Config = match from_str(source) {
        Ok(x) => x,
        Err(e) => {
            println!("Failed to load config: {}", e);
            std::process::exit(1);
        }
    };
    let pretty = PrettyConfig::new()
        .with_depth_limit(3)
        .with_separate_tuple_members(true)
        .with_enumerate_arrays(true);
    to_string_pretty(&config, pretty).expect("Serialization failed")
}

#[test]
fn test_sequence_ex1()
{
    let file = include_str!("preserve_sequence_ex1.ron");
    assert_eq!(
        read_original(file),
        make_roundtrip(file)
    );
}

#[test]
fn test_sequence_ex2()
{
    let file = include_str!("preserve_sequence_ex2.ron");
    assert_eq!(
        read_original(file),
        make_roundtrip(file)
    );
}
<|endoftext|>


<commit_before>use libsodium_sys::*;
use noise_protocol::*;
use sodiumoxide::crypto::hash::{sha256, sha512};
use sodiumoxide::crypto::scalarmult::curve25519;
use sodiumoxide::init as sodium_init;
use sodiumoxide::randombytes::randombytes_into;
use sodiumoxide::utils::memzero;
use std::mem::{swap, uninitialized};
use std::ptr::{null, null_mut};

/// Initialize the library. Call the `sodium_init` function.
///
/// `sodium_init()` initializes the library and should be called before any other function provided by Sodium. It is safe to call this function more than once and from different threads -- subsequent calls won't have any effects.
/// After this function returns, all of the other functions provided by Sodium will be thread-safe.
///
/// Libsodium doc: <https://libsodium.gitbook.io/doc/usage>.
pub fn init() -> Result<(), ()> {
    sodium_init()
}

#[derive(Debug)]
pub struct X25519Key(curve25519::Scalar);

impl U8Array for X25519Key {
    fn new() -> Self {
        X25519Key(curve25519::Scalar([0u8; 32]))
    }

    fn new_with(v: u8) -> Self {
        X25519Key(curve25519::Scalar([v; 32]))
    }

    fn from_slice(s: &[u8]) -> Self {
        X25519Key(curve25519::Scalar::from_slice(s).unwrap())
    }

    fn len() -> usize {
        32
    }

    fn as_slice(&self) -> &[u8] {
        &(self.0).0
    }

    fn as_mut(&mut self) -> &mut [u8] {
        &mut (self.0).0
    }
}

#[derive(Debug)]
pub struct Sensitive(A);

impl Drop for Sensitive
where
    A: U8Array,
{
    fn drop(&mut self) {
        memzero(self.0.as_mut())
    }
}

impl U8Array for Sensitive
where
    A: U8Array,
{
    fn new() -> Self {
        Sensitive(A::new())
    }

    fn new_with(v: u8) -> Self {
        Sensitive(A::new_with(v))
    }

    fn from_slice(s: &[u8]) -> Self {
        Sensitive(A::from_slice(s))
    }

    fn len() -> usize {
        A::len()
    }

    fn as_slice(&self) -> &[u8] {
        self.0.as_slice()
    }

    fn as_mut(&mut self) -> &mut [u8] {
        self.0.as_mut()
    }
}

pub enum X25519 {}

pub enum ChaCha20Poly1305 {}

/// The AES-256-GCM AEAD.
///
/// # Portability Warning
///
/// The current implementation of this construction is hardware-accelerated and requires the Intel SSSE3 extensions, as well as the `aesni` and `pclmul` instructions.
///
/// Intel Westmere processors (introduced in 2010) and newer meet the requirements.
///
/// There are no plans to support non hardware-accelerated implementations of AES-GCM. If portability is a concern, use ChaCha20-Poly1305 instead.
///
/// Before using the functions below, hardware support for AES can be checked with <Aes256Gcm::available>.
///
/// The function returns `true` if the current CPU supports the AES256-GCM implementation, and `false` if it doesn't.
///
/// The library must have been initialized with [init](init) prior to calling this function.
///
/// Libsodium doc: <https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/aes-256-gcm#limitations>.
pub enum Aes256Gcm {}

impl Aes256Gcm {
    /// Check for hardware support of AES-GCM.
    ///
    /// The function returns `true` if the current CPU supports the AES256-GCM implementation, and `false` if it doesn't.
    pub fn available() -> bool {
        unsafe { crypto_aead_aes256gcm_is_available() != 0 }
    }
}

#[derive(Default)]
pub struct Sha256 {
    state: sha256::State,
}

#[derive(Default)]
pub struct Sha512 {
    state: sha512::State,
}

#[repr(transparent)]
pub struct Blake2b {
    state: crypto_generichash_state,
}

impl DH for X25519 {
    type Key = X25519Key;
    type Pubkey = [u8; 32];
    type Output = Sensitive<[u8; 32]>;

    fn name() -> &'static str {
        "25519"
    }

    fn genkey() -> Self::Key {
        let mut k = [0u8; 32];
        randombytes_into(&mut k);
        k[0] &= 248;
        k[31] &= 127;
        k[31] |= 64;
        X25519Key(curve25519::Scalar(k))
    }

    fn pubkey(k: &Self::Key) -> Self::Pubkey {
        curve25519::scalarmult_base(&k.0).0
    }

    /// Returns `Err(())` if DH output is all-zero.
    fn dh(k: &Self::Key, pk: &Self::Pubkey) -> Result<Self::Output, ()> {
        let pk = curve25519::GroupElement(*pk);
        curve25519::scalarmult(&k.0, &pk).map(|x| Sensitive(x.0))
    }
}

impl Cipher for ChaCha20Poly1305 {
    type Key = Sensitive<[u8; 32]>;

    fn name() -> &'static str {
        "ChaChaPoly"
    }

    fn encrypt(k: &Self::Key, nonce: u64, ad: &[u8], plaintext: &[u8], out: &mut [u8]) {
        assert_eq!(out.len(), plaintext.len() + 16);

        let mut n = [0u8; 12];
        n[4..].copy_from_slice(&nonce.to_le_bytes());

        unsafe {
            crypto_aead_chacha20poly1305_ietf_encrypt(
                out.as_mut_ptr(),
                null_mut(),
                plaintext.as_ptr(),
                plaintext.len() as u64,
                ad.as_ptr(),
                ad.len() as u64,
                null(),
                n.as_ptr(),
                k.0.as_ptr(),
            );
        }
    }

    fn decrypt(
        k: &Self::Key,
        nonce: u64,
        ad: &[u8],
        ciphertext: &[u8],
        out: &mut [u8],
    ) -> Result<(), ()> {
        assert_eq!(out.len() + 16, ciphertext.len());

        let mut n = [0u8; 12];
        n[4..].copy_from_slice(&nonce.to_le_bytes());

        let ret = unsafe {
            crypto_aead_chacha20poly1305_ietf_decrypt(
                out.as_mut_ptr(),
                null_mut(),
                null_mut(),
                ciphertext.as_ptr(),
                ciphertext.len() as u64,
                ad.as_ptr(),
                ad.len() as u64,
                n.as_ptr(),
                k.0.as_ptr(),
            )
        };

        if ret == 0 {
            Ok(())
        } else {
            Err(())
        }
    }
}

impl Cipher for Aes256Gcm {
    type Key = Sensitive<[u8; 32]>;

    fn name() -> &'static str {
        "AESGCM"
    }

    fn encrypt(k: &Self::Key, nonce: u64, ad: &[u8], plaintext: &[u8], out: &mut [u8]) {
        assert_eq!(out.len(), plaintext.len() + 16);

        let mut n = [0u8; 12];
        n[4..].copy_from_slice(&nonce.to_be_bytes());

        unsafe {
            crypto_aead_aes256gcm_encrypt(
                out.as_mut_ptr(),
                null_mut(),
                plaintext.as_ptr(),
                plaintext.len() as u64,
                ad.as_ptr(),
                ad.len() as u64,
                null(),
                n.as_ptr(),
                k.0.as_ptr(),
            );
        }
    }

    fn decrypt(
        k: &Self::Key,
        nonce: u64,
        ad: &[u8],
        ciphertext: &[u8],
        out: &mut [u8],
    ) -> Result<(), ()> {
        assert_eq!(out.len() + 16, ciphertext.len());

        let mut n = [0u8; 12];
        n[4..].copy_from_slice(&nonce.to_be_bytes());

        let ret = unsafe {
            crypto_aead_aes256gcm_decrypt(
                out.as_mut_ptr(),
                null_mut(),
                null_mut(),
                ciphertext.as_ptr(),
                ciphertext.len() as u64,
                ad.as_ptr(),
                ad.len() as u64,
                n.as_ptr(),
                k.0.as_ptr(),
            )
        };

        if ret == 0 {
            Ok(())
        } else {
            Err(())
        }
    }
}

impl Hash for Sha256 {
    type Block = [u8; 64];
    type Output = Sensitive<[u8; 32]>;

    fn name() -> &'static str {
        "SHA256"
    }

    fn input(&mut self, data: &[u8]) {
        self.state.update(data);
    }

    fn result(&mut self) -> Self::Output {
        let mut state = sha256::State::new();
        swap(&mut state, &mut self.state);
        Sensitive(state.finalize().0)
    }
}

impl Hash for Sha512 {
    type Block = [u8; 128];
    type Output = Sensitive<[u8; 64]>;

    fn name() -> &'static str {
        "SHA512"
    }

    fn input(&mut self, data: &[u8]) {
        self.state.update(data);
    }

    fn result(&mut self) -> Self::Output {
        let mut state = sha512::State::new();
        swap(&mut state, &mut self.state);
        Sensitive(state.finalize().0)
    }
}

impl Default for Blake2b {
    fn default() -> Self {
        unsafe {
            let mut b: Blake2b = uninitialized();
            crypto_generichash_init(&mut b.state, null(), 0, 64);
            b
        }
    }
}

impl Hash for Blake2b {
    type Block = [u8; 128];
    type Output = Sensitive<[u8; 64]>;

    fn name() -> &'static str {
        "BLAKE2b"
    }

    fn input(&mut self, data: &[u8]) {
        unsafe {
            crypto_generichash_update(&mut self.state, data.as_ptr(), data.len() as u64);
        }
    }

    fn result(&mut self) -> Self::Output {
        unsafe {
            let mut out: Self::Output = uninitialized();
            crypto_generichash_final(&mut self.state, out.as_mut().as_mut_ptr(), 64);
            out
        }
    }
}
<commit_msg>Use MaybeUninit instead of uninitialized<commit_after>use libsodium_sys::*;
use noise_protocol::*;
use sodiumoxide::crypto::hash::{sha256, sha512};
use sodiumoxide::crypto::scalarmult::curve25519;
use sodiumoxide::init as sodium_init;
use sodiumoxide::randombytes::randombytes_into;
use sodiumoxide::utils::memzero;
use std::mem::{swap, MaybeUninit};
use std::ptr::{null, null_mut};

/// Initialize the library. Call the `sodium_init` function.
///
/// `sodium_init()` initializes the library and should be called before any other function provided by Sodium. It is safe to call this function more than once and from different threads -- subsequent calls won't have any effects.
/// After this function returns, all of the other functions provided by Sodium will be thread-safe.
///
/// Libsodium doc: <https://libsodium.gitbook.io/doc/usage>.
pub fn init() -> Result<(), ()> {
    sodium_init()
}

#[derive(Debug)]
pub struct X25519Key(curve25519::Scalar);

impl U8Array for X25519Key {
    fn new() -> Self {
        X25519Key(curve25519::Scalar([0u8; 32]))
    }

    fn new_with(v: u8) -> Self {
        X25519Key(curve25519::Scalar([v; 32]))
    }

    fn from_slice(s: &[u8]) -> Self {
        X25519Key(curve25519::Scalar::from_slice(s).unwrap())
    }

    fn len() -> usize {
        32
    }

    fn as_slice(&self) -> &[u8] {
        &(self.0).0
    }

    fn as_mut(&mut self) -> &mut [u8] {
        &mut (self.0).0
    }
}

#[derive(Debug)]
pub struct Sensitive(A);

impl Drop for Sensitive
where
    A: U8Array,
{
    fn drop(&mut self) {
        memzero(self.0.as_mut())
    }
}

impl U8Array for Sensitive
where
    A: U8Array,
{
    fn new() -> Self {
        Sensitive(A::new())
    }

    fn new_with(v: u8) -> Self {
        Sensitive(A::new_with(v))
    }

    fn from_slice(s: &[u8]) -> Self {
        Sensitive(A::from_slice(s))
    }

    fn len() -> usize {
        A::len()
    }

    fn as_slice(&self) -> &[u8] {
        self.0.as_slice()
    }

    fn as_mut(&mut self) -> &mut [u8] {
        self.0.as_mut()
    }
}

pub enum X25519 {}

pub enum ChaCha20Poly1305 {}

/// The AES-256-GCM AEAD.
///
/// # Portability Warning
///
/// The current implementation of this construction is hardware-accelerated and requires the Intel SSSE3 extensions, as well as the `aesni` and `pclmul` instructions.
///
/// Intel Westmere processors (introduced in 2010) and newer meet the requirements.
///
/// There are no plans to support non hardware-accelerated implementations of AES-GCM. If portability is a concern, use ChaCha20-Poly1305 instead.
///
/// Before using the functions below, hardware support for AES can be checked with <Aes256Gcm::available>.
///
/// The function returns `true` if the current CPU supports the AES256-GCM implementation, and `false` if it doesn't.
///
/// The library must have been initialized with [init](init) prior to calling this function.
///
/// Libsodium doc: <https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/aes-256-gcm#limitations>.
pub enum Aes256Gcm {}

impl Aes256Gcm {
    /// Check for hardware support of AES-GCM.
    ///
    /// The function returns `true` if the current CPU supports the AES256-GCM implementation, and `false` if it doesn't.
    pub fn available() -> bool {
        unsafe { crypto_aead_aes256gcm_is_available() != 0 }
    }
}

#[derive(Default)]
pub struct Sha256 {
    state: sha256::State,
}

#[derive(Default)]
pub struct Sha512 {
    state: sha512::State,
}

#[repr(transparent)]
pub struct Blake2b {
    state: crypto_generichash_state,
}

impl DH for X25519 {
    type Key = X25519Key;
    type Pubkey = [u8; 32];
    type Output = Sensitive<[u8; 32]>;

    fn name() -> &'static str {
        "25519"
    }

    fn genkey() -> Self::Key {
        let mut k = [0u8; 32];
        randombytes_into(&mut k);
        k[0] &= 248;
        k[31] &= 127;
        k[31] |= 64;
        X25519Key(curve25519::Scalar(k))
    }

    fn pubkey(k: &Self::Key) -> Self::Pubkey {
        curve25519::scalarmult_base(&k.0).0
    }

    /// Returns `Err(())` if DH output is all-zero.
    fn dh(k: &Self::Key, pk: &Self::Pubkey) -> Result<Self::Output, ()> {
        let pk = curve25519::GroupElement(*pk);
        curve25519::scalarmult(&k.0, &pk).map(|x| Sensitive(x.0))
    }
}

impl Cipher for ChaCha20Poly1305 {
    type Key = Sensitive<[u8; 32]>;

    fn name() -> &'static str {
        "ChaChaPoly"
    }

    fn encrypt(k: &Self::Key, nonce: u64, ad: &[u8], plaintext: &[u8], out: &mut [u8]) {
        assert_eq!(out.len(), plaintext.len() + 16);

        let mut n = [0u8; 12];
        n[4..].copy_from_slice(&nonce.to_le_bytes());

        unsafe {
            crypto_aead_chacha20poly1305_ietf_encrypt(
                out.as_mut_ptr(),
                null_mut(),
                plaintext.as_ptr(),
                plaintext.len() as u64,
                ad.as_ptr(),
                ad.len() as u64,
                null(),
                n.as_ptr(),
                k.0.as_ptr(),
            );
        }
    }

    fn decrypt(
        k: &Self::Key,
        nonce: u64,
        ad: &[u8],
        ciphertext: &[u8],
        out: &mut [u8],
    ) -> Result<(), ()> {
        assert_eq!(out.len() + 16, ciphertext.len());

        let mut n = [0u8; 12];
        n[4..].copy_from_slice(&nonce.to_le_bytes());

        let ret = unsafe {
            crypto_aead_chacha20poly1305_ietf_decrypt(
                out.as_mut_ptr(),
                null_mut(),
                null_mut(),
                ciphertext.as_ptr(),
                ciphertext.len() as u64,
                ad.as_ptr(),
                ad.len() as u64,
                n.as_ptr(),
                k.0.as_ptr(),
            )
        };

        if ret == 0 {
            Ok(())
        } else {
            Err(())
        }
    }
}

impl Cipher for Aes256Gcm {
    type Key = Sensitive<[u8; 32]>;

    fn name() -> &'static str {
        "AESGCM"
    }

    fn encrypt(k: &Self::Key, nonce: u64, ad: &[u8], plaintext: &[u8], out: &mut [u8]) {
        assert_eq!(out.len(), plaintext.len() + 16);

        let mut n = [0u8; 12];
        n[4..].copy_from_slice(&nonce.to_be_bytes());

        unsafe {
            crypto_aead_aes256gcm_encrypt(
                out.as_mut_ptr(),
                null_mut(),
                plaintext.as_ptr(),
                plaintext.len() as u64,
                ad.as_ptr(),
                ad.len() as u64,
                null(),
                n.as_ptr(),
                k.0.as_ptr(),
            );
        }
    }

    fn decrypt(
        k: &Self::Key,
        nonce: u64,
        ad: &[u8],
        ciphertext: &[u8],
        out: &mut [u8],
    ) -> Result<(), ()> {
        assert_eq!(out.len() + 16, ciphertext.len());

        let mut n = [0u8; 12];
        n[4..].copy_from_slice(&nonce.to_be_bytes());

        let ret = unsafe {
            crypto_aead_aes256gcm_decrypt(
                out.as_mut_ptr(),
                null_mut(),
                null_mut(),
                ciphertext.as_ptr(),
                ciphertext.len() as u64,
                ad.as_ptr(),
                ad.len() as u64,
                n.as_ptr(),
                k.0.as_ptr(),
            )
        };

        if ret == 0 {
            Ok(())
        } else {
            Err(())
        }
    }
}

impl Hash for Sha256 {
    type Block = [u8; 64];
    type Output = Sensitive<[u8; 32]>;

    fn name() -> &'static str {
        "SHA256"
    }

    fn input(&mut self, data: &[u8]) {
        self.state.update(data);
    }

    fn result(&mut self) -> Self::Output {
        let mut state = sha256::State::new();
        swap(&mut state, &mut self.state);
        Sensitive(state.finalize().0)
    }
}

impl Hash for Sha512 {
    type Block = [u8; 128];
    type Output = Sensitive<[u8; 64]>;

    fn name() -> &'static str {
        "SHA512"
    }

    fn input(&mut self, data: &[u8]) {
        self.state.update(data);
    }

    fn result(&mut self) -> Self::Output {
        let mut state = sha512::State::new();
        swap(&mut state, &mut self.state);
        Sensitive(state.finalize().0)
    }
}

impl Default for Blake2b {
    fn default() -> Self {
        unsafe {
            let mut b: MaybeUninit<crypto_generichash_state> = MaybeUninit::uninit();
            crypto_generichash_init(b.as_mut_ptr(), null(), 0, 64);
            Blake2b {
                state: b.assume_init(),
            }
        }
    }
}

impl Hash for Blake2b {
    type Block = [u8; 128];
    type Output = Sensitive<[u8; 64]>;

    fn name() -> &'static str {
        "BLAKE2b"
    }

    fn input(&mut self, data: &[u8]) {
        unsafe {
            crypto_generichash_update(&mut self.state, data.as_ptr(), data.len() as u64);
        }
    }

    fn result(&mut self) -> Self::Output {
        unsafe {
            let mut out: MaybeUninit<[u8; 64]> = MaybeUninit::uninit();
            crypto_generichash_final(&mut self.state, out.as_mut_ptr() as *mut u8, 64);
            Sensitive(out.assume_init())
        }
    }
}
<|endoftext|>


<commit_before>//! Support for sending and receiving data link layer packets using libpcap.
//! Also has support for reading pcap files.
extern crate pcap;

use std::marker::{Send, Sync};
use std::io;
use std::iter::repeat;
use self::pcap::{Active, Activated};
use datalink::{self, NetworkInterface};
use datalink::{EthernetDataLinkChannelIterator, EthernetDataLinkReceiver, EthernetDataLinkSender};
use datalink::Channel::Ethernet;
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::path::Path;

/// Configuration for the pcap datalink backend
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The size of buffer to use when reading packets. Defaults to 4096
    pub read_buffer_size: usize,

    /// The read timeout. Defaults to None.
    pub read_timeout: Option<Duration>,
}

impl<'a> From<&'a datalink::Config> for Config {
    fn from(config: &datalink::Config) -> Config {
        Config{
            read_buffer_size: config.read_buffer_size,
            read_timeout: config.read_timeout,
        }
    }
}

impl Default for Config {
    fn default() -> Config {
        Config{
            read_buffer_size: 4096,
            read_timeout: None,
        }
    }
}

/// Create a datalink channel from the provided pcap device
#[inline]
pub fn channel(network_interface: &NetworkInterface,
               config: Config) -> io::Result<datalink::Channel> {
    let cap = match pcap::Capture::from_device(&*network_interface.name) {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    }.buffer_size(config.read_buffer_size as i32);
    let cap = match config.read_timeout {
        Some(to) => cap.timeout(
            (to.as_secs() * 1000 + (to.subsec_nanos() / 1000) as u64) as i32
        ),
        None => cap
    };
    let cap = match cap.open() {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    };
    let cap = Arc::new(Mutex::new(cap));
    Ok(Ethernet(
        Box::new(DataLinkSenderImpl {
            capture: cap.clone(),
        }),
        Box::new(DataLinkReceiverImpl {
            capture: cap.clone(),
            read_buffer: repeat(0u8).take(config.read_buffer_size).collect(),
        })
    ))
}

/// Create a datalink channel from a pcap file
#[inline]
pub fn from_file<P: AsRef<Path>>(path: P, config: Config) -> io::Result<datalink::Channel> {
    let cap = match pcap::Capture::from_file(path) {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    };
    let cap = Arc::new(Mutex::new(cap));
    Ok(Ethernet(
        Box::new(InvalidDataLinkSenderImpl {}),
        Box::new(DataLinkReceiverImpl {
            capture: cap.clone(),
            read_buffer: repeat(0u8).take(config.read_buffer_size).collect(),
        })
    ))
}

struct DataLinkSenderImpl {
    capture: Arc<Mutex<pcap::Capture<Active>>>,
}

impl EthernetDataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
                      -> Option<io::Result<()>> {
        for _ in 0..num_packets {
            let mut data = vec![0; packet_size];
            {
                let eh = MutableEthernetPacket::new(&mut data).unwrap();
                func(eh);
            }
            let mut cap = self.capture.lock().unwrap();
            if let Err(e) = cap.sendpacket(&data) {
                return Some(Err(io::Error::new(io::ErrorKind::Other, e)))
            }
        }
        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>) -> Option<io::Result<()>> {
        let mut cap = self.capture.lock().unwrap();
        Some(match cap.sendpacket(packet.packet()) {
            Ok(()) => Ok(()),
            Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
        })
    }
}

struct InvalidDataLinkSenderImpl {}

impl EthernetDataLinkSender for InvalidDataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      _num_packets: usize,
                      _packet_size: usize,
                      _func: &mut FnMut(MutableEthernetPacket))
                      -> Option<io::Result<()>> {
        None
    }

    #[inline]
    fn send_to(&mut self,
               _packet: &EthernetPacket,
               _dst: Option<NetworkInterface>) -> Option<io::Result<()>> {
        None
    }
}

struct DataLinkReceiverImpl<T: Activated + Send + Sync> {
    capture: Arc<Mutex<pcap::Capture<T>>>,
    read_buffer: Vec<u8>,
}

impl <T: Activated + Send + Sync> EthernetDataLinkReceiver for DataLinkReceiverImpl<T> {
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(DataLinkChannelIteratorImpl { pc: self })
    }
}

struct DataLinkChannelIteratorImpl<'a, T: Activated + Send + Sync + 'a> {
    pc: &'a mut DataLinkReceiverImpl<T>,
}

impl<'a, T: Activated + Send + Sync> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a, T> {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        let mut cap = self.pc.capture.lock().unwrap();
        match cap.next() {
            Ok(pkt) => {
                self.pc.read_buffer.truncate(0);
                self.pc.read_buffer.extend(pkt.data);
            },
            Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
        };
        Ok(EthernetPacket::new(&self.pc.read_buffer).unwrap())
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    if let Ok(devices) = pcap::Device::list() {
        devices.iter().enumerate().map(|(i, dev)| {
            NetworkInterface {
                name: dev.name.clone(),
                index: i as u32,
                mac: None,
                ips: None,
                flags: 0,
            }
        }).collect()
    } else {
        vec![]
    }
}
<commit_msg>Correctly initialize 'ips' in pcap datalink.<commit_after>//! Support for sending and receiving data link layer packets using libpcap.
//! Also has support for reading pcap files.
extern crate pcap;

use std::marker::{Send, Sync};
use std::io;
use std::iter::repeat;
use self::pcap::{Active, Activated};
use datalink::{self, NetworkInterface};
use datalink::{EthernetDataLinkChannelIterator, EthernetDataLinkReceiver, EthernetDataLinkSender};
use datalink::Channel::Ethernet;
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::path::Path;

/// Configuration for the pcap datalink backend
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The size of buffer to use when reading packets. Defaults to 4096
    pub read_buffer_size: usize,

    /// The read timeout. Defaults to None.
    pub read_timeout: Option<Duration>,
}

impl<'a> From<&'a datalink::Config> for Config {
    fn from(config: &datalink::Config) -> Config {
        Config{
            read_buffer_size: config.read_buffer_size,
            read_timeout: config.read_timeout,
        }
    }
}

impl Default for Config {
    fn default() -> Config {
        Config{
            read_buffer_size: 4096,
            read_timeout: None,
        }
    }
}

/// Create a datalink channel from the provided pcap device
#[inline]
pub fn channel(network_interface: &NetworkInterface,
               config: Config) -> io::Result<datalink::Channel> {
    let cap = match pcap::Capture::from_device(&*network_interface.name) {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    }.buffer_size(config.read_buffer_size as i32);
    let cap = match config.read_timeout {
        Some(to) => cap.timeout(
            (to.as_secs() * 1000 + (to.subsec_nanos() / 1000) as u64) as i32
        ),
        None => cap
    };
    let cap = match cap.open() {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    };
    let cap = Arc::new(Mutex::new(cap));
    Ok(Ethernet(
        Box::new(DataLinkSenderImpl {
            capture: cap.clone(),
        }),
        Box::new(DataLinkReceiverImpl {
            capture: cap.clone(),
            read_buffer: repeat(0u8).take(config.read_buffer_size).collect(),
        })
    ))
}

/// Create a datalink channel from a pcap file
#[inline]
pub fn from_file<P: AsRef<Path>>(path: P, config: Config) -> io::Result<datalink::Channel> {
    let cap = match pcap::Capture::from_file(path) {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    };
    let cap = Arc::new(Mutex::new(cap));
    Ok(Ethernet(
        Box::new(InvalidDataLinkSenderImpl {}),
        Box::new(DataLinkReceiverImpl {
            capture: cap.clone(),
            read_buffer: repeat(0u8).take(config.read_buffer_size).collect(),
        })
    ))
}

struct DataLinkSenderImpl {
    capture: Arc<Mutex<pcap::Capture<Active>>>,
}

impl EthernetDataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
                      -> Option<io::Result<()>> {
        for _ in 0..num_packets {
            let mut data = vec![0; packet_size];
            {
                let eh = MutableEthernetPacket::new(&mut data).unwrap();
                func(eh);
            }
            let mut cap = self.capture.lock().unwrap();
            if let Err(e) = cap.sendpacket(&data) {
                return Some(Err(io::Error::new(io::ErrorKind::Other, e)))
            }
        }
        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>) -> Option<io::Result<()>> {
        let mut cap = self.capture.lock().unwrap();
        Some(match cap.sendpacket(packet.packet()) {
            Ok(()) => Ok(()),
            Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
        })
    }
}

struct InvalidDataLinkSenderImpl {}

impl EthernetDataLinkSender for InvalidDataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      _num_packets: usize,
                      _packet_size: usize,
                      _func: &mut FnMut(MutableEthernetPacket))
                      -> Option<io::Result<()>> {
        None
    }

    #[inline]
    fn send_to(&mut self,
               _packet: &EthernetPacket,
               _dst: Option<NetworkInterface>) -> Option<io::Result<()>> {
        None
    }
}

struct DataLinkReceiverImpl<T: Activated + Send + Sync> {
    capture: Arc<Mutex<pcap::Capture<T>>>,
    read_buffer: Vec<u8>,
}

impl <T: Activated + Send + Sync> EthernetDataLinkReceiver for DataLinkReceiverImpl<T> {
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(DataLinkChannelIteratorImpl { pc: self })
    }
}

struct DataLinkChannelIteratorImpl<'a, T: Activated + Send + Sync + 'a> {
    pc: &'a mut DataLinkReceiverImpl<T>,
}

impl<'a, T: Activated + Send + Sync> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a, T> {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        let mut cap = self.pc.capture.lock().unwrap();
        match cap.next() {
            Ok(pkt) => {
                self.pc.read_buffer.truncate(0);
                self.pc.read_buffer.extend(pkt.data);
            },
            Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
        };
        Ok(EthernetPacket::new(&self.pc.read_buffer).unwrap())
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    if let Ok(devices) = pcap::Device::list() {
        devices.iter().enumerate().map(|(i, dev)| {
            NetworkInterface {
                name: dev.name.clone(),
                index: i as u32,
                mac: None,
                ips: Vec::new(),
                flags: 0,
            }
        }).collect()
    } else {
        vec![]
    }
}
<|endoftext|>


<commit_before>//! A simple delay filter.
//!
//! The delay filter plays back delayed copies of its input. The first delay is
//! played at full amplitude, and is then decayed linearly by the feedback
//! multiplier.
//!
//! The output is mixed with the raw input using the wetness percentage.

use types::{SAMPLE_RATE, AudioDevice, Sample, Time};
use utils::ringbuffer::RingBuffer;

pub struct Delay {
    num_channels: usize,
    delay_buffers: Vec<RingBuffer<Sample>>,
    feedback: f32,
    wetness: f32
}

impl Delay {
    /// Creates a new Delay object.
    ///
    /// * `delay`: the time to delay the input, in seconds
    /// * `feedback`: how much of our delayed signal to feed back into the next
    ///               delay; should be between 0.0 and 1.0.
    /// * `wetness`: how much of our input signal to mix into the delayed signal
    ///              in the output; should be between 0.0 and 1.0.
    pub fn new(delay: f32, feedback: f32, wetness: f32,
               num_channels: usize) -> Self {
        // Create the delay buffers, starting with silence
        let delay_samples = (delay * SAMPLE_RATE as f32) as usize;
        let init = vec![0.0; delay_samples];

        Delay {
            num_channels: num_channels,
            delay_buffers: vec![RingBuffer::from(&init[..]); num_channels],
            feedback: feedback,
            wetness: wetness
        }
    }
}

impl AudioDevice for Delay {
    fn num_inputs(&self) -> usize {
        self.num_channels
    }

    fn num_outputs(&self) -> usize {
        self.num_channels
    }

    fn tick(&mut self, t: Time, inputs: &[Sample], outputs: &mut[Sample]) {
        for (i,s) in inputs.iter().enumerate() {
            // Get our delayed signal and feed it back with our input
            let delayed = self.delay_buffers[i][t];
            self.delay_buffers[i].push(s + self.feedback*delayed);

            // Mix our wet signal with the input
            outputs[i] = self.wetness*delayed + (1.0-self.wetness)*s;
        }
    }
}
<commit_msg>Add Message handling to delay<commit_after>//! A simple delay filter.
//!
//! The delay filter plays back delayed copies of its input. The first delay is
//! played at full amplitude, and is then decayed linearly by the feedback
//! multiplier.
//!
//! The output is mixed with the raw input using the wetness percentage.

use types::{SAMPLE_RATE, AudioDevice, Sample, Time};
use utils::ringbuffer::RingBuffer;

/// Defines the messages that the Delay supports
#[derive(Clone, Copy, Debug)]
pub enum Message {
    SetDelay(f32),
    SetFeedback(f32),
    SetWetness(f32)
}
pub use self::Message::*;

pub struct Delay {
    num_channels: usize,
    delay_buffers: Vec<RingBuffer<Sample>>,
    feedback: f32,
    wetness: f32
}

impl Delay {
    /// Creates a new Delay object.
    ///
    /// * `delay`: the time to delay the input, in seconds
    /// * `feedback`: how much of our delayed signal to feed back into the next
    ///               delay; should be between 0.0 and 1.0.
    /// * `wetness`: how much of our input signal to mix into the delayed signal
    ///              in the output; should be between 0.0 and 1.0.
    pub fn new(delay: f32, feedback: f32, wetness: f32,
               num_channels: usize) -> Self {
        // Create the delay buffers, starting with silence
        let delay_samples = (delay * SAMPLE_RATE as f32) as usize;
        let init = vec![0.0; delay_samples];

        Delay {
            num_channels: num_channels,
            delay_buffers: vec![RingBuffer::from(&init[..]); num_channels],
            feedback: feedback,
            wetness: wetness
        }
    }

    /// Applies the message to our Delay
    pub fn handle_message(&mut self, msg: Message) {
        match msg {
            SetDelay(delay) => {
                let delay_samples = (delay * SAMPLE_RATE as f32) as usize;
                for rb in self.delay_buffers.iter_mut() {
                    rb.resize(delay_samples);
                }
            },
            SetFeedback(feedback) => {
                self.feedback = feedback;
            },
            SetWetness(wetness) => {
                self.wetness = wetness;
            }
        }
    }
}

impl AudioDevice for Delay {
    fn num_inputs(&self) -> usize {
        self.num_channels
    }

    fn num_outputs(&self) -> usize {
        self.num_channels
    }

    fn tick(&mut self, t: Time, inputs: &[Sample], outputs: &mut[Sample]) {
        for (i,s) in inputs.iter().enumerate() {
            // Get our delayed signal and feed it back with our input
            let delayed = self.delay_buffers[i][t];
            self.delay_buffers[i].push(s + self.feedback*delayed);

            // Mix our wet signal with the input
            outputs[i] = self.wetness*delayed + (1.0-self.wetness)*s;
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::collections::VecDeque;
use std::iter::FromIterator;

use lexicon::Lexicon;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Orientation {
    Across,
    Down
}

impl Orientation {
    pub fn reverse(&self) -> Self {
        match *self {
            Orientation::Across => Orientation::Down,
            Orientation::Down => Orientation::Across
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Locale {
    row: usize,
    col: usize
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct WordspanAddress {
    start_row: usize,
    start_col: usize,
    orientation: Orientation,
    length: usize
}

impl WordspanAddress {
    pub fn new(start_row: usize, start_col: usize,
               orientation: Orientation, length: usize) -> Self {
        WordspanAddress {
            start_row: start_row,
            start_col: start_col,
            orientation: orientation,
            length: length
        }
    }

    pub fn oriented_new(start_this: usize, start_cross: usize,
                        orientation: Orientation, length: usize) -> Self {
        match orientation {
            Orientation::Across => WordspanAddress::new(
                start_this, start_cross, orientation, length),
            Orientation::Down => WordspanAddress::new(
                start_cross, start_this, orientation, length)
        }
    }

    pub fn encompassed_locales(&self) -> Vec<Locale> {
        (0..self.length).map(|offset| {
            match self.orientation {
                Orientation::Across => Locale {
                    row: self.start_row,
                    col: self.start_col + offset
                },
                Orientation::Down => Locale {
                    row: self.start_row + offset,
                    col: self.start_col
                }
            }
        }).collect()
    }
}

pub const BARRIER: char = '█';

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CrossRequirement {
    length: usize,
    prefix: Vec<char>
}

impl CrossRequirement {
    pub fn new(length: usize, prefix: Vec<char>) -> Self {
        CrossRequirement {
            length: length,
            prefix: prefix,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Puzzle {
    rows: usize,
    cols: usize,
    backing: Vec<char>
}

impl Puzzle {
    pub fn read(&self, row_index: usize, col_index: usize) -> char {
        self.backing[self.cols*row_index + col_index]
    }

    pub fn oriented_read(&self, orientation: Orientation,
                         this: usize, cross: usize) -> char {
        match orientation {
            Orientation::Across => self.read(this, cross),
            Orientation::Down => self.read(cross, this)
        }
    }

    pub fn write(&mut self, row_index: usize, col_index: usize,
                 letter: char) {
        self.backing[self.cols*row_index + col_index] = letter;
    }

    // XXX: returning a Vec<_> implies an allocation, but we can't return a
    // slice because the Down case isn't contiguous. Can we return a
    // Cow<[char]>? Profile and decide later
    pub fn read_wordspan(&self, address: WordspanAddress) -> Vec<char> {
        let start_square = self.cols*address.start_row + address.start_col;
        match address.orientation {
            Orientation::Across => {
                self.backing[start_square..start_square+address.length].to_vec()
            },
            Orientation::Down => {
                (0..address.length).map(|r| {
                    self.backing[start_square + self.cols*r]
                }).collect()
            }
        }
    }

    pub fn write_wordspan(&mut self, address: WordspanAddress, word: Vec<char>) {
        let start_square = self.cols*address.start_row + address.start_col;
        let mut offset = 0;
        for character in word {
            self.backing[start_square + offset] = character;
            offset += match address.orientation {
                Orientation::Across => 1,
                Orientation::Down => self.cols
            }
        }
    }

    pub fn oriented_wordspan_addresses(&self, orientation: Orientation)
                                       -> Vec<WordspanAddress> {
        let mut addresses = Vec::new();
        let (this_dimension, cross_dimension) = match orientation {
            Orientation::Across => (self.rows, self.cols),
            Orientation::Down => (self.cols, self.rows)
        };
        for beam in 0..this_dimension {
            let mut open_word_from: Option<usize> = None;
            for crossbeam in 0..cross_dimension {
                match open_word_from {
                    None => {
                        if self.oriented_read(orientation,
                                              beam, crossbeam) == BARRIER {
                            continue;
                        } else {
                            open_word_from = Some(crossbeam);
                        }
                    },
                    Some(open_from) => {
                        if self.oriented_read(orientation,
                                              beam, crossbeam) == BARRIER {
                            let address = WordspanAddress::oriented_new(
                                beam, open_from, orientation,
                                crossbeam-open_from
                            );
                            addresses.push(address);
                            open_word_from = None;
                        } else {
                            continue;
                        }
                    }
                }
            }
            // close off word closed by edge of puzzle rather than barrier
            if let Some(open_from) = open_word_from {
                let address = WordspanAddress::oriented_new(
                    beam, open_from, orientation,
                    cross_dimension-open_from
                );
                addresses.push(address);
            }
        }
        addresses
    }

    pub fn wordspan_addresses(&self) -> Vec<WordspanAddress> {
        let mut addresses = self.oriented_wordspan_addresses(Orientation::Across);
        addresses.extend(self.oriented_wordspan_addresses(Orientation::Down));
        addresses
    }

    pub fn is_solved(&self, lexicon: &Lexicon) -> bool {
        for address in self.wordspan_addresses() {
            let word = self.read_wordspan(address);
            if !lexicon.contains(&word) {
                return false;
            }
        }
        true
    }

    pub fn gather_cross_requirements(&self, address: WordspanAddress)
                                     -> Vec<CrossRequirement> {
        let mut cross_requirements = Vec::new();
        let mut our_locales = VecDeque::from_iter(
            address.encompassed_locales().into_iter());
        for cross_address in self.oriented_wordspan_addresses(
                address.orientation.reverse()) {
            if cross_address.encompassed_locales().contains(&our_locales[0]) {
                our_locales.pop_front();
                let requirement = CrossRequirement {
                    length: cross_address.length,
                    prefix: self.read_wordspan(cross_address).into_iter()
                        .take_while(|c| *c != ' ').collect()
                };
                cross_requirements.push(requirement);
            }
        }
        cross_requirements
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use lexicon::Lexicon;

    fn test_puzzle_i() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 5,
            backing: vec![
                'W', 'R', 'I', 'T', 'E',
                'A', 'A', 'R', 'O', 'N',
                'G', 'I', 'A', 'N', 'T',
                'E', 'S', 'T', 'E', 'R',
                'R', 'E', 'E', 'D', 'Y',
            ]
        }
    }

    fn test_puzzle_ii() -> Puzzle {
        Puzzle {
            rows: 7,
            cols: 11,
            backing: vec![
                'S', 'W', 'I', 'F', 'T', '█', 'S', 'T', 'A', 'C', 'K',
                'L', 'A', 'M', 'A', 'S', '█', 'L', 'A', 'M', 'A', 'R',
                'A', 'L', 'A', 'N', '█', 'L', 'E', 'G', 'A', 'T', 'O',
                'B', 'E', 'G', '█', 'L', 'A', 'D', '█', 'D', 'E', 'C',
                '█', 'S', 'E', 'L', 'I', 'M', '█', 'F', 'E', 'R', '█',
                '█', 'A', 'R', 'E', 'S', '█', 'P', 'I', 'U', 'S', '█',
                '█', '█', 'Y', 'I', 'P', '█', 'L', 'E', 'S', '█', '█',
            ]
        }
    }

    fn test_puzzle_iii() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 4,
            backing: vec![
                'Q', 'U', 'I', 'Z',
                'U', 'N', 'D', 'O',
                'A', 'I', 'L', 'S',
                ' ', ' ', ' ', ' ', // ITEM
                ' ', ' ', ' ', ' ', // LEDA (in case you were wondering)
            ],
        }
    }

    #[test]
    fn concerning_read_wordspan_across() {
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        assert_eq!(test_puzzle_i().read_wordspan(write_address),
                   charvec![WRITE]);
    }

    #[test]
    fn concerning_read_wordspan_down() {
        let raise_address = WordspanAddress::new(0, 1, Orientation::Down, 5);
        assert_eq!(test_puzzle_i().read_wordspan(raise_address),
                   charvec![RAISE]);
    }

    #[test]
    fn concerning_write_wordspan_across() {
        let mut puzzle = test_puzzle_i();
        // in more ways than one
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        puzzle.write_wordspan(write_address, charvec![PLATE]);
        assert_eq!(puzzle.read_wordspan(write_address),
                   charvec![PLATE]);
    }

    #[test]
    fn concerning_write_wordspan_down() {
        let mut puzzle = test_puzzle_i();
        let entry_address = WordspanAddress::new(0, 4, Orientation::Down, 5);
        puzzle.write_wordspan(entry_address, charvec![FAITH]);
        assert_eq!(puzzle.read_wordspan(entry_address),
                   charvec![FAITH]);
    }

    #[test]
    fn concerning_wordspan_addresses_across() {
        let puzzle = test_puzzle_ii();
        assert_eq!(
            &[WordspanAddress::new(0, 0, Orientation::Across, 5),
              WordspanAddress::new(0, 6, Orientation::Across, 5),
              WordspanAddress::new(1, 0, Orientation::Across, 5),
              WordspanAddress::new(1, 6, Orientation::Across, 5),
              WordspanAddress::new(2, 0, Orientation::Across, 4),
              WordspanAddress::new(2, 5, Orientation::Across, 6)],
            &puzzle.oriented_wordspan_addresses(Orientation::Across)[..6]
        );
    }

    #[test]
    fn concerning_wordspan_addresses_down() {
        let puzzle = test_puzzle_ii();
        assert_eq!(
            &[WordspanAddress::new(0, 0, Orientation::Down, 4),
              WordspanAddress::new(0, 1, Orientation::Down, 6),
              WordspanAddress::new(0, 2, Orientation::Down, 7),
              WordspanAddress::new(0, 3, Orientation::Down, 3),
              WordspanAddress::new(4, 3, Orientation::Down, 3),
              WordspanAddress::new(0, 4, Orientation::Down, 2)],
            &puzzle.oriented_wordspan_addresses(Orientation::Down)[..6]
        );
    }

    #[test]
    fn concerning_is_solved() {
        let lexicon = Lexicon::build(7);
        let puzzles = vec![test_puzzle_i(), test_puzzle_ii()];
        for mut puzzle in puzzles {
            assert!(puzzle.is_solved(&lexicon));
            puzzle.write(0, 0, 'Q');
            assert!(!puzzle.is_solved(&lexicon));
        }
    }

    #[test]
    fn concerning_gathering_cross_requirements() {
        assert_eq!(
            vec![CrossRequirement::new(5, charvec![QUA]),
                 CrossRequirement::new(5, charvec![UNI]),
                 CrossRequirement::new(5, charvec![IDL]),
                 CrossRequirement::new(5, charvec![ZOS])],
            test_puzzle_iii()
                .gather_cross_requirements(
                    WordspanAddress::new(3, 0, Orientation::Across, 4))
        );
    }

}
<commit_msg>is full<commit_after>#![allow(dead_code)]

use std::collections::VecDeque;
use std::iter::FromIterator;

use lexicon::Lexicon;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Orientation {
    Across,
    Down
}

impl Orientation {
    pub fn reverse(&self) -> Self {
        match *self {
            Orientation::Across => Orientation::Down,
            Orientation::Down => Orientation::Across
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Locale {
    row: usize,
    col: usize
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct WordspanAddress {
    start_row: usize,
    start_col: usize,
    orientation: Orientation,
    length: usize
}

impl WordspanAddress {
    pub fn new(start_row: usize, start_col: usize,
               orientation: Orientation, length: usize) -> Self {
        WordspanAddress {
            start_row: start_row,
            start_col: start_col,
            orientation: orientation,
            length: length
        }
    }

    pub fn oriented_new(start_this: usize, start_cross: usize,
                        orientation: Orientation, length: usize) -> Self {
        match orientation {
            Orientation::Across => WordspanAddress::new(
                start_this, start_cross, orientation, length),
            Orientation::Down => WordspanAddress::new(
                start_cross, start_this, orientation, length)
        }
    }

    pub fn encompassed_locales(&self) -> Vec<Locale> {
        (0..self.length).map(|offset| {
            match self.orientation {
                Orientation::Across => Locale {
                    row: self.start_row,
                    col: self.start_col + offset
                },
                Orientation::Down => Locale {
                    row: self.start_row + offset,
                    col: self.start_col
                }
            }
        }).collect()
    }
}

pub const BARRIER: char = '█';

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CrossRequirement {
    length: usize,
    prefix: Vec<char>
}

impl CrossRequirement {
    pub fn new(length: usize, prefix: Vec<char>) -> Self {
        CrossRequirement {
            length: length,
            prefix: prefix,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Puzzle {
    rows: usize,
    cols: usize,
    backing: Vec<char>
}

impl Puzzle {
    pub fn read(&self, row_index: usize, col_index: usize) -> char {
        self.backing[self.cols*row_index + col_index]
    }

    pub fn oriented_read(&self, orientation: Orientation,
                         this: usize, cross: usize) -> char {
        match orientation {
            Orientation::Across => self.read(this, cross),
            Orientation::Down => self.read(cross, this)
        }
    }

    pub fn write(&mut self, row_index: usize, col_index: usize,
                 letter: char) {
        self.backing[self.cols*row_index + col_index] = letter;
    }

    // XXX: returning a Vec<_> implies an allocation, but we can't return a
    // slice because the Down case isn't contiguous. Can we return a
    // Cow<[char]>? Profile and decide later
    pub fn read_wordspan(&self, address: WordspanAddress) -> Vec<char> {
        let start_square = self.cols*address.start_row + address.start_col;
        match address.orientation {
            Orientation::Across => {
                self.backing[start_square..start_square+address.length].to_vec()
            },
            Orientation::Down => {
                (0..address.length).map(|r| {
                    self.backing[start_square + self.cols*r]
                }).collect()
            }
        }
    }

    pub fn write_wordspan(&mut self, address: WordspanAddress, word: Vec<char>) {
        let start_square = self.cols*address.start_row + address.start_col;
        let mut offset = 0;
        for character in word {
            self.backing[start_square + offset] = character;
            offset += match address.orientation {
                Orientation::Across => 1,
                Orientation::Down => self.cols
            }
        }
    }

    pub fn oriented_wordspan_addresses(&self, orientation: Orientation)
                                       -> Vec<WordspanAddress> {
        let mut addresses = Vec::new();
        let (this_dimension, cross_dimension) = match orientation {
            Orientation::Across => (self.rows, self.cols),
            Orientation::Down => (self.cols, self.rows)
        };
        for beam in 0..this_dimension {
            let mut open_word_from: Option<usize> = None;
            for crossbeam in 0..cross_dimension {
                match open_word_from {
                    None => {
                        if self.oriented_read(orientation,
                                              beam, crossbeam) == BARRIER {
                            continue;
                        } else {
                            open_word_from = Some(crossbeam);
                        }
                    },
                    Some(open_from) => {
                        if self.oriented_read(orientation,
                                              beam, crossbeam) == BARRIER {
                            let address = WordspanAddress::oriented_new(
                                beam, open_from, orientation,
                                crossbeam-open_from
                            );
                            addresses.push(address);
                            open_word_from = None;
                        } else {
                            continue;
                        }
                    }
                }
            }
            // close off word closed by edge of puzzle rather than barrier
            if let Some(open_from) = open_word_from {
                let address = WordspanAddress::oriented_new(
                    beam, open_from, orientation,
                    cross_dimension-open_from
                );
                addresses.push(address);
            }
        }
        addresses
    }

    pub fn wordspan_addresses(&self) -> Vec<WordspanAddress> {
        let mut addresses = self.oriented_wordspan_addresses(Orientation::Across);
        addresses.extend(self.oriented_wordspan_addresses(Orientation::Down));
        addresses
    }

    pub fn is_solved(&self, lexicon: &Lexicon) -> bool {
        for address in self.wordspan_addresses() {
            let word = self.read_wordspan(address);
            if !lexicon.contains(&word) {
                return false;
            }
        }
        true
    }

    pub fn gather_cross_requirements(&self, address: WordspanAddress)
                                     -> Vec<CrossRequirement> {
        let mut cross_requirements = Vec::new();
        let mut our_locales = VecDeque::from_iter(
            address.encompassed_locales().into_iter());
        for cross_address in self.oriented_wordspan_addresses(
                address.orientation.reverse()) {
            if cross_address.encompassed_locales().contains(&our_locales[0]) {
                our_locales.pop_front();
                let requirement = CrossRequirement {
                    length: cross_address.length,
                    prefix: self.read_wordspan(cross_address).into_iter()
                        .take_while(|c| *c != ' ').collect()
                };
                cross_requirements.push(requirement);
            }
        }
        cross_requirements
    }

    pub fn is_full(&self) -> bool {
        self.backing.iter().all(|c| *c != ' ')
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use lexicon::Lexicon;

    fn test_puzzle_i() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 5,
            backing: vec![
                'W', 'R', 'I', 'T', 'E',
                'A', 'A', 'R', 'O', 'N',
                'G', 'I', 'A', 'N', 'T',
                'E', 'S', 'T', 'E', 'R',
                'R', 'E', 'E', 'D', 'Y',
            ]
        }
    }

    fn test_puzzle_ii() -> Puzzle {
        Puzzle {
            rows: 7,
            cols: 11,
            backing: vec![
                'S', 'W', 'I', 'F', 'T', '█', 'S', 'T', 'A', 'C', 'K',
                'L', 'A', 'M', 'A', 'S', '█', 'L', 'A', 'M', 'A', 'R',
                'A', 'L', 'A', 'N', '█', 'L', 'E', 'G', 'A', 'T', 'O',
                'B', 'E', 'G', '█', 'L', 'A', 'D', '█', 'D', 'E', 'C',
                '█', 'S', 'E', 'L', 'I', 'M', '█', 'F', 'E', 'R', '█',
                '█', 'A', 'R', 'E', 'S', '█', 'P', 'I', 'U', 'S', '█',
                '█', '█', 'Y', 'I', 'P', '█', 'L', 'E', 'S', '█', '█',
            ]
        }
    }

    fn test_puzzle_iii() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 4,
            backing: vec![
                'Q', 'U', 'I', 'Z',
                'U', 'N', 'D', 'O',
                'A', 'I', 'L', 'S',
                ' ', ' ', ' ', ' ', // ITEM
                ' ', ' ', ' ', ' ', // LEDA (in case you were wondering)
            ],
        }
    }

    #[test]
    fn concerning_read_wordspan_across() {
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        assert_eq!(test_puzzle_i().read_wordspan(write_address),
                   charvec![WRITE]);
    }

    #[test]
    fn concerning_read_wordspan_down() {
        let raise_address = WordspanAddress::new(0, 1, Orientation::Down, 5);
        assert_eq!(test_puzzle_i().read_wordspan(raise_address),
                   charvec![RAISE]);
    }

    #[test]
    fn concerning_write_wordspan_across() {
        let mut puzzle = test_puzzle_i();
        // in more ways than one
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        puzzle.write_wordspan(write_address, charvec![PLATE]);
        assert_eq!(puzzle.read_wordspan(write_address),
                   charvec![PLATE]);
    }

    #[test]
    fn concerning_write_wordspan_down() {
        let mut puzzle = test_puzzle_i();
        let entry_address = WordspanAddress::new(0, 4, Orientation::Down, 5);
        puzzle.write_wordspan(entry_address, charvec![FAITH]);
        assert_eq!(puzzle.read_wordspan(entry_address),
                   charvec![FAITH]);
    }

    #[test]
    fn concerning_wordspan_addresses_across() {
        let puzzle = test_puzzle_ii();
        assert_eq!(
            &[WordspanAddress::new(0, 0, Orientation::Across, 5),
              WordspanAddress::new(0, 6, Orientation::Across, 5),
              WordspanAddress::new(1, 0, Orientation::Across, 5),
              WordspanAddress::new(1, 6, Orientation::Across, 5),
              WordspanAddress::new(2, 0, Orientation::Across, 4),
              WordspanAddress::new(2, 5, Orientation::Across, 6)],
            &puzzle.oriented_wordspan_addresses(Orientation::Across)[..6]
        );
    }

    #[test]
    fn concerning_wordspan_addresses_down() {
        let puzzle = test_puzzle_ii();
        assert_eq!(
            &[WordspanAddress::new(0, 0, Orientation::Down, 4),
              WordspanAddress::new(0, 1, Orientation::Down, 6),
              WordspanAddress::new(0, 2, Orientation::Down, 7),
              WordspanAddress::new(0, 3, Orientation::Down, 3),
              WordspanAddress::new(4, 3, Orientation::Down, 3),
              WordspanAddress::new(0, 4, Orientation::Down, 2)],
            &puzzle.oriented_wordspan_addresses(Orientation::Down)[..6]
        );
    }

    #[test]
    fn concerning_is_solved() {
        let lexicon = Lexicon::build(7);
        let puzzles = vec![test_puzzle_i(), test_puzzle_ii()];
        for mut puzzle in puzzles {
            assert!(puzzle.is_solved(&lexicon));
            puzzle.write(0, 0, 'Q');
            assert!(!puzzle.is_solved(&lexicon));
        }
    }

    #[test]
    fn concerning_gathering_cross_requirements() {
        assert_eq!(
            vec![CrossRequirement::new(5, charvec![QUA]),
                 CrossRequirement::new(5, charvec![UNI]),
                 CrossRequirement::new(5, charvec![IDL]),
                 CrossRequirement::new(5, charvec![ZOS])],
            test_puzzle_iii()
                .gather_cross_requirements(
                    WordspanAddress::new(3, 0, Orientation::Across, 4))
        );
    }

    #[test]
    fn concerning_is_full() {
        assert!(test_puzzle_i().is_full());
        assert!(test_puzzle_ii().is_full());
        assert!(!test_puzzle_iii().is_full());
    }
}
<|endoftext|>