<commit_before>/* Copyright 2017 David Li.

 * This file is part of BigRedRPG.

 * BigRedRPG is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.

 * BigRedRPG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU Affero General Public License
 * along with BigRedRPG.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::collections::HashMap;

use rand::{self, Rng};

use interactiondb::InteractionDb;
use location::{Location, LocationId, Map};
use student::Student;
use util::rng;

pub struct Time(u32);

pub struct Cornell {
    map: Map,

    time: Time,
}

impl Cornell {
    pub fn new() -> Cornell {
        Cornell {
            map: Map::new(),

            time: Time(0),
        }
    }

    pub fn add_location(&mut self, location: Location) -> LocationId {
        self.map.add(location)
    }

    pub fn add_student(&mut self, student: Student, location: LocationId) {
        if let Some(loc) = self.map.get_mut(location) {
            loc.students.push(student);
        }
        else {
            panic!("LocationId not found: {:?}", location);
        }
    }

    pub fn step(&mut self, interactions: &InteractionDb) {
        // TODO: step time

        let mut rng = rand::thread_rng();
        for (location_id, location) in self.map.iter_mut() {
            for student in location.students.iter_mut() {
                let possible_interactions = interactions.search(&student, *location_id);

                if let Some(interaction) = rng.choose(&possible_interactions) {
                    let mut choices = Vec::new();
                    for &(ref item, mut chance, ref dispositions) in interaction.choices.iter() {
                        for disposition in dispositions.iter() {
                            chance += disposition.value(student);
                        }
                        choices.push((item, chance));
                    }
                    if let Some(choice) = rng::weighted_random(choices.iter().cloned(), &mut rng) {
                        for effect in choice.effects.iter() {
                            effect.apply(student);
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>feat(Simulation): advance time step<commit_after>/* Copyright 2017 David Li.

 * This file is part of BigRedRPG.

 * BigRedRPG is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.

 * BigRedRPG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU Affero General Public License
 * along with BigRedRPG.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::ops;

use rand::{self, Rng};

use interactiondb::InteractionDb;
use location::{Location, LocationId, Map};
use student::Student;
use util::rng;

/// Time represents the current game time, stored as the number of
/// minutes since game start.
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
pub struct Time(u32);

pub const TIME_STEP: Time = Time(15);

impl ops::Add for Time {
    type Output = Time;

    fn add(self, rhs: Time) -> Time {
        Time(self.0 + rhs.0)
    }
}

impl ops::AddAssign for Time {
    fn add_assign(&mut self, rhs: Time) {
        self.0 += rhs.0;
    }
}

pub struct Cornell {
    map: Map,

    time: Time,
}

impl Cornell {
    pub fn new() -> Cornell {
        Cornell {
            map: Map::new(),

            time: Time(0),
        }
    }

    pub fn add_location(&mut self, location: Location) -> LocationId {
        self.map.add(location)
    }

    pub fn add_student(&mut self, student: Student, location: LocationId) {
        if let Some(loc) = self.map.get_mut(location) {
            loc.students.push(student);
        }
        else {
            panic!("LocationId not found: {:?}", location);
        }
    }

    pub fn step(&mut self, interactions: &InteractionDb) {
        self.time += TIME_STEP;

        let mut rng = rand::thread_rng();
        for (location_id, location) in self.map.iter_mut() {
            for student in location.students.iter_mut() {
                let possible_interactions = interactions.search(&student, *location_id);

                if let Some(interaction) = rng.choose(&possible_interactions) {
                    let mut choices = Vec::new();
                    for &(ref item, mut chance, ref dispositions) in interaction.choices.iter() {
                        for disposition in dispositions.iter() {
                            chance += disposition.value(student);
                        }
                        choices.push((item, chance));
                    }
                    if let Some(choice) = rng::weighted_random(choices.iter().cloned(), &mut rng) {
                        for effect in choice.effects.iter() {
                            effect.apply(student);
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::super::bus;
use super::cp0::CP0;
use super::instruction::Instruction;
use super::instruction::INSTRUCTION_SIZE;
use super::opcode::Opcode;
use super::opcode::OpcodeSpecial;

use std::fmt;

const NUM_GPREG: usize = 32;
const NUM_FPREG: usize = 32;

const PIF_ROM_START: u64 = 0xffff_ffff_bfc0_0000;

pub struct Cpu {
    reg_gprs: [u64; NUM_GPREG],
    reg_fprs: [f64; NUM_FPREG],

    reg_pc: u64,

    reg_hi: u64,
    reg_lo: u64,

    reg_llbit: bool,

    reg_fcr0: u32,
    reg_fcr31: u32,

    cp0: CP0,

    bus: bus::Bus,
}

impl Cpu {
    pub fn new(bus: bus::Bus) -> Cpu {
        Cpu {
            reg_gprs: [0; NUM_GPREG],
            reg_fprs: [0.0; NUM_FPREG],

            reg_pc: PIF_ROM_START,

            reg_hi: 0,
            reg_lo: 0,

            reg_llbit: false,

            reg_fcr0: 0,
            reg_fcr31: 0,

            cp0: CP0::default(),

            bus: bus,
        }
    }

    pub fn run(&mut self) {
        loop {
            self.run_instruction();
        }
    }

    pub fn run_instruction(&mut self) {
        let instruction = self.read_instruction(self.reg_pc);
        println!("PC: {:#x}", self.reg_pc);
        let new_pc = self.reg_pc.wrapping_add(INSTRUCTION_SIZE as u64);
        self.change_pc(new_pc, false);

        self.execute_instruction(instruction);
    }

    fn execute_special(&mut self, instruction: Instruction) {
        match instruction.opcode_special() {
            OpcodeSpecial::OR => {
                let rs_val = self.read_gpr(instruction.source());
                let rt_val = self.read_gpr(instruction.target_register());
                self.write_gpr(instruction.destination(), rs_val | rt_val);
            }
            OpcodeSpecial::SRL => {
                let res = self.read_gpr(instruction.target_immediate()) >>
                          instruction.shift_amount();
                self.write_gpr(instruction.destination(), res);
            }
            OpcodeSpecial::JR => {
                println!("JUMPY");
                let new_pc = self.read_gpr(instruction.source());
                if new_pc & 0b11 != 0 {
                    panic!("Address error exception");
                }
                self.change_pc(new_pc, true);
            }
        }
    }

    fn execute_instruction(&mut self, instruction: Instruction) {
        println!("Instr: {:?}", instruction);
        match instruction.opcode() {
            Opcode::SPECIAL => {
                self.execute_special(instruction);
            }
            Opcode::ADDI => {
                let rs_val = self.read_gpr(instruction.source());
                self.write_gpr(instruction.target_immediate(), {

                    let rs_positive = (rs_val >> 31) & 1 == 0;
                    let imm = instruction.immediate_extend();
                    let imm_positive = (imm >> 31) & 1 == 0;
                    let res = rs_val.wrapping_add(imm);
                    let res_positive = (res >> 31 & 1) == 0;
                    match (rs_positive, imm_positive, res_positive) {
                        (true, true, false) => {
                            panic!("Integer overflow exception not implemented! (pp=n) {:016X}  \
                                    {:016X} != {:016X}",
                                   res,
                                   imm,
                                   res);
                        }
                        (false, false, true) => {
                            panic!("Integer overflow exception not implemented! (nn=p) {:016X}  \
                                    {:016X} != {:016X}",
                                   res,
                                   imm,
                                   res);
                        }
                        _ => {}
                    };
                    res
                });
            }
            Opcode::ADDIU => {
                let res = self.read_gpr(instruction.source())
                    .wrapping_add((instruction.immediate_extend()));
                self.write_gpr(instruction.target_immediate(), res);
            }
            Opcode::MTC0 => {
                let rt = instruction.target_register();
                let rd = instruction.destination();
                let data = self.read_gpr(rt);
                self.cp0.write_reg(rd, data);
            }
            Opcode::ANDI => {
                let res = self.read_gpr(instruction.source()) & (instruction.immediate() as u64);
                self.write_gpr(instruction.target_immediate(), res);
            }
            Opcode::ORI => {
                let res = self.read_gpr(instruction.source()) | (instruction.immediate() as u64);
                self.write_gpr(instruction.target_immediate(), res);
            }
            Opcode::LUI => {
                // assume 32 bit mode
                self.write_gpr(instruction.target_immediate(),
                               (((instruction.immediate() as u32) << 16) as i32) as u64);
            }
            Opcode::BEQ => {
                let branch = self.branch(instruction, |rs, rt| rs == rt);
            }
            Opcode::BEQL => self.branch_likely(instruction, |rs, rt| rs == rt),
            Opcode::BNE => {
                let branch = self.branch(instruction, |rs, rt| rs != rt);
            }
            Opcode::BNEL => self.branch_likely(instruction, |rs, rt| rs != rt),
            Opcode::LW => {
                // LW
                let base = self.read_gpr(instruction.source());
                let vaddr = base.wrapping_add((instruction.immediate() as i16) as u64);
                if vaddr & 0b11 != 0 {
                    panic!("Address error exception");
                }

                let word = self.read_word(vaddr);
                let mem = (word as i32) as u64;
                self.write_gpr(instruction.target_immediate(), mem);

            }
            Opcode::SW => {
                let base = self.read_gpr(instruction.source());
                let vaddr = base.wrapping_add((instruction.immediate() as i16) as u64);
                if vaddr & 0b11 != 0 {
                    panic!("Address error exception");
                }
                let value = self.read_gpr(instruction.target_immediate()) as u32;
                self.write_word(vaddr, value);
            }
        }

    }

    fn change_pc(&mut self, new_address: u64, with_delay: bool) {
        let delay_instuction = self.read_instruction(self.reg_pc);
        self.reg_pc = new_address;
        if with_delay {
            self.execute_instruction(delay_instuction);
        }
    }

    fn branch_likely<F>(&mut self, instruction: Instruction, f: F)
        where F: FnOnce(u64, u64) -> bool
    {
        if !self.branch(instruction, f) {
            self.reg_pc = self.reg_pc.wrapping_add(INSTRUCTION_SIZE as u64)
        }
    }

    fn branch<F>(&mut self, instruction: Instruction, f: F) -> bool
        where F: FnOnce(u64, u64) -> bool
    {
        let rs = self.read_gpr(instruction.source());
        let rt = self.read_gpr(instruction.target_immediate());
        let branch = f(rs, rt);

        if branch {
            let new_pc = self.reg_pc
                .wrapping_add(((instruction.immediate() << 2) as i16) as u64);
            self.change_pc(new_pc, true);
        }
        branch
    }

    fn read_word(&self, addr: u64) -> u32 {
        let paddr = vaddr_to_paddr(addr);
        self.bus.read_word(paddr as u32)
    }

    fn write_word(&mut self, addr: u64, value: u32) {
        let paddr = vaddr_to_paddr(addr);
        self.bus.write_word(paddr as u32, value);
    }

    fn read_instruction(&self, addr: u64) -> Instruction {

        Instruction(self.read_word(addr))
    }

    fn write_gpr(&mut self, index: u8, value: u64) {
        if index != 0 {
            self.reg_gprs[index as usize] = value;
        }
    }

    fn read_gpr(&self, index: u8) -> u64 {
        match index {
            0 => 0,
            _ => self.reg_gprs[index as usize],
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        const REGS_PER_LINE: usize = 2;
        const REG_NAMES: [&'static str; NUM_GPREG] =
            ["r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5",
             "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1",
             "gp", "sp", "s8", "ra"];

        try!(write!(f, "\nCPU General Purpose Registers:"));
        for reg_num in 0..NUM_GPREG {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f, ""));
            }
            try!(write!(f,
                        "{reg_name}/gpr{num:02}: {value:#018X} ",
                        num = reg_num,
                        reg_name = REG_NAMES[reg_num],
                        value = self.reg_gprs[reg_num]));
        }

        try!(write!(f, "\n\nCPU Floating Point Registers:"));
        for reg_num in 0..NUM_FPREG {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f, ""));
            }
            try!(write!(f,
                "fpr{num:02}: {value:21} ",
                num = reg_num,
                value = self.reg_fprs[reg_num],));
        }

        try!(writeln!(f, "\n\nCPU Special Registers:"));
        try!(writeln!(f,
                      "\
            reg_pc: {:#018X}\nreg_hi: {:#018X}\nreg_lo: \
                       {:#018X}\nreg_llbit: {}\nreg_fcr0:  {:#010X}\nreg_fcr31: {:#010X}\n",
                      self.reg_pc,
                      self.reg_hi,
                      self.reg_lo,
                      self.reg_llbit,
                      self.reg_fcr0,
                      self.reg_fcr31));

        try!(writeln!(f, "{:#?}", self.cp0));
        writeln!(f, "{:#?}", self.bus)
    }
}

fn vaddr_to_paddr(vaddr: u64) -> u64 {
    let addr_bit_values = (vaddr >> 29) & 0b111;
    if addr_bit_values == 0b101 {
        // kseg1
        vaddr - 0xffff_ffff_a000_0000
    } else {
        panic!("Unrecognised virtual address {:#x}", vaddr);
    }
}
<commit_msg>Sign extend result for SRL<commit_after>use super::super::bus;
use super::cp0::CP0;
use super::instruction::Instruction;
use super::instruction::INSTRUCTION_SIZE;
use super::opcode::Opcode;
use super::opcode::OpcodeSpecial;

use std::fmt;

const NUM_GPREG: usize = 32;
const NUM_FPREG: usize = 32;

const PIF_ROM_START: u64 = 0xffff_ffff_bfc0_0000;

pub struct Cpu {
    reg_gprs: [u64; NUM_GPREG],
    reg_fprs: [f64; NUM_FPREG],

    reg_pc: u64,

    reg_hi: u64,
    reg_lo: u64,

    reg_llbit: bool,

    reg_fcr0: u32,
    reg_fcr31: u32,

    cp0: CP0,

    bus: bus::Bus,
}

impl Cpu {
    pub fn new(bus: bus::Bus) -> Cpu {
        Cpu {
            reg_gprs: [0; NUM_GPREG],
            reg_fprs: [0.0; NUM_FPREG],

            reg_pc: PIF_ROM_START,

            reg_hi: 0,
            reg_lo: 0,

            reg_llbit: false,

            reg_fcr0: 0,
            reg_fcr31: 0,

            cp0: CP0::default(),

            bus: bus,
        }
    }

    pub fn run(&mut self) {
        loop {
            self.run_instruction();
        }
    }

    pub fn run_instruction(&mut self) {
        let instruction = self.read_instruction(self.reg_pc);
        println!("PC: {:#x}", self.reg_pc);
        let new_pc = self.reg_pc.wrapping_add(INSTRUCTION_SIZE as u64);
        self.change_pc(new_pc, false);

        self.execute_instruction(instruction);
    }

    fn execute_special(&mut self, instruction: Instruction) {
        match instruction.opcode_special() {
            OpcodeSpecial::OR => {
                let rs_val = self.read_gpr(instruction.source());
                let rt_val = self.read_gpr(instruction.target_register());
                self.write_gpr(instruction.destination(), rs_val | rt_val);
            }
            OpcodeSpecial::SRL => {
                let res = self.read_gpr(instruction.target_immediate()) >>
                          instruction.shift_amount();
                self.write_gpr(instruction.destination(), (res as i32) as u64);
            }
            OpcodeSpecial::JR => {
                println!("JUMPY");
                let new_pc = self.read_gpr(instruction.source());
                if new_pc & 0b11 != 0 {
                    panic!("Address error exception");
                }
                self.change_pc(new_pc, true);
            }
        }
    }

    fn execute_instruction(&mut self, instruction: Instruction) {
        println!("Instr: {:?}", instruction);
        match instruction.opcode() {
            Opcode::SPECIAL => {
                self.execute_special(instruction);
            }
            Opcode::ADDI => {
                let rs_val = self.read_gpr(instruction.source());
                self.write_gpr(instruction.target_immediate(), {

                    let rs_positive = (rs_val >> 31) & 1 == 0;
                    let imm = instruction.immediate_extend();
                    let imm_positive = (imm >> 31) & 1 == 0;
                    let res = rs_val.wrapping_add(imm);
                    let res_positive = (res >> 31 & 1) == 0;
                    match (rs_positive, imm_positive, res_positive) {
                        (true, true, false) => {
                            panic!("Integer overflow exception not implemented! (pp=n) {:016X}  \
                                    {:016X} != {:016X}",
                                   res,
                                   imm,
                                   res);
                        }
                        (false, false, true) => {
                            panic!("Integer overflow exception not implemented! (nn=p) {:016X}  \
                                    {:016X} != {:016X}",
                                   res,
                                   imm,
                                   res);
                        }
                        _ => {}
                    };
                    res
                });
            }
            Opcode::ADDIU => {
                let res = self.read_gpr(instruction.source())
                    .wrapping_add((instruction.immediate_extend()));
                self.write_gpr(instruction.target_immediate(), res);
            }
            Opcode::MTC0 => {
                let rt = instruction.target_register();
                let rd = instruction.destination();
                let data = self.read_gpr(rt);
                self.cp0.write_reg(rd, data);
            }
            Opcode::ANDI => {
                let res = self.read_gpr(instruction.source()) & (instruction.immediate() as u64);
                self.write_gpr(instruction.target_immediate(), res);
            }
            Opcode::ORI => {
                let res = self.read_gpr(instruction.source()) | (instruction.immediate() as u64);
                self.write_gpr(instruction.target_immediate(), res);
            }
            Opcode::LUI => {
                // assume 32 bit mode
                self.write_gpr(instruction.target_immediate(),
                               (((instruction.immediate() as u32) << 16) as i32) as u64);
            }
            Opcode::BEQ => {
                let branch = self.branch(instruction, |rs, rt| rs == rt);
            }
            Opcode::BEQL => self.branch_likely(instruction, |rs, rt| rs == rt),
            Opcode::BNE => {
                let branch = self.branch(instruction, |rs, rt| rs != rt);
            }
            Opcode::BNEL => self.branch_likely(instruction, |rs, rt| rs != rt),
            Opcode::LW => {
                // LW
                let base = self.read_gpr(instruction.source());
                let vaddr = base.wrapping_add((instruction.immediate() as i16) as u64);
                if vaddr & 0b11 != 0 {
                    panic!("Address error exception");
                }

                let word = self.read_word(vaddr);
                let mem = (word as i32) as u64;
                self.write_gpr(instruction.target_immediate(), mem);

            }
            Opcode::SW => {
                let base = self.read_gpr(instruction.source());
                let vaddr = base.wrapping_add((instruction.immediate() as i16) as u64);
                if vaddr & 0b11 != 0 {
                    panic!("Address error exception");
                }
                let value = self.read_gpr(instruction.target_immediate()) as u32;
                self.write_word(vaddr, value);
            }
        }

    }

    fn change_pc(&mut self, new_address: u64, with_delay: bool) {
        let delay_instuction = self.read_instruction(self.reg_pc);
        self.reg_pc = new_address;
        if with_delay {
            self.execute_instruction(delay_instuction);
        }
    }

    fn branch_likely<F>(&mut self, instruction: Instruction, f: F)
        where F: FnOnce(u64, u64) -> bool
    {
        if !self.branch(instruction, f) {
            self.reg_pc = self.reg_pc.wrapping_add(INSTRUCTION_SIZE as u64)
        }
    }

    fn branch<F>(&mut self, instruction: Instruction, f: F) -> bool
        where F: FnOnce(u64, u64) -> bool
    {
        let rs = self.read_gpr(instruction.source());
        let rt = self.read_gpr(instruction.target_immediate());
        let branch = f(rs, rt);

        if branch {
            let new_pc = self.reg_pc
                .wrapping_add(((instruction.immediate() << 2) as i16) as u64);
            self.change_pc(new_pc, true);
        }
        branch
    }

    fn read_word(&self, addr: u64) -> u32 {
        let paddr = vaddr_to_paddr(addr);
        self.bus.read_word(paddr as u32)
    }

    fn write_word(&mut self, addr: u64, value: u32) {
        let paddr = vaddr_to_paddr(addr);
        self.bus.write_word(paddr as u32, value);
    }

    fn read_instruction(&self, addr: u64) -> Instruction {

        Instruction(self.read_word(addr))
    }

    fn write_gpr(&mut self, index: u8, value: u64) {
        if index != 0 {
            self.reg_gprs[index as usize] = value;
        }
    }

    fn read_gpr(&self, index: u8) -> u64 {
        match index {
            0 => 0,
            _ => self.reg_gprs[index as usize],
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        const REGS_PER_LINE: usize = 2;
        const REG_NAMES: [&'static str; NUM_GPREG] =
            ["r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5",
             "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1",
             "gp", "sp", "s8", "ra"];

        try!(write!(f, "\nCPU General Purpose Registers:"));
        for reg_num in 0..NUM_GPREG {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f, ""));
            }
            try!(write!(f,
                        "{reg_name}/gpr{num:02}: {value:#018X} ",
                        num = reg_num,
                        reg_name = REG_NAMES[reg_num],
                        value = self.reg_gprs[reg_num]));
        }

        try!(write!(f, "\n\nCPU Floating Point Registers:"));
        for reg_num in 0..NUM_FPREG {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f, ""));
            }
            try!(write!(f,
                "fpr{num:02}: {value:21} ",
                num = reg_num,
                value = self.reg_fprs[reg_num],));
        }

        try!(writeln!(f, "\n\nCPU Special Registers:"));
        try!(writeln!(f,
                      "\
            reg_pc: {:#018X}\nreg_hi: {:#018X}\nreg_lo: \
                       {:#018X}\nreg_llbit: {}\nreg_fcr0:  {:#010X}\nreg_fcr31: {:#010X}\n",
                      self.reg_pc,
                      self.reg_hi,
                      self.reg_lo,
                      self.reg_llbit,
                      self.reg_fcr0,
                      self.reg_fcr31));

        try!(writeln!(f, "{:#?}", self.cp0));
        writeln!(f, "{:#?}", self.bus)
    }
}

fn vaddr_to_paddr(vaddr: u64) -> u64 {
    let addr_bit_values = (vaddr >> 29) & 0b111;
    if addr_bit_values == 0b101 {
        // kseg1
        vaddr - 0xffff_ffff_a000_0000
    } else {
        panic!("Unrecognised virtual address {:#x}", vaddr);
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod spec_tests;

#[cfg(test)]
mod functional_test;

#[cfg(test)]
mod length_and_timing_tests;

#[cfg(feature = "debugger")]
pub mod debugger;

mod byte_utils;
mod registers;
mod opcodes;

use cpu::byte_utils::{from_lo_hi, lo_hi, wrapping_dec, wrapping_inc};
use cpu::registers::Registers;
use errors::*;
use memory::*;

const STACK_LOC: u16 = 0x100;
const NMI_VECTOR: u16 = 0xfffa;
const RESET_VECTOR: u16 = 0xfffc;

#[cfg(test)]
pub type TestCpu = Cpu<SimpleMemory>;

#[cfg(test)]
impl TestCpu {
    pub fn new_test() -> Self {
        let memory = SimpleMemory::new();
        Cpu::new(memory, 0x200)
    }
}

#[derive(PartialEq, Eq)]
pub enum TickAction {
    None,
    Nmi,
}

pub type StepResult = Result<()>;

pub struct Cpu<M: Memory> {
    registers: Registers,
    memory: M,
    cycles: u64,
}

impl<Mem: Memory> Cpu<Mem> {
    pub fn new(memory: Mem, pc: u16) -> Self {
        let mut cpu = Cpu {
            registers: Registers::new(),
            memory: memory,
            cycles: 0,
        };

        cpu.registers.pc = pc;
        cpu
    }

    pub fn step(&mut self) -> StepResult {
        let opcode = self.read_pc()?;
        self::opcodes::execute(self, opcode)
    }

    fn read_memory(&mut self, addr: u16) -> Result<u8> {
        let val = self.memory.load(addr)?;
        self.tick()?;
        Ok(val)
    }

    fn read_memory16(&mut self, addr: u16) -> Result<u16> {
        let low_byte = self.read_memory(addr)?;
        let high_byte = self.read_memory(addr + 1)?;
        Ok(from_lo_hi(low_byte, high_byte))
    }

    fn read_memory16_zp(&mut self, addr: u8) -> Result<u16> {
        let low_byte = self.read_memory(addr as u16)?;
        let high_byte = self.read_memory(wrapping_inc(addr) as u16)?;
        Ok(from_lo_hi(low_byte, high_byte))
    }

    fn write_memory(&mut self, addr: u16, val: u8) -> Result<()> {
        self.memory.store(addr, val)?;
        self.tick()
    }

    pub fn reset(&mut self) -> Result<()> {
        let pc_low = self.read_memory(RESET_VECTOR)?;
        let pc_high = self.read_memory(RESET_VECTOR + 1)?;
        self.registers.pc = from_lo_hi(pc_low, pc_high);
        Ok(())
    }

    pub fn nmi(&mut self) -> Result<()> {
        let stat = self.registers.status;
        let pc = self.registers.pc;
        self.push_stack16(pc)?;
        self.push_stack(stat)?;
        let pc = self.read_memory16(NMI_VECTOR)?;
        self.registers.pc = pc;
        Ok(())
    }

    fn tick(&mut self) -> Result<()> {
        self.cycles += 1;
        if self.memory.tick()? == TickAction::Nmi {
            self.nmi()
        } else {
            Ok(())
        }
    }

    fn read_pc(&mut self) -> Result<u8> {
        let pc = self.registers.pc;
        let operand = self.read_memory(pc)?;
        self.registers.pc += 1;
        Ok(operand)
    }

    fn read_pc16(&mut self) -> Result<u16> {
        let low_byte = self.read_pc()?;
        let high_byte = self.read_pc()?;
        Ok(low_byte as u16 | (high_byte as u16) << 8)
    }

    fn push_stack(&mut self, value: u8) -> Result<()> {
        let sp = self.registers.sp as u16;
        self.write_memory(STACK_LOC + sp, value)?;
        self.registers.sp = wrapping_dec(self.registers.sp);
        Ok(())
    }

    fn push_stack16(&mut self, value: u16) -> Result<()> {
        let (low_byte, high_byte) = lo_hi(value);
        self.push_stack(high_byte)?;
        self.push_stack(low_byte)?;
        Ok(())
    }

    fn pop_stack(&mut self) -> Result<u8> {
        let sp = wrapping_inc(self.registers.sp);
        let val = self.read_memory(STACK_LOC + sp as u16)?;
        self.registers.sp = sp;
        Ok(val)
    }

    fn pop_stack16(&mut self) -> Result<u16> {
        let low_byte = self.pop_stack()?;
        let high_byte = self.pop_stack()?;
        Ok(from_lo_hi(low_byte, high_byte))
    }
}
<commit_msg>Make Cpu.nmi() private<commit_after>#[cfg(test)]
mod spec_tests;

#[cfg(test)]
mod functional_test;

#[cfg(test)]
mod length_and_timing_tests;

#[cfg(feature = "debugger")]
pub mod debugger;

mod byte_utils;
mod registers;
mod opcodes;

use cpu::byte_utils::{from_lo_hi, lo_hi, wrapping_dec, wrapping_inc};
use cpu::registers::Registers;
use errors::*;
use memory::*;

const STACK_LOC: u16 = 0x100;
const NMI_VECTOR: u16 = 0xfffa;
const RESET_VECTOR: u16 = 0xfffc;

#[cfg(test)]
pub type TestCpu = Cpu<SimpleMemory>;

#[cfg(test)]
impl TestCpu {
    pub fn new_test() -> Self {
        let memory = SimpleMemory::new();
        Cpu::new(memory, 0x200)
    }
}

#[derive(PartialEq, Eq)]
pub enum TickAction {
    None,
    Nmi,
}

pub type StepResult = Result<()>;

pub struct Cpu<M: Memory> {
    registers: Registers,
    memory: M,
    cycles: u64,
}

impl<Mem: Memory> Cpu<Mem> {
    pub fn new(memory: Mem, pc: u16) -> Self {
        let mut cpu = Cpu {
            registers: Registers::new(),
            memory: memory,
            cycles: 0,
        };

        cpu.registers.pc = pc;
        cpu
    }

    pub fn step(&mut self) -> StepResult {
        let opcode = self.read_pc()?;
        self::opcodes::execute(self, opcode)
    }

    fn read_memory(&mut self, addr: u16) -> Result<u8> {
        let val = self.memory.load(addr)?;
        self.tick()?;
        Ok(val)
    }

    fn read_memory16(&mut self, addr: u16) -> Result<u16> {
        let low_byte = self.read_memory(addr)?;
        let high_byte = self.read_memory(addr + 1)?;
        Ok(from_lo_hi(low_byte, high_byte))
    }

    fn read_memory16_zp(&mut self, addr: u8) -> Result<u16> {
        let low_byte = self.read_memory(addr as u16)?;
        let high_byte = self.read_memory(wrapping_inc(addr) as u16)?;
        Ok(from_lo_hi(low_byte, high_byte))
    }

    fn write_memory(&mut self, addr: u16, val: u8) -> Result<()> {
        self.memory.store(addr, val)?;
        self.tick()
    }

    pub fn reset(&mut self) -> Result<()> {
        let pc_low = self.read_memory(RESET_VECTOR)?;
        let pc_high = self.read_memory(RESET_VECTOR + 1)?;
        self.registers.pc = from_lo_hi(pc_low, pc_high);
        Ok(())
    }

    fn nmi(&mut self) -> Result<()> {
        let stat = self.registers.status;
        let pc = self.registers.pc;
        self.push_stack16(pc)?;
        self.push_stack(stat)?;
        let pc = self.read_memory16(NMI_VECTOR)?;
        self.registers.pc = pc;
        Ok(())
    }

    fn tick(&mut self) -> Result<()> {
        self.cycles += 1;
        if self.memory.tick()? == TickAction::Nmi {
            self.nmi()
        } else {
            Ok(())
        }
    }

    fn read_pc(&mut self) -> Result<u8> {
        let pc = self.registers.pc;
        let operand = self.read_memory(pc)?;
        self.registers.pc += 1;
        Ok(operand)
    }

    fn read_pc16(&mut self) -> Result<u16> {
        let low_byte = self.read_pc()?;
        let high_byte = self.read_pc()?;
        Ok(low_byte as u16 | (high_byte as u16) << 8)
    }

    fn push_stack(&mut self, value: u8) -> Result<()> {
        let sp = self.registers.sp as u16;
        self.write_memory(STACK_LOC + sp, value)?;
        self.registers.sp = wrapping_dec(self.registers.sp);
        Ok(())
    }

    fn push_stack16(&mut self, value: u16) -> Result<()> {
        let (low_byte, high_byte) = lo_hi(value);
        self.push_stack(high_byte)?;
        self.push_stack(low_byte)?;
        Ok(())
    }

    fn pop_stack(&mut self) -> Result<u8> {
        let sp = wrapping_inc(self.registers.sp);
        let val = self.read_memory(STACK_LOC + sp as u16)?;
        self.registers.sp = sp;
        Ok(val)
    }

    fn pop_stack16(&mut self) -> Result<u16> {
        let low_byte = self.pop_stack()?;
        let high_byte = self.pop_stack()?;
        Ok(from_lo_hi(low_byte, high_byte))
    }
}
<|endoftext|>


<commit_before>#[derive(PartialEq, Debug, Clone)]
pub enum Token {
    Word(String),

    //characters
    LeftParenthesis,
    RightParenthesis,
    SemiColon,
    SingleQuote,
    Colon
}

pub struct Lexer {
    src: Vec<char>,
    string_expr: bool
}

impl Lexer {

    pub fn new(line: &str) -> Lexer {
        Lexer {
            src: line.chars().collect::<Vec<char>>(),
            string_expr: false
        }
    }

    pub fn next_lexem(&mut self) -> Option<Token> {
        self.remove_front_spaces();
        if self.src.is_empty() {
            None
        }
        else {
            Some(self.parse_lexem())
        }
    }

    fn parse_lexem(&mut self) -> Token {
        if self.has_lexem_in_begining() {
            match self.src.remove(0) {
                '(' => return Token::LeftParenthesis,
                ',' => return Token::Colon,
                ')' => return Token::RightParenthesis,
                ';' => return Token::SemiColon,
                _ => {}
            }
        }
        let mut i = 0;
        while i < self.src.len() {
            let s = self.src[i];
            match s {
                'a'...'z' |
                'A'...'Z' |
                '0'...'9' |
                '_' => i += 1,
                '\'' => {
                    if i == 0 && !self.string_expr {
                        self.src = self.src.split_off(1);
                        self.string_expr = !self.string_expr;
                        return Token::SingleQuote;
                    }
                    else if self.src.len() - i > 1
                            && self.src[i] == '\''
                            && self.src[i+1] == '\''
                            && self.string_expr {
                        self.src.remove(i);
                        i += 1;
                    }
                    else {
                        self.string_expr = !self.string_expr;
                        break;
                    }
                },
                ' ' | '\t' | '\n' => {
                    if i == 0 && !self.string_expr {
                        self.src.remove(0);
                    }
                    else if self.string_expr {
                        i += 1;
                    }
                    else {
                        break;
                    }
                },
                /*'-' => {
                    if i == 0 && self.src[1] == '-' {
                        let mut j = 2;
                        let mut c = self.src[j];
                        while c != '\n' {
                            j += 1;
                            c = self.src[j];
                        }
                        self.src = self.src.split_off(j);
                    }
                }*/
                _ => break,
            }
        }
        let mut v = self.src.clone();
        self.src = v.split_off(i);
        Token::Word(v.iter().map(|c| *c).collect::<String>().to_lowercase())
    }

    fn has_lexem_in_begining(&self) -> bool {
        match self.src[0] {
            '(' | ')' | ',' | ';' => true,
            _ => false,
        }
    }

    fn remove_front_spaces(&mut self) {
        while !self.src.is_empty()
                && !self.string_expr
                && (self.src[0] == ' '
                || self.src[0] == '\t'
                || self.src[0] == '\n') {
            self.src.remove(0);
        }
    }
}
<commit_msg>impl: exclude line comments<commit_after>#[derive(PartialEq, Debug, Clone)]
pub enum Token {
    Word(String),

