<commit_before>use std::fmt;
use std::fs::File;
use std::io::Read;

const MEM_SIZE: usize = 4096;
const ROM_ADDR: usize = 0x200;

#[derive(Debug, Default)]
struct Registers {
    reg_gp: [u8; 16],
    reg_i: u16,

    reg_delay: u8,
    reg_sound: u8,

    reg_pc: u16,
    reg_sp: u8,

    stack: [u16; 16]
}

impl Registers {
    fn new() -> Registers {
        let mut reg = Registers::default();
        reg.reg_pc = (ROM_ADDR as u16);
        reg
    }

    fn write_register(&mut self, target_reg: u8, data_value: u8) {
        self.reg_gp[target_reg as usize] = data_value;
        println!("Loaded value {:#x} into register V{:x}", data_value, target_reg)
    }
}

#[derive(Default, Debug)]
struct Keypad {
    keys: [u8; 16],
}

struct Memory {
    mem: [u8; MEM_SIZE],
}

impl Memory {
    fn store_program_data(&mut self, rom: File) {
        let mut last_stored_addr = ROM_ADDR;

        for byte in rom.bytes() {
            match byte {
                Ok(b) => {
                    self.mem[last_stored_addr] = b;
                    last_stored_addr += 2;
                },
                Err(e) => panic!("Some error {:?} occurred while storing program data.", e)
            }
        }
    }
}

impl fmt::Debug for Memory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "First opcode: {:#x} {:#x}", self.mem[0x200], self.mem[0x202])
    }
}

impl Default for Memory {
    fn default() -> Memory {
        Memory {
            mem: [0u8; MEM_SIZE]
        }
    }
}

#[derive(Debug)]
pub struct Chip8 {
    reg: Registers,
    mem: Memory,
    keys: Keypad
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            reg: Registers::new(),
            mem: Memory::default(),
            keys: Keypad::default()
        }
    }

    pub fn run(&mut self) {
        loop {
            let instruction = self.read_word();
            self.process_instruction(instruction);
        }
    }

    pub fn store_program_data(&mut self, rom: File) {
        self.mem.store_program_data(rom);
    }

    fn read_word(&mut self) -> u16 {
        let instruction_high_order = (self.mem.mem[self.reg.reg_pc as usize] as u16) << 8;
        let instruction_low_order = self.mem.mem[(self.reg.reg_pc + 2) as usize] as u16;

        let instruction = instruction_high_order | instruction_low_order;
        println!("Instruction: {:#x}", instruction);

        self.reg.reg_pc += 4;
        instruction
    }

    fn process_instruction(&mut self, instruction: u16) {
        let op_type: u8 = ((instruction >> 12) & 0xff) as u8;

        match op_type {
            0x6 => {
                let target_reg = ((instruction >> 8) & 0x0f) as u8;
                let data_value = (instruction & 0x00ff) as u8;
                self.reg.write_register(target_reg, data_value);
            },
            _ => {
                println!("Chip8 status at end time: {:#?}", self);
                panic!("Unsupported op type: {:#x}", op_type)
            }
        }
    }
}<commit_msg>implemented a number of new opcodes, now seems to have hit a loop which is likely a menu of some kind. display implementation will have to be next<commit_after>use std::fmt;
use std::fs::File;
use std::io::Read;
use std::num::Wrapping;

const MEM_SIZE: usize = 4096;
const ROM_ADDR: usize = 0x200;

#[derive(Debug, Default)]
struct Registers {
    reg_gp: [u8; 16],
    reg_i: u16,

    reg_delay: u8,
    reg_sound: u8,

    reg_pc: u16,
    reg_sp: u8,

    stack: [u16; 16]
}

impl Registers {
    fn new() -> Registers {
        let mut reg = Registers::default();
        reg.reg_pc = (ROM_ADDR as u16);
        reg
    }

    fn write_register(&mut self, target_reg: u8, data_value: u8) {
        self.reg_gp[target_reg as usize] = data_value;
        println!("Loaded value {:#x} into register V{:x}", data_value, target_reg)
    }

    fn write_register_i(&mut self, data_value: u16) {
        self.reg_i = data_value;
        println!("Loaded value {:#x} into I register", data_value);
    }

    fn read_register(&self, target_reg: u8) -> u8 {
        self.reg_gp[target_reg as usize]
    }

    fn jump_to_address(&mut self, addr: u16, jump_type: JumpType) {
        match jump_type {
            JumpType::SUBROUTINE => {
                self.stack[self.reg_sp as usize] = self.reg_pc;
                self.reg_sp += 1;
            }
            JumpType::NORMAL => {}
        }
        println!("Jumping to address {:#x}", addr);
        self.reg_pc = addr;
    }

    fn return_from_subroutine(&mut self) {
        self.reg_pc = self.stack[self.reg_sp as usize];
        self.reg_sp -= 1;
    }
}

#[derive(Default, Debug)]
struct Keypad {
    keys: [u8; 16],
}

struct Memory {
    mem: [u8; MEM_SIZE],
}

impl Memory {
    fn store_program_data(&mut self, rom: File) {
        let mut last_stored_addr = ROM_ADDR;

        for byte in rom.bytes() {
            match byte {
                Ok(b) => {
                    self.mem[last_stored_addr] = b;
                    last_stored_addr += 1;
                },
                Err(e) => panic!("Some error {:?} occurred while storing program data.", e)
            }
        }
    }

    fn display_pong_rom(&self) {
        let mut addr = ROM_ADDR;
        for i in 1..100 {
            println!("{:#x}", self.mem[addr]);
            addr += 1;
        }
    }
}

impl fmt::Debug for Memory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TODO implement debug output for memory")
    }
}

impl Default for Memory {
    fn default() -> Memory {
        Memory {
            mem: [0u8; MEM_SIZE]
        }
    }
}

#[derive(Debug)]
pub struct Chip8 {
    reg: Registers,
    mem: Memory,
    keys: Keypad
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            reg: Registers::new(),
            mem: Memory::default(),
            keys: Keypad::default()
        }
    }

    pub fn run(&mut self) {
        loop {
            let instruction = self.read_word();
            self.process_instruction(instruction);
        }
    }

    pub fn store_program_data(&mut self, rom: File) {
        self.mem.store_program_data(rom);
    }

    pub fn debug_pong_rom(&self) {
        self.mem.display_pong_rom();
    }

    fn read_word(&mut self) -> u16 {
        let instruction_high_order = (self.mem.mem[self.reg.reg_pc as usize] as u16) << 8;
        let instruction_low_order = self.mem.mem[(self.reg.reg_pc + 2) as usize] as u16;

        let instruction = instruction_high_order | instruction_low_order;
        println!("Instruction: {:#x}", instruction);

        self.reg.reg_pc += 4;
        instruction
    }

    fn process_instruction(&mut self, instruction: u16) {
        let op_type: u8 = ((instruction >> 12) & 0xff) as u8;

        match op_type {
            0x0 => {
                //we will ignore the 0nnn opcode used for jumping to machine code routines
                let operation = instruction & 0x00ff;
                if(operation == 0xe0) {
                    //TODO clear the display
                } else if (operation == 0xee) {
                    self.reg.return_from_subroutine();
                }
            },
            0x1 => {
                let jump_addr = instruction & 0x0fff;
                self.reg.jump_to_address(jump_addr, JumpType::NORMAL);
            },
            0x2 => {
                let subroutine_addr = instruction & 0x0fff;
                self.reg.jump_to_address(subroutine_addr, JumpType::SUBROUTINE);
            },
            0x6 => {
                let target_reg = ((instruction >> 8) & 0x0f) as u8;
                let data_value = (instruction & 0x00ff) as u8;
                self.reg.write_register(target_reg, data_value);
            },
            0x7 => {
                let target_reg = ((instruction >> 8) & 0x0f) as u8;
                let immediate_value = (instruction & 0x00ff) as u8;
                let reg_value = self.reg.read_register(target_reg);
                let data_value = immediate_value.wrapping_add(reg_value);
                println!("Addition");
                self.reg.write_register(target_reg, data_value);
            },
            0x8 => {
                let reg_one = ((instruction >> 8) & 0x0f) as u8;
                let reg_two = ((instruction >> 4) & 0x0f) as u8;
                let operation = (instruction & 0x000f) as u8;
                match operation {
                    0 => {
                        let data_value = self.reg.read_register(reg_two);
                        self.reg.write_register(reg_one, data_value);
                    },
                    1 => {
                        let reg_one_value = self.reg.read_register(reg_one);
                        let reg_two_value = self.reg.read_register(reg_two);
                        let data_value = reg_one_value | reg_two_value;
                        self.reg.write_register(reg_one, data_value);
                    },
                    2 => {
                        let reg_one_value = self.reg.read_register(reg_one);
                        let reg_two_value = self.reg.read_register(reg_two);
                        let data_value = reg_one_value & reg_two_value;
                        self.reg.write_register(reg_one, data_value);
                    },
                    3 => {
                        let reg_one_value = self.reg.read_register(reg_one);
                        let reg_two_value = self.reg.read_register(reg_two);
                        if(reg_two_value > reg_one_value) {
                            self.reg.write_register(0x0f, 0x01);
                        }
                        let data_value = reg_two_value - reg_one_value;
                        self.reg.write_register(reg_one, data_value);
                    },
                    4 => {

                    },
                    5 => {

                    },
                    6 => {

                    },
                    7 => {

                    },
                    0xe => {

                    },
                    _ => panic!("Unrecognized opcode: {:#x}", instruction)
                }
            },
            0xa => {
                let data_value = instruction & 0x0fff;
                self.reg.write_register_i(data_value);
            },
            0xb => {
                let initial_addr = instruction & 0x0fff;
                let offset = self.reg.read_register(0) as u16;
                self.reg.jump_to_address(initial_addr + offset, JumpType::NORMAL);
            },
            0xd => {
                //TODO: display/sprites
                println!("Display operation");
            },
            0xe => {
                //TODO: input checks
                println!("Input checks");
            },
            _ => {
                println!("Chip8 status at end time: {:#?}", self);
                panic!("Unsupported op type: {:#x}", op_type)
            }
        }
    }
}