    //characters
    LeftParenthesis,
    RightParenthesis,
    SemiColon,
    SingleQuote,
    Colon
}

pub struct Lexer {
    src: Vec<char>,
    string_expr: bool
}

impl Lexer {

    pub fn new(line: &str) -> Lexer {
        Lexer {
            src: line.chars().collect::<Vec<char>>(),
            string_expr: false
        }
    }

    pub fn next_lexem(&mut self) -> Option<Token> {
        self.remove_front_spaces();
        if self.src.is_empty() {
            None
        }
        else {
            Some(self.parse_lexem())
        }
    }

    fn parse_lexem(&mut self) -> Token {
        if self.has_lexem_in_begining() {
            match self.src.remove(0) {
                '(' => return Token::LeftParenthesis,
                ',' => return Token::Colon,
                ')' => return Token::RightParenthesis,
                ';' => return Token::SemiColon,
                _ => {}
            }
        }
        let mut i = 0;
        while i < self.src.len() {
            let s = self.src[i];
            match s {
                'a'...'z' |
                'A'...'Z' |
                '0'...'9' |
                '_' => i += 1,
                '\'' => {
                    if i == 0 && !self.string_expr {
                        self.src = self.src.split_off(1);
                        self.string_expr = !self.string_expr;
                        return Token::SingleQuote;
                    }
                    else if self.src.len() - i > 1
                            && self.src[i] == '\''
                            && self.src[i+1] == '\''
                            && self.string_expr {
                        self.src.remove(i);
                        i += 1;
                    }
                    else {
                        self.string_expr = !self.string_expr;
                        break;
                    }
                },
                ' ' | '\t' | '\n' => {
                    if i == 0 && !self.string_expr {
                        self.src.remove(0);
                    }
                    else if self.string_expr {
                        i += 1;
                    }
                    else {
                        break;
                    }
                },
                '-' => {
                    if i == 0 && self.src[1] == '-' {
                        let mut j = 2;
                        let mut c = self.src[j];
                        while c != '\n' {
                            j += 1;
                            c = self.src[j];
                        }
                        self.src = self.src.split_off(j);
                    }
                }
                _ => break,
            }
        }
        let mut v = self.src.clone();
        self.src = v.split_off(i);
        Token::Word(v.iter().map(|c| *c).collect::<String>().to_lowercase())
    }