enum JumpType {
    NORMAL, SUBROUTINE
}<|endoftext|>


<commit_before>//! Database operations

use postgres::{Connection, SslMode};
use postgres::error::ConnectError;

const DB_CONNECTION_STR: &'static str = "postgresql://cratesfyi@localhost";

/// Connects to database
pub fn connect_db() -> Result<Connection, ConnectError> {
    Connection::connect(DB_CONNECTION_STR, SslMode::None)
}

/// Creates database tables
pub fn create_tables(conn: &Connection) {
    let tables = [
        "CREATE TABLE crates ( \
            id SERIAL, \
            name text UNIQUE NOT NULL, \
            latest_version_id INT DEFAULT 0, \
            github_stars INT DEFAULT 0, \
            badges JSON, \
            issues JSON, \
            downloads_total INT DEFAULT 0 \
        )",
        "CREATE TABLE releases ( \
            id SERIAL, \
            crate_id INT NOT NULL, \
            version TEXT, \
            release_time TIMESTAMP, \
            dependencies JSON, \
            yanked BOOL DEFAULT FALSE, \
            build_status INT DEFAULT 0, \
            rustdoc_status INT DEFAULT 0, \
            test_status INT DEFAULT 0, \
            license TEXT, \
            repository_url TEXT, \
            homepage_url TEXT, \
            description TEXT, \
            description_long TEXT, \
            readme TEXT, \
            authors JSON, \
            keywords JSON, \
            downloads INT DEFAULT 0, \
            UNIQUE (crate_id, version) \
        )",
        "CREATE TABLE authors ( \
            id SERIAL, \
            name TEXT NOT NULL, \
            email TEXT, \
            slug TEXT UNIQUE NOT NULL, \
            github_url TEXT, \
            github_profile_picture_url TEXT \
        )",
        "CREATE TABLE author_rels ( \
            cid INT, \
            aid INT, \
            UNIQUE(cid, aid) \
        )",
        "CREATE TABLE keywords ( \
            id SERIAL, \
            name TEXT, \
            slug TEXT NOT NULL UNIQUE \
        )",
        "CREATE TABLE keyword_rels ( \
            cid INT, \
            kid INT, \
            UNIQUE(cid, kid) \
        )"
    ];

    for table in tables.into_iter() {
        if let Err(e) = conn.execute(table, &[]) {
            println!("{}", e);
        }
    }
}

#[test]
#[ignore]
fn test_connect_db() {
    let conn = connect_db();
    assert!(conn.is_ok());
}
<commit_msg>Update database schema<commit_after>//! Database operations

use postgres::{Connection, SslMode};
use postgres::error::ConnectError;

const DB_CONNECTION_STR: &'static str = "postgresql://cratesfyi@localhost";

/// Connects to database
pub fn connect_db() -> Result<Connection, ConnectError> {
    Connection::connect(DB_CONNECTION_STR, SslMode::None)
}

/// Creates database tables
pub fn create_tables(conn: &Connection) {
    let queries = [
        "CREATE TABLE crates ( \
            id SERIAL, \
            name text UNIQUE NOT NULL, \
            latest_version_id INT DEFAULT 0, \
            github_stars INT DEFAULT 0, \
            badges JSON, \
            issues JSON, \
            downloads_total INT DEFAULT 0 \
        )",
        "CREATE TABLE releases ( \
            id SERIAL, \
            crate_id INT NOT NULL, \
            version TEXT, \
            release_time TIMESTAMP, \
            dependencies JSON, \
            yanked BOOL DEFAULT FALSE, \
            build_status INT DEFAULT 0, \
            rustdoc_status INT DEFAULT 0, \
            test_status INT DEFAULT 0, \
            license TEXT, \
            repository_url TEXT, \
            homepage_url TEXT, \
            description TEXT, \
            description_long TEXT, \
            readme TEXT, \
            authors JSON, \
            keywords JSON, \
            have_examples BOOL DEFAULT FALSE, \
            downloads INT DEFAULT 0, \
            UNIQUE (crate_id, version) \
        )",
        "CREATE TABLE authors ( \
            id SERIAL, \
            name TEXT NOT NULL, \
            email TEXT, \
            slug TEXT UNIQUE NOT NULL \
        )",
        "CREATE TABLE author_rels ( \
            rid INT, \
            aid INT, \
            UNIQUE(rid, aid) \
        )",
        "CREATE TABLE keywords ( \
            id SERIAL, \
            name TEXT, \
            slug TEXT NOT NULL UNIQUE \
        )",
        "CREATE TABLE keyword_rels ( \
            rid INT, \
            kid INT, \
            UNIQUE(rid, kid) \
        )",
        "CREATE TABLE owners ( \
            id SERIAL, \
            login TEXT NOT NULL UNIQUE, \
            slug TEXT NOT NULL UNIQUE, \
            avatar TEXT, \
            name TEXT, \
            email TEXT \
        )",
        "CREATE TABLE owner_rels ( \
            cid INT, \
            oid INT, \
            UNIQUE(cid, oid) \
        )"
    ];

    for query in queries.into_iter() {
        if let Err(e) = conn.execute(query, &[]) {
            println!("{}", e);
        }
    }
}

#[test]
#[ignore]
fn test_connect_db() {
    let conn = connect_db();
    assert!(conn.is_ok());
}
<|endoftext|>


<commit_before>use crate::spec::{LinkerFlavor, Target, TargetResult};

pub fn target() -> TargetResult {
    let mut base = super::linux_base::opts();
    base.cpu = "x86-64".to_string();
    base.max_atomic_width = Some(64);
    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
    // BUG: temporarily workaround #59674
    base.stack_probes = false;
    base.has_elf_tls = false;
    // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
    // breaks code gen. See LLVM bug 36743
    base.needs_plt = true;

    Ok(Target {
        llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128".to_string(),
        arch: "x86_64".to_string(),
        target_os: "linux".to_string(),
        target_env: "gnu".to_string(),
        target_vendor: "unknown".to_string(),
        linker_flavor: LinkerFlavor::Gcc,
        options: base,
    })
}
<commit_msg>Revert "Disable stack probing for gnux32."<commit_after>use crate::spec::{LinkerFlavor, Target, TargetResult};