    fn has_lexem_in_begining(&self) -> bool {
        match self.src[0] {
            '(' | ')' | ',' | ';' => true,
            _ => false,
        }
    }

    fn remove_front_spaces(&mut self) {
        while !self.src.is_empty()
                && !self.string_expr
                && (self.src[0] == ' '
                || self.src[0] == '\t'
                || self.src[0] == '\n') {
            self.src.remove(0);
        }
    }
}
<|endoftext|>


<commit_before>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

use std::iter::Range;

/// The `SharedVertex` trait is meant to be used with the `IndexedPolygon` trait.
/// This trait is meant as a way to calculate the shared vertices that are
/// required to build the implementors mesh.
pub trait SharedVertex<V> {
    /// return the shared vertex at offset `i`
    fn shared_vertex(&self, i: uint) -> V;

    /// return the number of shared vertices required to represent the mesh
    fn shared_vertex_count(&self) -> uint;

    /// create an iterator that returns each shared vertex that is required to
    /// build the mesh.
    fn shared_vertex_iter<'a>(&'a self) -> ShareVertexIterator<'a, Self, V> {
        ShareVertexIterator {
            base: self,
            idx: range(0, self.shared_vertex_count())
        }
    }
}

pub struct ShareVertexIterator<'a, T, V> {
    base: &'a T,
    idx: Range<uint>
}