pub fn target() -> TargetResult {
    let mut base = super::linux_base::opts();
    base.cpu = "x86-64".to_string();
    base.max_atomic_width = Some(64);
    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
    base.stack_probes = true;
    base.has_elf_tls = false;
    // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
    // breaks code gen. See LLVM bug 36743
    base.needs_plt = true;

    Ok(Target {
        llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128".to_string(),
        arch: "x86_64".to_string(),
        target_os: "linux".to_string(),
        target_env: "gnu".to_string(),
        target_vendor: "unknown".to_string(),
        linker_flavor: LinkerFlavor::Gcc,
        options: base,
    })
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate fuse;
extern crate time;

use self::fuse::{Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory, ReplyOpen,
                 ReplyEmpty, FileAttr, FileType};
use self::time::Timespec;
use std::collections::HashMap;
use std::convert::AsRef;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io::{Read, Seek, SeekFrom};
use std::io::{Result, Error, ErrorKind};
use std::iter;
use std::path::{Path, PathBuf};
use std::vec::Vec;
use std::rc::Rc;

use physical;

macro_rules! error_with_log {
    ($reply:expr, $e:expr) => {{
        error!("{}:{}: {:?}", file!(), line!(), $e);
        $reply.error(to_cerr($e))
    }}
}

// TODO: configurable?
const TTL: Timespec = Timespec { sec: 1, nsec: 0 };

pub trait SeekableRead: Seek + Read {}
impl<T: Seek + Read> SeekableRead for T {}

pub enum Entry {
    File(Box<File>),
    Dir(Box<Dir>),
}

impl Entry {
    pub fn getattr(&self, ino: u64) -> Result<FileAttr> {
        let attr = match self {
            &Entry::File(ref f) => f.getattr(),
            &Entry::Dir(ref d) => d.getattr(),
        };
        attr.map(|mut a| {
            a.ino = ino;
            a
        })
    }
    pub fn name(&self) -> &OsStr {
        match self {
            &Entry::File(ref f) => f.name(),
            &Entry::Dir(ref d) => d.name(),
        }
    }
    pub fn file_type(&self, ino: u64) -> Result<FileType> {
        self.getattr(ino).map(|a| a.kind)
    }
}

pub trait File {
    fn getattr(&self) -> Result<FileAttr>;
    fn open(&self) -> Result<Box<SeekableRead>>;
    fn name(&self) -> &OsStr;
}

pub trait Dir {
    fn open(&self) -> Result<Box<Iterator<Item = Result<Entry>>>>;
    fn lookup(&self, name: &OsStr) -> Result<Entry>;
    fn getattr(&self) -> Result<FileAttr>;
    fn name(&self) -> &OsStr;
}

fn to_cerr(e: Error) -> libc::c_int {
    match e.raw_os_error() {
        Some(raw) => raw,
        None => libc::EIO,
    }
}

struct InodeReserver {
    inode: u64,
}

impl InodeReserver {
    fn inode(&self) -> u64 {
        return self.inode;
    }
}

struct EntryHolder {
    inode: u64,
    inode_to_entry: HashMap<u64, Entry>,
    path_to_inode: HashMap<(u64, OsString), u64>,
}

impl EntryHolder {
    fn new() -> EntryHolder {
        EntryHolder {
            inode: 0,
            inode_to_entry: HashMap::new(),
            path_to_inode: HashMap::new(),
        }
    }
    fn get_by_path(&self, parent: u64, name: &OsStr) -> Option<(u64, &Entry)> {
        self.path_to_inode
            .get(&(parent, name.to_os_string()))
            .and_then(|ino| self.inode_to_entry.get(ino).map(|e| (*ino, e)))
    }
    fn reserve_inode(&mut self) -> InodeReserver {
        let i = self.inode;
        self.inode += 1;
        InodeReserver { inode: i }
    }
    fn register_with(&mut self, parent: u64, ent: Entry, ir: InodeReserver) {
        debug!("register {:?} with {}", ent.name(), ir.inode);
        self.path_to_inode.insert(
            (parent, ent.name().to_os_string()),
            ir.inode,
        );
        self.inode_to_entry.insert(ir.inode, ent);
    }
    fn register_root(&mut self, root: Entry) {
        self.inode = 2; // next to root (1)
        self.register_with(0, root, InodeReserver { inode: 1 })
    }
    fn get_by_inode(&self, ino: u64) -> Option<&Entry> {
        self.inode_to_entry.get(&ino)
    }
}

struct HandlerHolder {
    fh: u64, // fh counter
    file_handlers: HashMap<u64, Box<SeekableRead>>,
    dir_handlers: HashMap<u64, iter::Peekable<Box<Iterator<Item = Result<Entry>>>>>,
}

impl HandlerHolder {
    fn new() -> HandlerHolder {
        HandlerHolder {
            fh: 0,
            file_handlers: HashMap::new(),
            dir_handlers: HashMap::new(),
        }
    }
    fn register_file(&mut self, r: Box<SeekableRead>) -> u64 {
        let fh = self.fh;
        self.fh += 1;
        self.file_handlers.insert(fh, r);
        return fh;
    }
    fn register_dir<I>(&mut self, iter: I) -> u64
    where
        I: Iterator<Item = Result<Entry>> + 'static,
    {
        let fh = self.fh;
        self.fh += 1;
        let iter: Box<Iterator<Item = Result<Entry>>> = Box::new(iter);
        self.dir_handlers.insert(fh, iter.peekable());
        return fh;
    }
    fn get_file(&self, fh: u64) -> Option<&Box<SeekableRead>> {
        self.file_handlers.get(&fh)
    }
    fn get_file_mut(&mut self, fh: u64) -> Option<&mut Box<SeekableRead>> {
        self.file_handlers.get_mut(&fh)
    }
    fn get_dir_mut(
        &mut self,
        fh: u64,
    ) -> Option<&mut iter::Peekable<Box<Iterator<Item = Result<Entry>>>>> {
        self.dir_handlers.get_mut(&fh)
    }
    fn release_file(&mut self, fh: u64) {
        self.file_handlers.remove(&fh);
    }
    // if the handler is not found, return false.
    fn release_dir(&mut self, fh: u64) -> bool {
        self.dir_handlers.remove(&fh).is_some()
    }
}

pub trait Viewer {
    fn view(&self, e: Entry) -> Entry;
}

struct CompositeViewer {
    viewers: Vec<Box<Viewer>>,
}

impl CompositeViewer {
    fn new() -> CompositeViewer {
        CompositeViewer { viewers: Vec::new() }
    }

    fn add<V: Viewer + 'static>(&mut self, v: V) {
        self.viewers.push(Box::new(v))
    }

    fn view(&self, e: Entry) -> Entry {
        let mut e = e;
        for viewer in self.viewers.iter() {
            e = viewer.view(e);
        }
        e
    }
}

pub struct ShowFS {
    origin: PathBuf,
    entries: EntryHolder,
    handlers: HandlerHolder,
    viewers: Rc<CompositeViewer>,
    buf: Vec<u8>,
}

impl ShowFS {
    pub fn new<P>(origin: P) -> ShowFS
    where
        P: AsRef<Path>,
    {
        ShowFS {
            origin: origin.as_ref().to_path_buf(),
            entries: EntryHolder::new(),
            handlers: HandlerHolder::new(),
            viewers: Rc::new(CompositeViewer::new()),
            buf: Vec::new(),
        }
    }

    pub fn register_viewer<V: Viewer + 'static>(&mut self, v: V) {
        Rc::get_mut(&mut self.viewers).unwrap().add(v)
    }

    pub fn mount<P>(mut self, target: P) -> Result<()>
    where
        P: AsRef<Path>,
    {
        let root = if fs::metadata(self.origin.clone())?.is_dir() {
            Entry::Dir(Box::new(physical::Dir::new(self.origin.clone())))
        } else {
            Entry::File(Box::new(physical::File::new(self.origin.clone())))
        };
        let viewed_root = self.viewers.view(root);
        match viewed_root {
            Entry::Dir(_) if fs::metadata(target.as_ref())?.is_dir() => {
                // fallthrough
            }
            _ => {
                return Err(Error::new(
                    ErrorKind::InvalidInput,
                    "invalid origin or mountpoint",
                ));
            }
        }
        self.entries.register_root(viewed_root);
        fuse::mount(self, &target, &[])
    }
}

impl Filesystem for ShowFS {
    // kernel path resolving function
    fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
        // check cache.
        match self.entries.get_by_path(parent, name) {
            Some((ino, ent)) => {
                match ent.getattr(ino) {
                    Ok(attr) => {
                        reply.entry(&TTL, &attr, 0);
                        return;
                    }
                    Err(e) => {
                        error_with_log!(reply, e);
                        return;
                    }
                }
            }
            _ => {
                // fallthrough
            }
        }

        // look underlying.
        let ret_ent = match self.entries.get_by_inode(parent) {
            Some(&Entry::Dir(ref p)) => p.lookup(name),
            _ => {
                reply.error(libc::ENOENT);
                return;
            }
        };
        let attr = match ret_ent {
            Ok(ent) => {
                let ir = self.entries.reserve_inode();
                let ent = self.viewers.view(ent);
                let attr = ent.getattr(ir.inode());
                self.entries.register_with(parent, ent, ir);
                attr
            }
            Err(e) => {
                error_with_log!(reply, e);
                return;
            }
        };
        match attr {
            Ok(attr) => reply.entry(&TTL, &attr, 0),
            Err(e) => error_with_log!(reply, e),
        }
    }

    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        if let Some(ent) = self.entries.get_by_inode(ino) {
            match ent.getattr(ino) {
                Ok(attr) => reply.attr(&TTL, &attr),
                Err(e) => error_with_log!(reply, e),
            }
        } else {
            reply.error(libc::ENOENT);
        }
    }

    fn open(&mut self, _req: &Request, ino: u64, flags: u32, reply: ReplyOpen) {
        if flags & libc::O_RDONLY as u32 != 0 {
            // support read only.
            reply.error(libc::EINVAL);
            return;
        }

        let file = match self.entries.get_by_inode(ino) {
            Some(&Entry::File(ref file)) => file.clone(),
            Some(_) => {
                reply.error(libc::EINVAL);
                return;
            }
            None => {
                reply.error(libc::ENOENT);
                return;
            }
        };
        match file.open() {
            Ok(contents) => {
                let fh = self.handlers.register_file(contents);
                // flag can only be direct_io or keep_cache.
                reply.opened(fh, 0);
            }
            Err(e) => error_with_log!(reply, e),
        }
    }

    // called when all opened fds are closed.
    fn release(
        &mut self,
        _req: &Request,
        _ino: u64,
        fh: u64,
        _flags: u32,
        _lock_owner: u64,
        _flush: bool,
        reply: ReplyEmpty,
    ) {
        if self.handlers.get_file(fh).is_none() {
            reply.error(libc::EBADF);
            return;
        }
        self.handlers.release_file(fh);
        reply.ok();
    }

    fn read(
        &mut self,
        _req: &Request,
        _ino: u64,
        fh: u64,
        offset: u64,
        size: u32,
        reply: ReplyData,
    ) {
        if let Some(reader) = self.handlers.get_file_mut(fh) {
            if let Err(e) = reader.seek(SeekFrom::Start(offset)) {
                error_with_log!(reply, e);
                return;

            }
            let size = size as usize;
            self.buf.resize(size, 0);
            let mut read = 0;
            while read < size {
                match reader.read(&mut self.buf[read..]) {
                    Ok(n) if n == 0 => break,
                    Ok(n) => read += n,
                    Err(e) => {
                        error_with_log!(reply, e);
                        return;
                    }
                }
            }
            reply.data(&self.buf[..read])
        } else {
            reply.error(libc::EBADF)
        }
    }

    fn opendir(&mut self, _req: &Request, ino: u64, _flags: u32, reply: ReplyOpen) {
        let handler = match self.entries.get_by_inode(ino) {
            Some(&Entry::Dir(ref d)) => d.open(),
            Some(_) => {
                reply.error(libc::EBADF);
                return;
            }
            None => {
                reply.error(libc::ENOENT);
                return;
            }

        };
        match handler {
            Ok(dh) => {
                let viewer = self.viewers.clone();
                let fh = self.handlers.register_dir(
                    dh.map(move |re| re.map(|e| viewer.view(e))),
                );
                reply.opened(fh, 0);
            }
            Err(e) => error_with_log!(reply, e),
        }
    }

    fn releasedir(&mut self, _req: &Request, _ino: u64, fh: u64, _flags: u32, reply: ReplyEmpty) {
        if self.handlers.release_dir(fh) {
            reply.ok();
        } else {
            reply.error(libc::EBADF);
            return;
        }
    }

    fn readdir(
        &mut self,
        _req: &Request,
        ino: u64,
        fh: u64,
        offset: u64,
        mut reply: ReplyDirectory,
    ) {
        let h = match self.handlers.get_dir_mut(fh) {
            Some(h) => h,
            None => {
                reply.error(libc::ENOENT);
                return;
            }
        };
        for offset in (offset + 1).. {
            let mut reserver = None;
            // check if an entry can be inserted.
            match h.peek() {
                Some(&Ok(ref ent)) => {
                    let ent_ino = match self.entries.get_by_path(ino, ent.name()) {
                        Some((ent_ino, _)) => ent_ino,
                        None => {
                            let r = self.entries.reserve_inode();
                            let i = r.inode();
                            reserver = Some(r);
                            i
                        }
                    };
                    match ent.file_type(ent_ino) {
                        Ok(ft) => {
                            if reply.add(ent_ino, offset, ft, ent.name()) {
                                // buffer is full.
                                reply.ok();
                                return;
                            }
                        }
                        Err(e) => {
                            error_with_log!(reply, e);
                            return;
                        }
                    }
                }
                _ => {
                    // fallthrough
                }
            }

            match h.next() {
                Some(Ok(ent)) => {
                    if let Some(r) = reserver {
                        self.entries.register_with(ino, ent, r)
                    }
                }
                Some(Err(e)) => {
                    error_with_log!(reply, e);
                    return;
                }
                None => {
                    reply.ok();
                    return;
                }
            }
        }
    }
}
<commit_msg>warn if ENOENT<commit_after>extern crate libc;
extern crate fuse;
extern crate time;

use self::fuse::{Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory, ReplyOpen,
                 ReplyEmpty, FileAttr, FileType};
use self::time::Timespec;
use std::collections::HashMap;
use std::convert::AsRef;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io::{Read, Seek, SeekFrom};
use std::io::{Result, Error, ErrorKind};
use std::iter;
use std::path::{Path, PathBuf};
use std::vec::Vec;
use std::rc::Rc;

use physical;

macro_rules! error_with_log {
    ($reply:expr, $e:expr) => {{
        let cerr = to_cerr(&$e);
        if cerr == libc::ENOENT {
            warn!("{}:{}: {:?}", file!(), line!(), $e);
        } else {
            error!("{}:{}: {:?}", file!(), line!(), $e);
        }
        $reply.error(cerr)
    }}
}

// TODO: configurable?
const TTL: Timespec = Timespec { sec: 1, nsec: 0 };

pub trait SeekableRead: Seek + Read {}
impl<T: Seek + Read> SeekableRead for T {}

pub enum Entry {
    File(Box<File>),
    Dir(Box<Dir>),
}

impl Entry {
    pub fn getattr(&self, ino: u64) -> Result<FileAttr> {
        let attr = match self {
            &Entry::File(ref f) => f.getattr(),
            &Entry::Dir(ref d) => d.getattr(),
        };
        attr.map(|mut a| {
            a.ino = ino;
            a
        })
    }
    pub fn name(&self) -> &OsStr {
        match self {
            &Entry::File(ref f) => f.name(),
            &Entry::Dir(ref d) => d.name(),
        }
    }
    pub fn file_type(&self, ino: u64) -> Result<FileType> {
        self.getattr(ino).map(|a| a.kind)
    }
}

pub trait File {
    fn getattr(&self) -> Result<FileAttr>;
    fn open(&self) -> Result<Box<SeekableRead>>;
    fn name(&self) -> &OsStr;
}

pub trait Dir {
    fn open(&self) -> Result<Box<Iterator<Item = Result<Entry>>>>;
    fn lookup(&self, name: &OsStr) -> Result<Entry>;
    fn getattr(&self) -> Result<FileAttr>;
    fn name(&self) -> &OsStr;
}

fn to_cerr(e: &Error) -> libc::c_int {
    match e.raw_os_error() {
        Some(raw) => raw,
        None => libc::EIO,
    }
}

struct InodeReserver {
    inode: u64,
}

impl InodeReserver {
    fn inode(&self) -> u64 {
        return self.inode;
    }
}

struct EntryHolder {
    inode: u64,
    inode_to_entry: HashMap<u64, Entry>,
    path_to_inode: HashMap<(u64, OsString), u64>,
}

impl EntryHolder {
    fn new() -> EntryHolder {
        EntryHolder {
            inode: 0,
            inode_to_entry: HashMap::new(),
            path_to_inode: HashMap::new(),
        }
    }
    fn get_by_path(&self, parent: u64, name: &OsStr) -> Option<(u64, &Entry)> {
        self.path_to_inode
            .get(&(parent, name.to_os_string()))
            .and_then(|ino| self.inode_to_entry.get(ino).map(|e| (*ino, e)))
    }
    fn reserve_inode(&mut self) -> InodeReserver {
        let i = self.inode;
        self.inode += 1;
        InodeReserver { inode: i }
    }
    fn register_with(&mut self, parent: u64, ent: Entry, ir: InodeReserver) {
        debug!("register {:?} with {}", ent.name(), ir.inode);
        self.path_to_inode.insert(
            (parent, ent.name().to_os_string()),
            ir.inode,
        );
        self.inode_to_entry.insert(ir.inode, ent);
    }
    fn register_root(&mut self, root: Entry) {
        self.inode = 2; // next to root (1)
        self.register_with(0, root, InodeReserver { inode: 1 })
    }
    fn get_by_inode(&self, ino: u64) -> Option<&Entry> {
        self.inode_to_entry.get(&ino)
    }
}

struct HandlerHolder {
    fh: u64, // fh counter
    file_handlers: HashMap<u64, Box<SeekableRead>>,
    dir_handlers: HashMap<u64, iter::Peekable<Box<Iterator<Item = Result<Entry>>>>>,
}

impl HandlerHolder {
    fn new() -> HandlerHolder {
        HandlerHolder {
            fh: 0,
            file_handlers: HashMap::new(),
            dir_handlers: HashMap::new(),
        }
    }
    fn register_file(&mut self, r: Box<SeekableRead>) -> u64 {
        let fh = self.fh;
        self.fh += 1;
        self.file_handlers.insert(fh, r);
        return fh;
    }
    fn register_dir<I>(&mut self, iter: I) -> u64
    where
        I: Iterator<Item = Result<Entry>> + 'static,
    {
        let fh = self.fh;
        self.fh += 1;
        let iter: Box<Iterator<Item = Result<Entry>>> = Box::new(iter);
        self.dir_handlers.insert(fh, iter.peekable());
        return fh;
    }
    fn get_file(&self, fh: u64) -> Option<&Box<SeekableRead>> {
        self.file_handlers.get(&fh)
    }
    fn get_file_mut(&mut self, fh: u64) -> Option<&mut Box<SeekableRead>> {
        self.file_handlers.get_mut(&fh)
    }
    fn get_dir_mut(
        &mut self,
        fh: u64,
    ) -> Option<&mut iter::Peekable<Box<Iterator<Item = Result<Entry>>>>> {
        self.dir_handlers.get_mut(&fh)
    }
    fn release_file(&mut self, fh: u64) {
        self.file_handlers.remove(&fh);
    }
    // if the handler is not found, return false.
    fn release_dir(&mut self, fh: u64) -> bool {
        self.dir_handlers.remove(&fh).is_some()
    }
}

pub trait Viewer {
    fn view(&self, e: Entry) -> Entry;
}

struct CompositeViewer {
    viewers: Vec<Box<Viewer>>,
}

impl CompositeViewer {
    fn new() -> CompositeViewer {
        CompositeViewer { viewers: Vec::new() }
    }

    fn add<V: Viewer + 'static>(&mut self, v: V) {
        self.viewers.push(Box::new(v))
    }

    fn view(&self, e: Entry) -> Entry {
        let mut e = e;
        for viewer in self.viewers.iter() {
            e = viewer.view(e);
        }
        e
    }
}

pub struct ShowFS {
    origin: PathBuf,
    entries: EntryHolder,
    handlers: HandlerHolder,
    viewers: Rc<CompositeViewer>,
    buf: Vec<u8>,
}

impl ShowFS {
    pub fn new<P>(origin: P) -> ShowFS
    where
        P: AsRef<Path>,
    {
        ShowFS {
            origin: origin.as_ref().to_path_buf(),
            entries: EntryHolder::new(),
            handlers: HandlerHolder::new(),
            viewers: Rc::new(CompositeViewer::new()),
            buf: Vec::new(),
        }
    }