impl<'a, T: SharedVertex<V>, V> Iterator<V> for ShareVertexIterator<'a, T, V> {
    fn next(&mut self) -> Option<V> {
        self.idx.next().map(|idx| self.base.shared_vertex(idx))
    }
}

/// The `IndexedPolygon` trait is used with the `SharedVertex` trait in order to build
/// a mesh. `IndexedPolygon` calculates each polygon face required to build an implementors mesh.
/// each face is always returned in indexed form that points to the correct vertice supplied
/// by the `SharedVertex` trait.
pub trait IndexedPolygon<V> {
    /// return a polygon with indices to the shared vertex
    fn indexed_polygon(&self, i: uint) -> V;

    /// return the number of polygons that are needed to represent this mesh
    fn indexed_polygon_count(&self) -> uint;

    /// create a iterator that will return a polygon for each face in the source mesh
    fn indexed_polygon_iter<'a>(&'a self) -> IndexedPolygonIterator<'a, Self, V> {
        IndexedPolygonIterator {
            base: self,
            idx: range(0, self.indexed_polygon_count())
        }
    }
}

pub struct IndexedPolygonIterator<'a, T, V> {
    base: &'a T,
    idx: Range<uint>
}

impl<'a, T: IndexedPolygon<V>, V> Iterator<V> for IndexedPolygonIterator<'a, T, V> {
    fn next(&mut self) -> Option<V> {
        self.idx.next().map(|idx| self.base.indexed_polygon(idx))
    }
}<commit_msg>fixed building with newest rust version<commit_after>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