    pub fn register_viewer<V: Viewer + 'static>(&mut self, v: V) {
        Rc::get_mut(&mut self.viewers).unwrap().add(v)
    }

    pub fn mount<P>(mut self, target: P) -> Result<()>
    where
        P: AsRef<Path>,
    {
        let root = if fs::metadata(self.origin.clone())?.is_dir() {
            Entry::Dir(Box::new(physical::Dir::new(self.origin.clone())))
        } else {
            Entry::File(Box::new(physical::File::new(self.origin.clone())))
        };
        let viewed_root = self.viewers.view(root);
        match viewed_root {
            Entry::Dir(_) if fs::metadata(target.as_ref())?.is_dir() => {
                // fallthrough
            }
            _ => {
                return Err(Error::new(
                    ErrorKind::InvalidInput,
                    "invalid origin or mountpoint",
                ));
            }
        }
        self.entries.register_root(viewed_root);
        fuse::mount(self, &target, &[])
    }
}

impl Filesystem for ShowFS {
    // kernel path resolving function
    fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
        // check cache.
        match self.entries.get_by_path(parent, name) {
            Some((ino, ent)) => {
                match ent.getattr(ino) {
                    Ok(attr) => {
                        reply.entry(&TTL, &attr, 0);
                        return;
                    }
                    Err(e) => {
                        error_with_log!(reply, e);
                        return;
                    }
                }
            }
            _ => {
                // fallthrough
            }
        }

        // look underlying.
        let ret_ent = match self.entries.get_by_inode(parent) {
            Some(&Entry::Dir(ref p)) => p.lookup(name),
            _ => {
                reply.error(libc::ENOENT);
                return;
            }
        };
        let attr = match ret_ent {
            Ok(ent) => {
                let ir = self.entries.reserve_inode();
                let ent = self.viewers.view(ent);
                let attr = ent.getattr(ir.inode());
                self.entries.register_with(parent, ent, ir);
                attr
            }
            Err(e) => {
                error_with_log!(reply, e);
                return;
            }
        };
        match attr {
            Ok(attr) => reply.entry(&TTL, &attr, 0),
            Err(e) => error_with_log!(reply, e),
        }
    }

    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        if let Some(ent) = self.entries.get_by_inode(ino) {
            match ent.getattr(ino) {
                Ok(attr) => reply.attr(&TTL, &attr),
                Err(e) => error_with_log!(reply, e),
            }
        } else {
            reply.error(libc::ENOENT);
        }
    }

    fn open(&mut self, _req: &Request, ino: u64, flags: u32, reply: ReplyOpen) {
        if flags & libc::O_RDONLY as u32 != 0 {
            // support read only.
            reply.error(libc::EINVAL);
            return;
        }

        let file = match self.entries.get_by_inode(ino) {
            Some(&Entry::File(ref file)) => file.clone(),
            Some(_) => {
                reply.error(libc::EINVAL);
                return;
            }
            None => {
                reply.error(libc::ENOENT);
                return;
            }
        };
        match file.open() {
            Ok(contents) => {
                let fh = self.handlers.register_file(contents);
                // flag can only be direct_io or keep_cache.
                reply.opened(fh, 0);
            }
            Err(e) => error_with_log!(reply, e),
        }
    }

    // called when all opened fds are closed.
    fn release(
        &mut self,
        _req: &Request,
        _ino: u64,
        fh: u64,
        _flags: u32,
        _lock_owner: u64,
        _flush: bool,
        reply: ReplyEmpty,
    ) {
        if self.handlers.get_file(fh).is_none() {
            reply.error(libc::EBADF);
            return;
        }
        self.handlers.release_file(fh);
        reply.ok();
    }

    fn read(
        &mut self,
        _req: &Request,
        _ino: u64,
        fh: u64,
        offset: u64,
        size: u32,
        reply: ReplyData,
    ) {
        if let Some(reader) = self.handlers.get_file_mut(fh) {
            if let Err(e) = reader.seek(SeekFrom::Start(offset)) {
                error_with_log!(reply, e);
                return;

            }
            let size = size as usize;
            self.buf.resize(size, 0);
            let mut read = 0;
            while read < size {
                match reader.read(&mut self.buf[read..]) {
                    Ok(n) if n == 0 => break,
                    Ok(n) => read += n,
                    Err(e) => {
                        error_with_log!(reply, e);
                        return;
                    }
                }
            }
            reply.data(&self.buf[..read])
        } else {
            reply.error(libc::EBADF)
        }
    }

    fn opendir(&mut self, _req: &Request, ino: u64, _flags: u32, reply: ReplyOpen) {
        let handler = match self.entries.get_by_inode(ino) {
            Some(&Entry::Dir(ref d)) => d.open(),
            Some(_) => {
                reply.error(libc::EBADF);
                return;
            }
            None => {
                reply.error(libc::ENOENT);
                return;
            }

        };
        match handler {
            Ok(dh) => {
                let viewer = self.viewers.clone();
                let fh = self.handlers.register_dir(
                    dh.map(move |re| re.map(|e| viewer.view(e))),
                );
                reply.opened(fh, 0);
            }
            Err(e) => error_with_log!(reply, e),
        }
    }

    fn releasedir(&mut self, _req: &Request, _ino: u64, fh: u64, _flags: u32, reply: ReplyEmpty) {
        if self.handlers.release_dir(fh) {
            reply.ok();
        } else {
            reply.error(libc::EBADF);
            return;
        }
    }

    fn readdir(
        &mut self,
        _req: &Request,
        ino: u64,
        fh: u64,
        offset: u64,
        mut reply: ReplyDirectory,
    ) {
        let h = match self.handlers.get_dir_mut(fh) {
            Some(h) => h,
            None => {
                reply.error(libc::ENOENT);
                return;
            }
        };
        for offset in (offset + 1).. {
            let mut reserver = None;
            // check if an entry can be inserted.
            match h.peek() {
                Some(&Ok(ref ent)) => {
                    let ent_ino = match self.entries.get_by_path(ino, ent.name()) {
                        Some((ent_ino, _)) => ent_ino,
                        None => {
                            let r = self.entries.reserve_inode();
                            let i = r.inode();
                            reserver = Some(r);
                            i
                        }
                    };
                    match ent.file_type(ent_ino) {
                        Ok(ft) => {
                            if reply.add(ent_ino, offset, ft, ent.name()) {
                                // buffer is full.
                                reply.ok();
                                return;
                            }
                        }
                        Err(e) => {
                            error_with_log!(reply, e);
                            return;
                        }
                    }
                }
                _ => {
                    // fallthrough
                }
            }

            match h.next() {
                Some(Ok(ent)) => {
                    if let Some(r) = reserver {
                        self.entries.register_with(ino, ent, r)
                    }
                }
                Some(Err(e)) => {
                    error_with_log!(reply, e);
                    return;
                }
                None => {
                    reply.ok();
                    return;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// 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::cmp;

/// Inclusive range from min to max
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct InclusiveRange<T: Copy + Ord> {
    pub min: T,
    pub max: T
}

impl<T: Copy + Ord> InclusiveRange<T> {
    /// Create an InclusiveRange range from min to max
    pub fn new(min: T, max: T) -> InclusiveRange<T> {
        assert!(min <= max);
        InclusiveRange { min: min, max: max }
    }
}

/// Create range covering the overlap between two ranges, or None if
/// there is no overlap.
pub fn range_clamp<T: Copy + Ord>(a: &InclusiveRange<T>,
                                  b: &InclusiveRange<T>)
                                  -> Option<InclusiveRange<T>> {
    let min = cmp::max(a.min, b.min);
    let max = cmp::min(a.max, b.max);

    if min < max {
        Some(InclusiveRange::new(min, max))
    }
    else {
        None
    }
}

#[test]
fn test_range_clamp() {
    assert!(range_clamp(&InclusiveRange::new(0, 2),
                        &InclusiveRange::new(0, 2)) ==
            Some(InclusiveRange::new(0, 2)));

    assert!(range_clamp(&InclusiveRange::new(0, 1),
                        &InclusiveRange::new(2, 3)) ==
            None);

    assert!(range_clamp(&InclusiveRange::new(2, 3),
                        &InclusiveRange::new(0, 1)) ==
            None);

    assert!(range_clamp(&InclusiveRange::new(0, 2),
                        &InclusiveRange::new(1, 3)) ==
            Some(InclusiveRange::new(1, 2)));

    assert!(range_clamp(&InclusiveRange::new(1, 3),
                        &InclusiveRange::new(0, 2)) ==
            Some(InclusiveRange::new(1, 2)));
}
<commit_msg>Range f32 fixes<commit_after>// Copyright 2015 Nicholas Bishop
//
// 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.

/// Inclusive range from min to max
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct InclusiveRange<T: Copy + PartialOrd> {
    pub min: T,
    pub max: T
}

pub const RANGE_0_1_F32: InclusiveRange<f32> = InclusiveRange { min: 0.0, max: 0.0 };

impl<T: Copy + PartialOrd> InclusiveRange<T> {
    /// Create an InclusiveRange range from min to max
    pub fn new(min: T, max: T) -> InclusiveRange<T> {
        assert!(min <= max);
        InclusiveRange { min: min, max: max }
    }
}

/// Create range covering the overlap between two ranges, or None if
/// there is no overlap.
pub fn range_clamp<T: Copy + PartialOrd>(a: &InclusiveRange<T>,
                                         b: &InclusiveRange<T>)
                                         -> Option<InclusiveRange<T>> {
    let min = if a.min > b.min { a.min } else { b.min };
    let max = if a.max < b.max { a.max } else { b.max };

    if min <= max {
        Some(InclusiveRange::new(min, max))
    }
    else {
        None
    }
}

#[test]
fn test_range_clamp() {
    assert!(range_clamp(&InclusiveRange::new(0, 2),
                        &InclusiveRange::new(0, 2)) ==
            Some(InclusiveRange::new(0, 2)));

    assert!(range_clamp(&InclusiveRange::new(0, 1),
                        &InclusiveRange::new(2, 3)) ==
            None);

    assert!(range_clamp(&InclusiveRange::new(2, 3),
                        &InclusiveRange::new(0, 1)) ==
            None);

    assert!(range_clamp(&InclusiveRange::new(0, 2),
                        &InclusiveRange::new(1, 3)) ==
            Some(InclusiveRange::new(1, 2)));

    assert!(range_clamp(&InclusiveRange::new(1, 3),
                        &InclusiveRange::new(0, 2)) ==
            Some(InclusiveRange::new(1, 2)));

    assert!(range_clamp(&InclusiveRange::new(1.0, 3.0),
                        &InclusiveRange::new(0.0, 2.0)) ==
            Some(InclusiveRange::new(1.0, 2.0)));
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Write;
use std::io::Result;
use std::io::Error;
use std::io::ErrorKind;

const BUFFER_SIZE : usize = 256us;

struct Buffer {
    data: [u8; BUFFER_SIZE],
    len: usize,
    cur: usize,
    bit: u8,
    sum: u64
}

impl Buffer {
    fn create() -> Buffer {
        return Buffer {
            data: [0u8; BUFFER_SIZE],
            len: 0us,
            cur: 0us,
            bit: 7u8,
            sum: 0u64
        };
    }

    fn fill(&mut self, istream: &mut Read) -> Result<bool> {
        match istream.read(&mut self.data[0..]) {
            Ok(0) => Ok(true),
            Ok(n) => {
                self.sum += n as u64;
                self.len = n;
                self.cur = 0;
                Ok(false)
            },
            Err(e) => Err(e)
        }
    }

    fn pull(&mut self, istream: &mut Read) -> Result<(u8, bool)> {
        let value = (self.data[self.cur] & (1 << self.bit)) >> self.bit;

        if self.bit == 0 {
            self.bit = 7;
            self.cur += 1;
            if self.cur == self.len {
                return match self.fill(istream) {
                    Ok(b) => Ok((value, b)),
                    Err(e) => Err(e)
                }
            }
        } else {
            self.bit -= 1;
        }
        return Ok((value, false));
    }

    fn flush(&mut self, ostream: &mut Write) -> Result<()> {
        // Flush the remaining incomplete byte as well
        if self.bit < 7 {
            self.len += 1;
        }

        while self.cur < self.len {
            match ostream.write(&self.data[self.cur..self.len]) {
                Ok(0) => { return Err(Error::new(ErrorKind::WriteZero, "Zero bytes written to output")); }
                Ok(n) => {
                    self.cur += n;
                    self.sum += n as u64;
                },
                Err(e) => { return Err(e); }
            }
        }

        self.len = 0;
        self.cur = 0;
        return Ok(());
    }

    fn push(&mut self, value: u8, ostream: &mut Write) -> Result<()> {
        self.data[self.len] |= value << self.bit;

        if self.bit == 0 {
            self.bit = 7;
            self.len += 1;
            if self.len == self.data.len() {
                if let Err(e) = self.flush(ostream) {
                    return Err(e);
                }
            }
            self.data[self.len] = 0;
        } else {
            self.bit -= 1;
        }
        return Ok(());
    }
}

struct Status {
    low: u64,
    high: u64,
    range: u64,
    pending: u8,
    freq: [u64; 258],
    input: Buffer,
    output: Buffer
}

impl Status {
    fn init() -> Status {
        let mut res = Status {
            low: 0x00000000_00000000u64,
            high: 0xFFFFFFFF_FFFFFFFFu64,
            range: 0u64,
            pending: 0u8,
            freq: [0u64; 258],
            input: Buffer::create(),
            output: Buffer::create()
        };
        for i in 1..258 {
            res.freq[i] = i as u64;
        }
        return res;
    }

    fn metrics(&self) -> (u64, u64) {
        return (self.input.sum , self.output.sum);
    }
}

pub fn compress(istream: &mut Read, ostream: &mut Write) -> Result<(u64, u64)> {
    let mut st = Status::init();
    let mut count = 0u64;

    if try!(st.input.fill(istream)) {
        return Ok(st.metrics());
    }

    loop {
        let (v, eof) = try!(st.input.pull(istream));
        try!(st.output.push(v, ostream));

        count += 1;
        if count >= 236 || eof {
            break;
        }
    }

    try!(st.output.flush(ostream));

    println!("{} bits", count);
    return Ok(st.metrics());
}

<commit_msg>Implemented compressor<commit_after>use std::io::Read;
use std::io::Write;
use std::io::Result;
use std::io::Error;
use std::io::ErrorKind;

const BUFFER_SIZE: usize = 256;
const EOF_VALUE: usize = 256;
const CODE_BITS: usize = 33;
const CODE_MIN: u64 = 0;
const CODE_MAX: u64 = (1 << CODE_BITS) - 1;
const ONE_FOURTH: u64 = 1 << (CODE_BITS - 2);
const ONE_HALF: u64 = 2 * ONE_FOURTH;
const THREE_FOURTHS: u64 = 3 * ONE_FOURTH;

struct Buffer {
    data: [u8; BUFFER_SIZE],
    len: usize,
    cur: usize,
    bit: u8,
    sum: u64
}

impl Buffer {
    fn create() -> Buffer {
        return Buffer {
            data: [0u8; BUFFER_SIZE],
            len: 0us,
            cur: 0us,
            bit: 7u8,
            sum: 0u64
        };
    }

    fn fill_buffer(&mut self, istream: &mut Read) -> Result<bool> {
        match istream.read(&mut self.data[0..]) {
            Ok(0) => Ok(true),
            Ok(n) => {
                self.sum += n as u64;
                self.len = n;
                self.cur = 0;
                Ok(false)
            },
            Err(e) => Err(e)
        }
    }

    fn get_byte(&mut self, istream: &mut Read) -> Result<(u8, bool)> {
        let value = self.data[self.cur];
        self.cur += 1;
        if self.cur == self.len {
            return match self.fill_buffer(istream) {
                Ok(b) => Ok((value, b)),
                Err(e) => Err(e)
            }
        } else {
            return Ok((value, false));
        }
    }

    fn get_bit(&mut self, istream: &mut Read) -> Result<(u8, bool)> {
        let value = (self.data[self.cur] & (1 << self.bit)) >> self.bit;

        if self.bit == 0 {
            self.bit = 7;
            self.cur += 1;
            if self.cur == self.len {
                return match self.fill_buffer(istream) {
                    Ok(b) => Ok((value, b)),
                    Err(e) => Err(e)
                }
            }
        } else {
            self.bit -= 1;
        }
        return Ok((value, false));
    }

    fn flush_buffer(&mut self, ostream: &mut Write) -> Result<()> {
        // Flush the remaining incomplete byte as well
        if self.bit < 7 {
            self.len += 1;
        }

        while self.cur < self.len {
            match ostream.write(&self.data[self.cur..self.len]) {
                Ok(0) => { return Err(Error::new(ErrorKind::WriteZero, "Zero bytes written to output")); }
                Ok(n) => {
                    self.cur += n;
                    self.sum += n as u64;
                },
                Err(e) => { return Err(e); }
            }
        }

        self.len = 0;
        self.cur = 0;
        return Ok(());
    }

    fn put_byte(&mut self, value: u8, ostream: &mut Write) -> Result<()> {
        return Ok(());
    }

    fn put_bit(&mut self, value: u8, ostream: &mut Write) -> Result<()> {
        self.data[self.len] |= value << self.bit;

        if self.bit == 0 {
            self.bit = 7;
            self.len += 1;
            if self.len == self.data.len() {
                if let Err(e) = self.flush_buffer(ostream) {
                    return Err(e);
                }
            }
            self.data[self.len] = 0;
        } else {
            self.bit -= 1;
        }
        return Ok(());
    }
}

struct Status {
    low: u64,
    high: u64,
    range: u64,
    pending: u8,
    freq: [u64; 258],
    input: Buffer,
    output: Buffer
}

impl Status {
    fn init() -> Status {
        let mut res = Status {
            low: CODE_MIN,
            high: CODE_MAX,
            range: 0u64,
            pending: 0u8,
            freq: [0u64; 258],
            input: Buffer::create(),
            output: Buffer::create()
        };
        for i in 1..258 {
            res.freq[i] = i as u64;
        }
        return res;
    }

    fn get_probability(&self, chr: usize) -> (u64, u64, u64) {
        (self.freq[chr], self.freq[chr + 1], self.freq[self.freq.len() - 1])
    }

    fn put_pending_bits(&mut self, bit: u8, ostream: &mut Write) -> Result<()> {
        try!(self.output.put_bit(bit, ostream));
        while self.pending > 0 {
            try!(self.output.put_bit(bit, ostream));
            self.pending -= 1;
        }
        return Ok(());
    }

    fn metrics(&self) -> (u64, u64) {
        (self.input.sum , self.output.sum)
    }
}

pub fn compress(istream: &mut Read, ostream: &mut Write) -> Result<(u64, u64)> {
    let mut status = Status::init();

    let mut eof = try!(status.input.fill_buffer(istream));
    loop {
        let chr = if eof {
            EOF_VALUE
        } else {
            match status.input.get_byte(istream) {
                Ok((c, e)) => { eof = e; c as usize },
                Err(e) => { return Err(e); }
            }
        };

        {
            let (low, high, count) = status.get_probability(chr);
            status.range = status.high - status.low + 1;
            status.high = status.low + (status.range * high / count) - 1;
            status.low = low + (status.range * low / count);
        }

        loop {
           if status.high < ONE_HALF {
               try!(status.put_pending_bits(0, ostream));
           } else if status.low >= ONE_HALF {
               try!(status.put_pending_bits(1, ostream));
           } else if status.low >= ONE_FOURTH && status.high < THREE_FOURTHS {
                status.pending += 1;
                status.low -= ONE_FOURTH;
                status.high -= ONE_FOURTH;
           } else {
               break;
           }

           status.high = ((status.high << 1) + 1) & CODE_MAX;
           status.low = (status.low << 1) & CODE_MAX;
        }

        if eof {
            break;
        }
    }

    status.pending += 1;
    if status.low < ONE_FOURTH {
        try!(status.put_pending_bits(0, ostream));
    } else {
        try!(status.put_pending_bits(1, ostream));
    }
    try!(status.output.flush_buffer(ostream));

    return Ok(status.metrics());
}

pub fn decompress(istream: &mut Read, ostream: &mut Write) -> Result<(u64, u64)> {
    let mut status = Status::init();

    let mut eof = try!(status.input.fill_buffer(istream));
    loop {
        break;
    }
    try!(status.output.flush_buffer(ostream));

    return Ok(status.metrics());
}

<|endoftext|>


<commit_before>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Represents the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort { stream: raw_stream })
    }

    /// Write a single `MidiEvent`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_event<T: Into<MidiEvent>>(&mut self, midi_event: T) -> Result<()> {
        self.write_events(vec![midi_event])
    }

    /// Write a buffer of midi events to the output port.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
        let events: Vec<ffi::PmEvent> = midi_events.into_iter()
                                                   .map(|event| event.into().into())
                                                   .collect();
        Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, midi_message.into()) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<commit_msg>Allow any type that is `Into<MidiMessage>` in `write_message`<commit_after>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Represents the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort { stream: raw_stream })
    }

    /// Write a single `MidiEvent`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_event<T: Into<MidiEvent>>(&mut self, midi_event: T) -> Result<()> {
        self.write_events(vec![midi_event])
    }

    /// Write a buffer of midi events to the output port.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
        let events: Vec<ffi::PmEvent> = midi_events.into_iter()
                                                   .map(|event| event.into().into())
                                                   .collect();
        Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message<T: Into<MidiMessage>>(&mut self, midi_message: T) -> Result<()> {
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, midi_message.into().into()) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<|endoftext|>