use std::iter::Range;

/// The `SharedVertex` trait is meant to be used with the `IndexedPolygon` trait.
/// This trait is meant as a way to calculate the shared vertices that are
/// required to build the implementors mesh.
pub trait SharedVertex<V> {
    /// return the shared vertex at offset `i`
    fn shared_vertex(&self, i: uint) -> V;

    /// return the number of shared vertices required to represent the mesh
    fn shared_vertex_count(&self) -> uint;

    /// create an iterator that returns each shared vertex that is required to
    /// build the mesh.
    fn shared_vertex_iter<'a>(&'a self) -> ShareVertexIterator<'a, Self, V> {
        ShareVertexIterator {
            base: self,
            idx: range(0, self.shared_vertex_count())
        }
    }
}

pub struct ShareVertexIterator<'a, T:'a, V> {
    base: &'a T,
    idx: Range<uint>
}

impl<'a, T: SharedVertex<V>, V> Iterator<V> for ShareVertexIterator<'a, T, V> {
    fn next(&mut self) -> Option<V> {
        self.idx.next().map(|idx| self.base.shared_vertex(idx))
    }
}

/// The `IndexedPolygon` trait is used with the `SharedVertex` trait in order to build
/// a mesh. `IndexedPolygon` calculates each polygon face required to build an implementors mesh.
/// each face is always returned in indexed form that points to the correct vertice supplied
/// by the `SharedVertex` trait.
pub trait IndexedPolygon<V> {
    /// return a polygon with indices to the shared vertex
    fn indexed_polygon(&self, i: uint) -> V;