<commit_before>extern crate glm;
use std::ops::Add;

pub trait Shape {
    fn get_center(&self) -> glm::DVec2;
    fn contains(&self, point: &glm::DVec2) -> bool;
    fn intersects_with_circle(&self, circle: &Circle) -> bool;
    fn intersects_with_rectangle(&self, rectangle: &Rectangle) -> bool;
    fn distance<S>(&self, other: &S) -> f64
        where S: Shape
    {
        glm::distance(self.get_center(), other.get_center())
    }
}

pub struct Rectangle {
    dims: glm::DVec2,
    center: glm::DVec2,
}

impl Shape for Rectangle {
    fn get_center(&self) -> glm::DVec2 {
        self.center
    }

    fn contains(&self, point: &glm::DVec2) -> bool {
        let half_x = self.dims.x / 2.;
        let half_y = self.dims.y / 2.;

        if self.center.x - half_x > point.x {
            false
        } else if self.center.x + half_x < point.x {
            false
        } else if self.center.y - half_y > point.y {
            false
        } else if self.center.y + half_y < point.y {
            false
        } else {
            true
        }
    }

    fn intersects_with_rectangle(&self, rectangle: &Rectangle) -> bool {
        let half_x = self.dims.x / 2.;
        let half_y = self.dims.y / 2.;

        if self.center.x - half_x > rectangle.center.x + rectangle.dims.x / 2. {
            false
        } else if self.center.x + half_x < rectangle.center.x - rectangle.dims.x / 2. {
            false
        } else if self.center.y - half_y > rectangle.center.y + rectangle.dims.y / 2. {
            false
        } else if self.center.y + half_y < rectangle.center.y - rectangle.dims.y / 2. {
            false
        } else {
            true
        }
    }

    fn intersects_with_circle(&self, circle: &Circle) -> bool {
        circle.intersects_with_rectangle(&self)
    }
}

pub struct Circle {
    radius: f64,
    center: glm::DVec2,
}

impl Circle {
    fn intersects_with_line(&self, p1: glm::DVec2, p2: glm::DVec2) -> bool {
        let d = p2 + p1;
        let f = p1 - self.center;
        let a = glm::dot(d, d);
        let b = 2_f64 * glm::dot(f, d);
        let c = glm::dot(f, f) - self.radius * self.radius;
        let mut discriminant = b * b - 4_f64 * a * c;

        if discriminant < 0_f64 {
            return false;
        }

        discriminant = discriminant.sqrt();

        let t1 = (-b - discriminant) / (2_f64 * a);
        let t2 = (-b + discriminant) / (2_f64 * a);

        if t1 >= 0_f64 && t1 <= 1_f64 {
            true
        } else if t2 >= 0_f64 && t2 <= 1_f64 {
            true
        } else {
            false
        }
    }
}

impl Shape for Circle {
    fn get_center(&self) -> glm::DVec2 {
        self.center
    }

    fn contains(&self, point: &glm::DVec2) -> bool {
        let distance = glm::distance(self.center, *point);
        distance < self.radius
    }

    fn intersects_with_rectangle(&self, rectangle: &Rectangle) -> bool {
        if self.contains(&rectangle.center) {
            true
        } else if rectangle.contains(&self.center) {
            true
        } else {
            false
        }
    }

    fn intersects_with_circle(&self, circle: &Circle) -> bool {
        let distance = glm::distance(self.center, circle.center);
        distance < (self.radius + circle.radius)
    }
}

#[cfg(test)]
mod test {
    extern crate glm;
    use super::*;

    #[test]
    fn circle_no_contains() {
        let circle = Circle {
            radius: 1 as f64,
            center: glm::dvec2(2 as f64, 0 as f64),
        };
        let point = glm::dvec2(4 as f64, 4 as f64);
        assert!(!circle.contains(&point));
    }

    #[test]
    fn circle_contains() {
        let circle = Circle {
            radius: 3 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };
        let point = glm::dvec2(4 as f64, 4 as f64);
        assert!(circle.contains(&point));
    }

    #[test]
    fn circle_circle_no_intersect() {
        let circle_a = Circle {
            radius: 3 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        let circle_b = Circle {
            radius: 1 as f64,
            center: glm::dvec2(4 as f64, 7 as f64),
        };

        assert!(!circle_a.intersects_with_circle(&circle_b));
        assert!(!circle_b.intersects_with_circle(&circle_a));
    }

    #[test]
    fn circle_circle_intersect() {
        let circle_a = Circle {
            radius: 3 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        let circle_b = Circle {
            radius: 1 as f64,
            center: glm::dvec2(1 as f64, 5 as f64),
        };

        assert!(circle_a.intersects_with_circle(&circle_b));
        assert!(circle_b.intersects_with_circle(&circle_a));
    }

    #[test]
    fn rectangle_no_contains() {
        let rectangle = Rectangle {
            dims: glm::dvec2(2 as f64, 3 as f64),
            center: glm::dvec2(3 as f64, 0 as f64),
        };
        let point = glm::dvec2(3.5 as f64, -1 as f64);
        assert!(rectangle.contains(&point));
    }

    #[test]
    fn rectangle_contains() {
        let rectangle = Rectangle {
            dims: glm::dvec2(2 as f64, 3 as f64),
            center: glm::dvec2(3 as f64, 0 as f64),
        };
        let point = glm::dvec2(3.5 as f64, 2 as f64);
        assert!(!rectangle.contains(&point));
    }

    #[test]
    fn rectangle_rectangle_no_intersect() {
        let rectangle_a = Rectangle {
            dims: glm::dvec2(2 as f64, 3 as f64),
            center: glm::dvec2(3 as f64, 0 as f64),
        };

        let rectangle_b = Rectangle {
            dims: glm::dvec2(5 as f64, 2 as f64),
            center: glm::dvec2(0 as f64, 8 as f64),
        };
        assert!(!rectangle_a.intersects_with_rectangle(&rectangle_b));
        assert!(!rectangle_b.intersects_with_rectangle(&rectangle_a));
    }

    #[test]
    fn rectangle_rectangle_intersect() {
        let rectangle_a = Rectangle {
            dims: glm::dvec2(2 as f64, 3 as f64),
            center: glm::dvec2(3 as f64, 0 as f64),
        };

        let rectangle_b = Rectangle {
            dims: glm::dvec2(1 as f64, 2 as f64),
            center: glm::dvec2(2.5 as f64, 1 as f64),
        };
        assert!(rectangle_a.intersects_with_rectangle(&rectangle_b));
        assert!(rectangle_b.intersects_with_rectangle(&rectangle_a));
    }

    #[test]
    fn rectangle_circle_no_intersect() {
        let rectangle = Rectangle {
            dims: glm::dvec2(5 as f64, 2 as f64),
            center: glm::dvec2(6 as f64, 0 as f64),
        };

        let circle = Circle {
            radius: 3 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        assert!(!rectangle.intersects_with_circle(&circle));
        assert!(!circle.intersects_with_rectangle(&rectangle));
    }

    #[test]
    fn rectangle_inside_circle() {
        let rectangle = Rectangle {
            dims: glm::dvec2(1 as f64, 2 as f64),
            center: glm::dvec2(3 as f64, 5 as f64),
        };

        let circle = Circle {
            radius: 5 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        assert!(rectangle.intersects_with_circle(&circle));
        assert!(circle.intersects_with_rectangle(&rectangle));
    }

    #[test]
    fn circle_inside_rectangle() {
        let rectangle = Rectangle {
            dims: glm::dvec2(5 as f64, 7 as f64),
            center: glm::dvec2(4 as f64, 2 as f64),
        };

        let circle = Circle {
            radius: 1 as f64,
            center: glm::dvec2(5 as f64, 3 as f64),
        };

        assert!(rectangle.intersects_with_circle(&circle));
        assert!(circle.intersects_with_rectangle(&rectangle));
    }

    #[test]
    fn rectangle_circle_intersect() {
        let rectangle = Rectangle {
            dims: glm::dvec2(2 as f64, 2 as f64),
            center: glm::dvec2(5 as f64, 3 as f64),
        };

        let circle = Circle {
            radius: 2 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        assert!(rectangle.intersects_with_circle(&circle));
        assert!(circle.intersects_with_rectangle(&rectangle));
    }
}
<commit_msg>fix distance calculation<commit_after>extern crate glm;

pub trait Shape {
    fn get_center(&self) -> glm::DVec2;
    fn contains(&self, point: &glm::DVec2) -> bool;
    fn intersects_with_circle(&self, circle: &Circle) -> bool;
    fn intersects_with_rectangle(&self, rectangle: &Rectangle) -> bool;
    fn distance<S>(&self, other: &S) -> f64
        where S: Shape
    {
        glm::distance(self.get_center(), other.get_center())
    }
}

pub struct Rectangle {
    dims: glm::DVec2,
    center: glm::DVec2,
}

impl Shape for Rectangle {
    fn get_center(&self) -> glm::DVec2 {
        self.center
    }

    fn contains(&self, point: &glm::DVec2) -> bool {
        let half_x = self.dims.x / 2.;
        let half_y = self.dims.y / 2.;

        if self.center.x - half_x > point.x {
            false
        } else if self.center.x + half_x < point.x {
            false
        } else if self.center.y - half_y > point.y {
            false
        } else if self.center.y + half_y < point.y {
            false
        } else {
            true
        }
    }

    fn intersects_with_rectangle(&self, rectangle: &Rectangle) -> bool {
        let half_x = self.dims.x / 2.;
        let half_y = self.dims.y / 2.;

        if self.center.x - half_x > rectangle.center.x + rectangle.dims.x / 2. {
            false
        } else if self.center.x + half_x < rectangle.center.x - rectangle.dims.x / 2. {
            false
        } else if self.center.y - half_y > rectangle.center.y + rectangle.dims.y / 2. {
            false
        } else if self.center.y + half_y < rectangle.center.y - rectangle.dims.y / 2. {
            false
        } else {
            true
        }
    }

    fn intersects_with_circle(&self, circle: &Circle) -> bool {
        circle.intersects_with_rectangle(&self)
    }
}

pub struct Circle {
    radius: f64,
    center: glm::DVec2,
}

impl Circle {
    fn intersects_with_line(&self, p1: glm::DVec2, p2: glm::DVec2) -> bool {
        let d = p2 - p1;
        let f = p1 - self.center;
        let a = glm::dot(d, d);
        let b = 2_f64 * glm::dot(f, d);
        let c = glm::dot(f, f) - self.radius * self.radius;
        let mut discriminant = b * b - 4_f64 * a * c;

        if discriminant < 0_f64 {
            return false;
        }

        discriminant = discriminant.sqrt();

        let t1 = (-b - discriminant) / (2_f64 * a);
        let t2 = (-b + discriminant) / (2_f64 * a);

        if t1 >= 0_f64 && t1 <= 1_f64 {
            true
        } else if t2 >= 0_f64 && t2 <= 1_f64 {
            true
        } else {
            false
        }
    }
}

impl Shape for Circle {
    fn get_center(&self) -> glm::DVec2 {
        self.center
    }

    fn contains(&self, point: &glm::DVec2) -> bool {
        let distance = glm::distance(self.center, *point);
        distance < self.radius
    }

    fn intersects_with_rectangle(&self, rectangle: &Rectangle) -> bool {
        if self.contains(&rectangle.center) {
            true
        } else if rectangle.contains(&self.center) {
            true
        } else {
            false
        }
    }

    fn intersects_with_circle(&self, circle: &Circle) -> bool {
        let distance = glm::distance(self.center, circle.center);
        distance < (self.radius + circle.radius)
    }
}

#[cfg(test)]
mod test {
    extern crate glm;
    use super::*;

    #[test]
    fn circle_no_contains() {
        let circle = Circle {
            radius: 1 as f64,
            center: glm::dvec2(2 as f64, 0 as f64),
        };
        let point = glm::dvec2(4 as f64, 4 as f64);
        assert!(!circle.contains(&point));
    }

    #[test]
    fn circle_contains() {
        let circle = Circle {
            radius: 3 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };
        let point = glm::dvec2(4 as f64, 4 as f64);
        assert!(circle.contains(&point));
    }

    #[test]
    fn circle_circle_no_intersect() {
        let circle_a = Circle {
            radius: 3 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        let circle_b = Circle {
            radius: 1 as f64,
            center: glm::dvec2(4 as f64, 7 as f64),
        };

        assert!(!circle_a.intersects_with_circle(&circle_b));
        assert!(!circle_b.intersects_with_circle(&circle_a));
    }

    #[test]
    fn circle_circle_intersect() {
        let circle_a = Circle {
            radius: 3 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        let circle_b = Circle {
            radius: 1 as f64,
            center: glm::dvec2(1 as f64, 5 as f64),
        };

        assert!(circle_a.intersects_with_circle(&circle_b));
        assert!(circle_b.intersects_with_circle(&circle_a));
    }

    #[test]
    fn rectangle_no_contains() {
        let rectangle = Rectangle {
            dims: glm::dvec2(2 as f64, 3 as f64),
            center: glm::dvec2(3 as f64, 0 as f64),
        };
        let point = glm::dvec2(3.5 as f64, -1 as f64);
        assert!(rectangle.contains(&point));
    }

    #[test]
    fn rectangle_contains() {
        let rectangle = Rectangle {
            dims: glm::dvec2(2 as f64, 3 as f64),
            center: glm::dvec2(3 as f64, 0 as f64),
        };
        let point = glm::dvec2(3.5 as f64, 2 as f64);
        assert!(!rectangle.contains(&point));
    }

    #[test]
    fn rectangle_rectangle_no_intersect() {
        let rectangle_a = Rectangle {
            dims: glm::dvec2(2 as f64, 3 as f64),
            center: glm::dvec2(3 as f64, 0 as f64),
        };

        let rectangle_b = Rectangle {
            dims: glm::dvec2(5 as f64, 2 as f64),
            center: glm::dvec2(0 as f64, 8 as f64),
        };
        assert!(!rectangle_a.intersects_with_rectangle(&rectangle_b));
        assert!(!rectangle_b.intersects_with_rectangle(&rectangle_a));
    }

    #[test]
    fn rectangle_rectangle_intersect() {
        let rectangle_a = Rectangle {
            dims: glm::dvec2(2 as f64, 3 as f64),
            center: glm::dvec2(3 as f64, 0 as f64),
        };

        let rectangle_b = Rectangle {
            dims: glm::dvec2(1 as f64, 2 as f64),
            center: glm::dvec2(2.5 as f64, 1 as f64),
        };
        assert!(rectangle_a.intersects_with_rectangle(&rectangle_b));
        assert!(rectangle_b.intersects_with_rectangle(&rectangle_a));
    }

    #[test]
    fn rectangle_circle_no_intersect() {
        let rectangle = Rectangle {
            dims: glm::dvec2(5 as f64, 2 as f64),
            center: glm::dvec2(6 as f64, 0 as f64),
        };

        let circle = Circle {
            radius: 3 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        assert!(!rectangle.intersects_with_circle(&circle));
        assert!(!circle.intersects_with_rectangle(&rectangle));
    }

    #[test]
    fn rectangle_inside_circle() {
        let rectangle = Rectangle {
            dims: glm::dvec2(1 as f64, 2 as f64),
            center: glm::dvec2(3 as f64, 5 as f64),
        };

        let circle = Circle {
            radius: 5 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        assert!(rectangle.intersects_with_circle(&circle));
        assert!(circle.intersects_with_rectangle(&rectangle));
    }

    #[test]
    fn circle_inside_rectangle() {
        let rectangle = Rectangle {
            dims: glm::dvec2(5 as f64, 7 as f64),
            center: glm::dvec2(4 as f64, 2 as f64),
        };

        let circle = Circle {
            radius: 1 as f64,
            center: glm::dvec2(5 as f64, 3 as f64),
        };

        assert!(rectangle.intersects_with_circle(&circle));
        assert!(circle.intersects_with_rectangle(&rectangle));
    }

    #[test]
    fn rectangle_circle_intersect() {
        let rectangle = Rectangle {
            dims: glm::dvec2(2 as f64, 2 as f64),
            center: glm::dvec2(5 as f64, 3 as f64),
        };

        let circle = Circle {
            radius: 2 as f64,
            center: glm::dvec2(2 as f64, 3 as f64),
        };

        assert!(rectangle.intersects_with_circle(&circle));
        assert!(circle.intersects_with_rectangle(&rectangle));
    }
}
<|endoftext|>