    /// return the number of polygons that are needed to represent this mesh
    fn indexed_polygon_count(&self) -> uint;

    /// create a iterator that will return a polygon for each face in the source mesh
    fn indexed_polygon_iter<'a>(&'a self) -> IndexedPolygonIterator<'a, Self, V> {
        IndexedPolygonIterator {
            base: self,
            idx: range(0, self.indexed_polygon_count())
        }
    }
}

pub struct IndexedPolygonIterator<'a, T:'a, V> {
    base: &'a T,
    idx: Range<uint>
}

impl<'a, T: IndexedPolygon<V>, V> Iterator<V> for IndexedPolygonIterator<'a, T, V> {
    fn next(&mut self) -> Option<V> {
        self.idx.next().map(|idx| self.base.indexed_polygon(idx))
    }
}<|endoftext|>


<commit_before>use types::{OscPacket, OscType, OscResult, OscMessage, OscMidiMessage, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            read_time_tag(cursor)
        }
        'b' => {
            read_blob(cursor)
        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            let opt_char = try!(cursor.read_u32::<BigEndian>()
                                      .map(char::from_u32)
                                      .map_err(OscError::ByteOrderError));
            match opt_char {
                Some(c) => Ok(OscType::Char(c)),
                None => Err(OscError::BadArg("Argument is not a char!".to_string())),
            }
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<commit_msg>Refactor `read_char` to seperate method<commit_after>use types::{OscPacket, OscType, OscResult, OscMessage, OscMidiMessage, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            read_time_tag(cursor)
        }
        'b' => {
            read_blob(cursor)
        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            read_char(cursor)
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let opt_char = try!(cursor.read_u32::<BigEndian>()
                              .map(char::from_u32)
                              .map_err(OscError::ByteOrderError));
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<|endoftext|>


<commit_before>use crate::encoder;
use crate::errors::OscError;
use crate::types::{
    OscArray, OscBundle, OscColor, OscMessage, OscMidiMessage, OscPacket, OscType, Result,
};

use std::io::{BufRead, Read};
use std::{char, io};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTU size for ethernet
pub const MTU: usize = 1536;

/// Takes an byte slice as argument and returns an
/// OSC packet on success or an `OscError` if the slice
/// does not contain a valid OSC message.
pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    if msg.is_empty() {
        return Err(OscError::BadPacket("Empty packet."));
    }

    match msg[0] as char {
        '/' => decode_message(msg),
        '#' => decode_bundle(msg),
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = read_osc_string(&mut cursor)?;
    let type_tags: String = read_osc_string(&mut cursor)?;

    if type_tags.len() > 1 {
        let args: Vec<OscType> = read_osc_args(&mut cursor, type_tags)?;
        Ok(OscPacket::Message(OscMessage { addr, args }))
    } else {
        Ok(OscPacket::Message(OscMessage { addr, args: vec![] }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let bundle_tag = read_osc_string(&mut cursor)?;
    if bundle_tag != "#bundle" {
        return Err(OscError::BadBundle(format!(
            "Wrong bundle specifier: {}",
            bundle_tag
        )));
    }

    let time_tag = read_time_tag(&mut cursor)?;

    let mut bundle: Vec<OscPacket> = Vec::new();

    // Empty bundle
    if msg.len() == cursor.position() as usize {
        return Ok(OscPacket::Bundle(OscBundle {
            timetag: time_tag,
            content: bundle,
        }))
    }

    let mut elem_size = read_bundle_element_size(&mut cursor)?;

    while msg.len() >= (cursor.position() as usize) + elem_size {
        let packet = read_bundle_element_content(&mut cursor, elem_size)?;
        bundle.push(packet);

        if msg.len() == cursor.position() as usize {
            break;
        }

        elem_size = read_bundle_element_size(&mut cursor)?;
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_bundle_element_size(cursor: &mut io::Cursor<&[u8]>) -> Result<usize> {
    cursor
        .read_u32::<BigEndian>()
        .map(|size| size as usize)
        .map_err(OscError::ReadError)
}

fn read_bundle_element_content(cursor: &mut io::Cursor<&[u8]>, elem_size: usize) -> Result<OscPacket> {
    let mut buf: Vec<u8> = Vec::with_capacity(elem_size);

    let mut handle = cursor.take(elem_size as u64);

    let cnt = handle.read_to_end(&mut buf).map_err(OscError::ReadError)?;

    if cnt == elem_size {
        decode(&buf)
    } else {
        Err(OscError::BadBundle(
            "Bundle shorter than expected!".to_string(),
        ))
    }
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    // ignore returned byte count
    cursor
        .read_until(0, &mut str_buf)
        .map_err(OscError::ReadError)?;
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(OscError::StringError)
        .map(|s| s.trim_matches(0u8 as char).to_string())
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars().skip(1).collect();

    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    let mut stack: Vec<Vec<OscType>> = Vec::new();
    for tag in type_tags {
        if tag == '[' {
            // array start: save current frame and start a new frame
            // for the array's content
            stack.push(args);
            args = Vec::new();
        } else if tag == ']' {
            // found the end of the current array:
            // create array object from current frame and step one level up
            let array = OscType::Array(OscArray { content: args });
            match stack.pop() {
                Some(stashed) => args = stashed,
                None => return Err(OscError::BadMessage("Encountered ] outside array")),
            }
            args.push(array);
        } else {
            let arg: OscType = read_osc_arg(cursor, tag)?;
            args.push(arg);
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => cursor
            .read_f32::<BigEndian>()
            .map(OscType::Float)
            .map_err(OscError::ReadError),
        'd' => cursor
            .read_f64::<BigEndian>()
            .map(OscType::Double)
            .map_err(OscError::ReadError),
        'i' => cursor
            .read_i32::<BigEndian>()
            .map(OscType::Int)
            .map_err(OscError::ReadError),
        'h' => cursor
            .read_i64::<BigEndian>()
            .map(OscType::Long)
            .map_err(OscError::ReadError),
        's' => read_osc_string(cursor).map(OscType::String),
        't' => read_time_tag(cursor).map(OscType::Time),
        'b' => read_blob(cursor),
        'r' => read_osc_color(cursor),
        'T' => Ok(true.into()),
        'F' => Ok(false.into()),
        'N' => Ok(OscType::Nil),
        'I' => Ok(OscType::Inf),
        'c' => read_char(cursor),
        'm' => read_midi_message(cursor),
        _ => Err(OscError::BadArg(format!(
            "Type tag \"{}\" is not implemented!",
            tag
        ))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = cursor
        .read_u32::<BigEndian>()
        .map(char::from_u32)
        .map_err(OscError::ReadError)?;
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = cursor
        .read_u32::<BigEndian>()
        .map_err(OscError::ReadError)? as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    cursor
        .take(size as u64)
        .read_to_end(&mut byte_buf)
        .map_err(OscError::ReadError)?;

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<(u32, u32)> {
    let date = cursor
        .read_u32::<BigEndian>()
        .map_err(OscError::ReadError)?;
    let frac = cursor
        .read_u32::<BigEndian>()
        .map_err(OscError::ReadError)?;

    Ok((date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    cursor
        .take(4)
        .read_to_end(&mut buf)
        .map_err(OscError::ReadError)?;

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))
}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    cursor
        .take(4)
        .read_to_end(&mut buf)
        .map_err(OscError::ReadError)?;

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(encoder::pad(pos));
}
<commit_msg>cargo fmt<commit_after>use crate::encoder;
use crate::errors::OscError;
use crate::types::{
    OscArray, OscBundle, OscColor, OscMessage, OscMidiMessage, OscPacket, OscType, Result,
};

use std::io::{BufRead, Read};
use std::{char, io};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTU size for ethernet
pub const MTU: usize = 1536;

/// Takes an byte slice as argument and returns an
/// OSC packet on success or an `OscError` if the slice
/// does not contain a valid OSC message.
pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    if msg.is_empty() {
        return Err(OscError::BadPacket("Empty packet."));
    }

    match msg[0] as char {
        '/' => decode_message(msg),
        '#' => decode_bundle(msg),
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = read_osc_string(&mut cursor)?;
    let type_tags: String = read_osc_string(&mut cursor)?;

    if type_tags.len() > 1 {
        let args: Vec<OscType> = read_osc_args(&mut cursor, type_tags)?;
        Ok(OscPacket::Message(OscMessage { addr, args }))
    } else {
        Ok(OscPacket::Message(OscMessage { addr, args: vec![] }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let bundle_tag = read_osc_string(&mut cursor)?;
    if bundle_tag != "#bundle" {
        return Err(OscError::BadBundle(format!(
            "Wrong bundle specifier: {}",
            bundle_tag
        )));
    }

    let time_tag = read_time_tag(&mut cursor)?;

    let mut bundle: Vec<OscPacket> = Vec::new();

    // Empty bundle
    if msg.len() == cursor.position() as usize {
        return Ok(OscPacket::Bundle(OscBundle {
            timetag: time_tag,
            content: bundle,
        }));
    }

    let mut elem_size = read_bundle_element_size(&mut cursor)?;

    while msg.len() >= (cursor.position() as usize) + elem_size {
        let packet = read_bundle_element_content(&mut cursor, elem_size)?;
        bundle.push(packet);

        if msg.len() == cursor.position() as usize {
            break;
        }

        elem_size = read_bundle_element_size(&mut cursor)?;
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_bundle_element_size(cursor: &mut io::Cursor<&[u8]>) -> Result<usize> {
    cursor
        .read_u32::<BigEndian>()
        .map(|size| size as usize)
        .map_err(OscError::ReadError)
}

fn read_bundle_element_content(
    cursor: &mut io::Cursor<&[u8]>,
    elem_size: usize,
) -> Result<OscPacket> {
    let mut buf: Vec<u8> = Vec::with_capacity(elem_size);

    let mut handle = cursor.take(elem_size as u64);

    let cnt = handle.read_to_end(&mut buf).map_err(OscError::ReadError)?;

    if cnt == elem_size {
        decode(&buf)
    } else {
        Err(OscError::BadBundle(
            "Bundle shorter than expected!".to_string(),
        ))
    }
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    // ignore returned byte count
    cursor
        .read_until(0, &mut str_buf)
        .map_err(OscError::ReadError)?;
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(OscError::StringError)
        .map(|s| s.trim_matches(0u8 as char).to_string())
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars().skip(1).collect();

    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    let mut stack: Vec<Vec<OscType>> = Vec::new();
    for tag in type_tags {
        if tag == '[' {
            // array start: save current frame and start a new frame
            // for the array's content
            stack.push(args);
            args = Vec::new();
        } else if tag == ']' {
            // found the end of the current array:
            // create array object from current frame and step one level up
            let array = OscType::Array(OscArray { content: args });
            match stack.pop() {
                Some(stashed) => args = stashed,
                None => return Err(OscError::BadMessage("Encountered ] outside array")),
            }
            args.push(array);
        } else {
            let arg: OscType = read_osc_arg(cursor, tag)?;
            args.push(arg);
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => cursor
            .read_f32::<BigEndian>()
            .map(OscType::Float)
            .map_err(OscError::ReadError),
        'd' => cursor
            .read_f64::<BigEndian>()
            .map(OscType::Double)
            .map_err(OscError::ReadError),
        'i' => cursor
            .read_i32::<BigEndian>()
            .map(OscType::Int)
            .map_err(OscError::ReadError),
        'h' => cursor
            .read_i64::<BigEndian>()
            .map(OscType::Long)
            .map_err(OscError::ReadError),
        's' => read_osc_string(cursor).map(OscType::String),
        't' => read_time_tag(cursor).map(OscType::Time),
        'b' => read_blob(cursor),
        'r' => read_osc_color(cursor),
        'T' => Ok(true.into()),
        'F' => Ok(false.into()),
        'N' => Ok(OscType::Nil),
        'I' => Ok(OscType::Inf),
        'c' => read_char(cursor),
        'm' => read_midi_message(cursor),
        _ => Err(OscError::BadArg(format!(
            "Type tag \"{}\" is not implemented!",
            tag
        ))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = cursor
        .read_u32::<BigEndian>()
        .map(char::from_u32)
        .map_err(OscError::ReadError)?;
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = cursor
        .read_u32::<BigEndian>()
        .map_err(OscError::ReadError)? as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    cursor
        .take(size as u64)
        .read_to_end(&mut byte_buf)
        .map_err(OscError::ReadError)?;

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<(u32, u32)> {
    let date = cursor
        .read_u32::<BigEndian>()
        .map_err(OscError::ReadError)?;
    let frac = cursor
        .read_u32::<BigEndian>()
        .map_err(OscError::ReadError)?;

    Ok((date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    cursor
        .take(4)
        .read_to_end(&mut buf)
        .map_err(OscError::ReadError)?;

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))
}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    cursor
        .take(4)
        .read_to_end(&mut buf)
        .map_err(OscError::ReadError)?;

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(encoder::pad(pos));
}
<|endoftext|>


<commit_before>use ideal::{Id, IdVec};
use ideal::vec::IdsIter;
use point::Point;
use cgmath::{Point3, EuclideanSpace};

pub struct VertexData {
    point: Point,
    edges: Vec<Edge>,
    faces: Vec<Face>,
}

pub struct EdgeData {
    vertices: (Vertex, Vertex),
    faces: (Face, Face),
}

pub struct FaceData {
    point: Point,
    vertices: Vec<Vertex>,
    edges: Vec<Edge>,
}

#[derive(Default)]
pub struct Diagram {
    vertices: IdVec<VertexData>,
    edges: IdVec<EdgeData>,
    faces: IdVec<FaceData>,
}

impl Diagram {
    pub fn add_vertex(&mut self, point: Point, faces: &[Face]) -> Vertex {
        let vertex = self.vertices.push(VertexData {
            point: point,
            edges: Vec::new(),
            faces: Vec::from(faces),
        });
        for &face in faces {
            self.faces[face].vertices.push(vertex);
        }
        vertex
    }

    pub fn vertices(&self) -> IdsIter<VertexData> {
        self.vertices.ids()
    }

    pub fn clear_vertices(&mut self) {
        self.vertices.clear()
    }

    pub fn vertex_point(&self, vertex: Vertex) -> &Point {
        &self.vertices[vertex].point
    }

    pub fn vertex_edges(&self, vertex: Vertex) -> &[Edge] {
        &self.vertices[vertex].edges
    }

    pub fn vertex_faces(&self, vertex: Vertex) -> &[Face] {
        &self.vertices[vertex].faces
    }

    pub fn vertex_neighbors(&self, vertex: Vertex) -> Vec<Vertex> {
        self.vertex_edges(vertex)
            .iter()
            .map(|&edge| self.other_edge_vertex(edge, vertex))
            .collect()
    }

    pub fn add_edge(&mut self, vertex0: Vertex, vertex1: Vertex) -> Edge {
        self.edges.push(EdgeData {
            vertices: (vertex0, vertex1),
            faces: (Face::invalid(), Face::invalid())
        })
    }

    pub fn edges(&self) -> IdsIter<EdgeData> {
        self.edges.ids()
    }

    pub fn clear_edges(&mut self) {
        self.edges.clear();
    }

    pub fn edge_vertices(&self, edge: Edge) -> (Vertex, Vertex) {
        self.edges[edge].vertices
    }

    pub fn set_edge_faces(&mut self, edge: Edge, face0: Face, face1: Face) {
        self.edges[edge].faces = (face0, face1)
    }

    pub fn other_edge_vertex(&self, edge: Edge, vertex: Vertex) -> Vertex {
        let (vertex0, vertex1) = self.edge_vertices(edge);
        if vertex == vertex0 {
            vertex1
        } else if vertex == vertex1 {
            vertex0
        } else {
            Vertex::invalid()
        }
    }

    pub fn add_face(&mut self, point: Point) -> Face {
        self.faces.push(FaceData {
            point: point,
            vertices: Vec::new(),
            edges: Vec::new(),
        })
    }

    pub fn faces(&self) -> IdsIter<FaceData> {
        self.faces.ids()
    }

    pub fn reset_faces(&mut self) {
        for face in self.faces() {
            let face_points: Vec<_> = self
                .face_vertices(face)
                .iter()
                .map(|&vertex| self.vertex_point(vertex).position())
                .collect();
            let p = Point3::centroid(&face_points);
            self.faces[face].point = Point::from_cartesian(p.x, p.y, p.z);
        }
    }

    pub fn face_point(&self, face: Face) -> &Point {
        &self.faces[face].point
    }

    pub fn face_vertices(&self, face: Face) -> &[Vertex] {
        &self.faces[face].vertices
    }

    pub fn face_edges(&self, face: Face) -> &[Edge] {
        &self.faces[face].edges
    }
}

pub type Vertex = Id<VertexData>;
pub type Edge = Id<EdgeData>;
pub type Face = Id<FaceData>;<commit_msg>Diagram::edge_faces<commit_after>use ideal::{Id, IdVec};
use ideal::vec::IdsIter;
use point::Point;
use cgmath::{Point3, EuclideanSpace};

pub struct VertexData {
    point: Point,
    edges: Vec<Edge>,
    faces: Vec<Face>,
}

pub struct EdgeData {
    vertices: (Vertex, Vertex),
    faces: (Face, Face),
}

pub struct FaceData {
    point: Point,
    vertices: Vec<Vertex>,
    edges: Vec<Edge>,
}

#[derive(Default)]
pub struct Diagram {
    vertices: IdVec<VertexData>,
    edges: IdVec<EdgeData>,
    faces: IdVec<FaceData>,
}

impl Diagram {
    pub fn add_vertex(&mut self, point: Point, faces: &[Face]) -> Vertex {
        let vertex = self.vertices.push(VertexData {
            point: point,
            edges: Vec::new(),
            faces: Vec::from(faces),
        });
        for &face in faces {
            self.faces[face].vertices.push(vertex);
        }
        vertex
    }

    pub fn vertices(&self) -> IdsIter<VertexData> {
        self.vertices.ids()
    }

    pub fn clear_vertices(&mut self) {
        self.vertices.clear()
    }

    pub fn vertex_point(&self, vertex: Vertex) -> &Point {
        &self.vertices[vertex].point
    }

    pub fn vertex_edges(&self, vertex: Vertex) -> &[Edge] {
        &self.vertices[vertex].edges
    }

    pub fn vertex_faces(&self, vertex: Vertex) -> &[Face] {
        &self.vertices[vertex].faces
    }

    pub fn vertex_neighbors(&self, vertex: Vertex) -> Vec<Vertex> {
        self.vertex_edges(vertex)
            .iter()
            .map(|&edge| self.other_edge_vertex(edge, vertex))
            .collect()
    }

    pub fn add_edge(&mut self, vertex0: Vertex, vertex1: Vertex) -> Edge {
        self.edges.push(EdgeData {
            vertices: (vertex0, vertex1),
            faces: (Face::invalid(), Face::invalid())
        })
    }

    pub fn edges(&self) -> IdsIter<EdgeData> {
        self.edges.ids()
    }

    pub fn clear_edges(&mut self) {
        self.edges.clear();
    }

    pub fn edge_vertices(&self, edge: Edge) -> (Vertex, Vertex) {
        self.edges[edge].vertices
    }

    pub fn edge_faces(&self, edge: Edge) -> (Face, Face) {
        self.edges[edge].faces
    }

    pub fn set_edge_faces(&mut self, edge: Edge, face0: Face, face1: Face) {
        self.edges[edge].faces = (face0, face1)
    }

    pub fn other_edge_vertex(&self, edge: Edge, vertex: Vertex) -> Vertex {
        let (vertex0, vertex1) = self.edge_vertices(edge);
        if vertex == vertex0 {
            vertex1
        } else if vertex == vertex1 {
            vertex0
        } else {
            Vertex::invalid()
        }
    }

    pub fn add_face(&mut self, point: Point) -> Face {
        self.faces.push(FaceData {
            point: point,
            vertices: Vec::new(),
            edges: Vec::new(),
        })
    }

    pub fn faces(&self) -> IdsIter<FaceData> {
        self.faces.ids()
    }

    pub fn reset_faces(&mut self) {
        for face in self.faces() {
            let face_points: Vec<_> = self
                .face_vertices(face)
                .iter()
                .map(|&vertex| self.vertex_point(vertex).position())
                .collect();
            let p = Point3::centroid(&face_points);
            self.faces[face].point = Point::from_cartesian(p.x, p.y, p.z);
        }
    }

    pub fn face_point(&self, face: Face) -> &Point {
        &self.faces[face].point
    }

    pub fn face_vertices(&self, face: Face) -> &[Vertex] {
        &self.faces[face].vertices
    }

    pub fn face_edges(&self, face: Face) -> &[Edge] {
        &self.faces[face].edges
    }
}

pub type Vertex = Id<VertexData>;
pub type Edge = Id<EdgeData>;
pub type Face = Id<FaceData>;<|endoftext|>