<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use common::Config;

/// Conversion table from triple OS name to Rust SYSNAME
const OS_TABLE: &'static [(&'static str, &'static str)] = &[
    ("mingw32", "windows"),
    ("win32", "windows"),
    ("windows", "windows"),
    ("darwin", "macos"),
    ("android", "android"),
    ("linux", "linux"),
    ("freebsd", "freebsd"),
    ("dragonfly", "dragonfly"),
    ("bitrig", "bitrig"),
    ("openbsd", "openbsd"),
];

const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
    ("i386", "x86"),
    ("i686", "x86"),
    ("amd64", "x86_64"),
    ("x86_64", "x86_64"),
    ("sparc", "sparc"),
    ("powerpc", "powerpc"),
    ("arm64", "aarch64"),
    ("arm", "arm"),
    ("aarch64", "aarch64"),
    ("mips", "mips"),
    ("xcore", "xcore"),
    ("msp430", "msp430"),
    ("hexagon", "hexagon"),
    ("s390x", "systemz"),
];

pub fn get_os(triple: &str) -> &'static str {
    for &(triple_os, os) in OS_TABLE {
        if triple.contains(triple_os) {
            return os
        }
    }
    panic!("Cannot determine OS from triple");
}
pub fn get_arch(triple: &str) -> &'static str {
    for &(triple_arch, arch) in ARCH_TABLE {
        if triple.contains(triple_arch) {
            return arch
        }
    }
    panic!("Cannot determine Architecture from triple");
}

pub fn make_new_path(path: &str) -> String {
    assert!(cfg!(windows));
    // Windows just uses PATH as the library search path, so we have to
    // maintain the current value while adding our own
    match env::var(lib_path_env_var()) {
        Ok(curr) => {
            format!("{}{}{}", path, path_div(), curr)
        }
        Err(..) => path.to_string()
    }
}

pub fn lib_path_env_var() -> &'static str { "PATH" }
fn path_div() -> &'static str { ";" }

pub fn logv(config: &Config, s: String) {
    debug!("{}", s);
    if config.verbose { println!("{}", s); }
}
<commit_msg>Alphabetize<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use common::Config;

/// Conversion table from triple OS name to Rust SYSNAME
const OS_TABLE: &'static [(&'static str, &'static str)] = &[
    ("android", "android"),
    ("bitrig", "bitrig"),
    ("darwin", "macos"),
    ("dragonfly", "dragonfly"),
    ("freebsd", "freebsd"),
    ("linux", "linux"),
    ("mingw32", "windows"),
    ("openbsd", "openbsd"),
    ("win32", "windows"),
    ("windows", "windows"),
];

const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
    ("aarch64", "aarch64"),
    ("amd64", "x86_64"),
    ("arm", "arm"),
    ("arm64", "aarch64"),
    ("hexagon", "hexagon"),
    ("i386", "x86"),
    ("i686", "x86"),
    ("mips", "mips"),
    ("msp430", "msp430"),
    ("powerpc", "powerpc"),
    ("s390x", "systemz"),
    ("sparc", "sparc"),
    ("x86_64", "x86_64"),
    ("xcore", "xcore"),
];

pub fn get_os(triple: &str) -> &'static str {
    for &(triple_os, os) in OS_TABLE {
        if triple.contains(triple_os) {
            return os
        }
    }
    panic!("Cannot determine OS from triple");
}
pub fn get_arch(triple: &str) -> &'static str {
    for &(triple_arch, arch) in ARCH_TABLE {
        if triple.contains(triple_arch) {
            return arch
        }
    }
    panic!("Cannot determine Architecture from triple");
}

pub fn make_new_path(path: &str) -> String {
    assert!(cfg!(windows));
    // Windows just uses PATH as the library search path, so we have to
    // maintain the current value while adding our own
    match env::var(lib_path_env_var()) {
        Ok(curr) => {
            format!("{}{}{}", path, path_div(), curr)
        }
        Err(..) => path.to_string()
    }
}

pub fn lib_path_env_var() -> &'static str { "PATH" }
fn path_div() -> &'static str { ";" }

pub fn logv(config: &Config, s: String) {
    debug!("{}", s);
    if config.verbose { println!("{}", s); }
}
<|endoftext|>


<commit_before>// Copyright 2015 Jauhien Piatlicki.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Core LLVM: Instructions hierarchy
// LLVM-C header Core.h

use std;

use libc::c_uint;

use llvm_sys::*;
use llvm_sys::prelude::*;
use llvm_sys::core::*;

use ::{LLVMRef, LLVMRefCtor};
use core::value::{Value, ValueCtor};

pub trait Instruction : Value + ValueCtor {
    fn get_parent(&self) -> LLVMBasicBlockRef {
        unsafe {
            LLVMGetInstructionParent(self.to_ref())
        }
    }

    fn get_next(&self) -> Self {
        unsafe {
            Self::from_ref(LLVMGetNextInstruction(self.to_ref()))
        }
    }

    fn get_previous(&self) -> Self {
        unsafe {
            Self::from_ref(LLVMGetPreviousInstruction(self.to_ref()))
        }
    }

    fn erase_from_parent(mut self) {
        unsafe {
            LLVMInstructionEraseFromParent(self.to_ref())
        }
    }

    fn get_opcode(&self) -> LLVMOpcode {
        unsafe {
            LLVMGetInstructionOpcode(self.to_ref())
        }
    }
}

new_ref_type!(InstructionRef for LLVMValueRef
              implementing
              Value,
              ValueCtor,
              Instruction
              );

pub trait PHINode : Instruction {
    fn add_incoming(&mut self, incoming_values: &mut [LLVMValueRef], incoming_blocks: &mut [LLVMBasicBlockRef]) {
        assert!(incoming_values.len() == incoming_blocks.len());
        unsafe {
            LLVMAddIncoming(self.to_ref(),
                            incoming_values.as_mut_ptr(),
                            incoming_blocks.as_mut_ptr(),
                            incoming_values.len() as c_uint)
        }
    }

    fn count_incoming(&self) -> u32 {
        unsafe {
            LLVMCountIncoming(self.to_ref())
        }
    }

    fn get_incoming_value(&self, index: u32) -> Option<LLVMValueRef> {
        if index < self.count_incoming() {
            unsafe {
                Some(LLVMGetIncomingValue(self.to_ref(), index))
            }
        } else {
            None
        }
    }

    fn get_incoming_block(&self, index: u32) -> Option<LLVMBasicBlockRef> {
        if index < self.count_incoming() {
            unsafe {
                Some(LLVMGetIncomingBlock(self.to_ref(), index))
            }
        } else {
            None
        }
    }
}

new_ref_type!(PHINodeRef for LLVMValueRef
              implementing
              Value,
              ValueCtor,
              Instruction,
              PHINode
              );
<commit_msg>[core] make it possible to have Instruction trait objects<commit_after>// Copyright 2015 Jauhien Piatlicki.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Core LLVM: Instructions hierarchy
// LLVM-C header Core.h

use std;

use libc::c_uint;

use llvm_sys::*;
use llvm_sys::prelude::*;
use llvm_sys::core::*;

use ::{LLVMRef, LLVMRefCtor};
use core::value::{Value, ValueCtor};

pub trait Instruction : Value {
    fn get_parent(&self) -> LLVMBasicBlockRef {
        unsafe {
            LLVMGetInstructionParent(self.to_ref())
        }
    }

    fn get_next(&self) -> InstructionRef {
        unsafe {
            InstructionRef::from_ref(LLVMGetNextInstruction(self.to_ref()))
        }
    }

    fn get_previous(&self) -> InstructionRef {
        unsafe {
            InstructionRef::from_ref(LLVMGetPreviousInstruction(self.to_ref()))
        }
    }

    //TODO fix ownership
    fn erase_from_parent(&mut self) {
        unsafe {
            LLVMInstructionEraseFromParent(self.to_ref())
        }
    }

    fn get_opcode(&self) -> LLVMOpcode {
        unsafe {
            LLVMGetInstructionOpcode(self.to_ref())
        }
    }
}

new_ref_type!(InstructionRef for LLVMValueRef
              implementing
              Value,
              ValueCtor,
              Instruction
              );

pub trait PHINode : Instruction {
    fn add_incoming(&mut self, incoming_values: &mut [LLVMValueRef], incoming_blocks: &mut [LLVMBasicBlockRef]) {
        assert!(incoming_values.len() == incoming_blocks.len());
        unsafe {
            LLVMAddIncoming(self.to_ref(),
                            incoming_values.as_mut_ptr(),
                            incoming_blocks.as_mut_ptr(),
                            incoming_values.len() as c_uint)
        }
    }

    fn count_incoming(&self) -> u32 {
        unsafe {
            LLVMCountIncoming(self.to_ref())
        }
    }

    fn get_incoming_value(&self, index: u32) -> Option<LLVMValueRef> {
        if index < self.count_incoming() {
            unsafe {
                Some(LLVMGetIncomingValue(self.to_ref(), index))
            }
        } else {
            None
        }
    }

    fn get_incoming_block(&self, index: u32) -> Option<LLVMBasicBlockRef> {
        if index < self.count_incoming() {
            unsafe {
                Some(LLVMGetIncomingBlock(self.to_ref(), index))
            }
        } else {
            None
        }
    }
}

new_ref_type!(PHINodeRef for LLVMValueRef
              implementing
              Value,
              ValueCtor,
              Instruction,
              PHINode
              );
<|endoftext|>


<commit_before>//! Debugger commands
use std::convert::From;
use std::char;

use super::Debugger;
use cpu::instruction::Operation;

/// The commands runnable by the debugger
#[derive(Debug, PartialEq, Eq)]
pub enum Command {
    Registers,
    Help,
    Unknown,
    Step,
    Run,
    Quit,
    Breakpoint,
    Memory,
}

impl<'a> From<&'a str> for Command {
    fn from(s: &'a str) -> Command {
        match s {
            "q" | "quit" => Command::Quit,
            "h" | "?" | "help" => Command::Help,
            "s" | "step" => Command::Step,
            "r" | "registers" => Command::Registers,
            "c" | "run" => Command::Run,
            "bp" | "breakpoint" => Command::Breakpoint,
            "m" | "memory" => Command::Memory,
            _ => Command::Unknown,
        }
    }
}

impl Command {
    pub fn execute(&self,
               dbg: &mut Debugger,
               args: &[&str]) {
        use self::Command::*;
        match *self {
            Help => {
                println!("The following commands are available. Short forms are listed\
                          in brackets after the long form. Options, if any are listed\
                          after the short forms");
                println!("\thelp (h, ?) - Print this message");
            },
            Step => {
                let times = if args.is_empty() {
                    1
                } else if let Ok(n) = args[0].parse::<usize>() {
                    n
                } else {
                    println!("Usage: step [n] - n is an optional integer (default: 1), the number of steps to take.");
                    return;
                };

                for _ in 0..times {
                    println!(" [0x{:0>4x}]: {}",
                             dbg.cpu.pc,
                             dbg.cpu.peek_op());
                    dbg.cpu.step();
                }

            },
            Run => {
                dbg.cpu.run();
            },
            Registers => {
                println!("r0 = 0x{:0>4x}, r1 = 0x{:0>4x}, r2 = 0x{:0>4x}, r3 = 0x{:0>4x}",
                         dbg.cpu.data.registers[0],
                         dbg.cpu.data.registers[1],
                         dbg.cpu.data.registers[2],
                         dbg.cpu.data.registers[3]);
                println!("r4 = 0x{:0>4x}, r5 = 0x{:0>4x}, r6 = 0x{:0>4x}, r7 = 0x{:0>4x}",
                         dbg.cpu.data.registers[4],
                         dbg.cpu.data.registers[5],
                         dbg.cpu.data.registers[6],
                         dbg.cpu.data.registers[7]);
            },
            Breakpoint => {
                let usage = "breakpoint list         - Lists all breakpoints.\n\
                             breakpoint set [addr]   - Set a breakpoint at the given address.\n\
                             breakpoint unset [addr] - Unset the breakpoint at the given address.";
                if args.is_empty() {
                    println!("{}", usage);
                    return;
                }

                match args[0] {
                    "list" => {
                        println!("Set breakpoints:");
                        for addr in dbg.breakpoints.iter() {
                            println!("\t0x{:0>4x}", addr);
                        }
                    },
                    "set" => {
                        let addrs = (&args[1..]).iter()
                            .map(|addr| if addr.starts_with("0x") {
                                usize::from_str_radix(&addr[2..], 16)
                            } else {
                                usize::from_str_radix(addr, 16)
                            })
                            .filter(|addr| addr.is_ok())
                            .map(|addr| addr.unwrap());

                        for addr in addrs {
                            if Operation::is_valid(addr, &dbg.cpu.data.ram) {
                                dbg.cpu.data.ram[addr] |= 0xcc00;
                                dbg.breakpoints.insert(addr);
                                println!("Added breakpoint at 0x{:0>4x}", addr);
                            } else {
                                println!("Address 0x{:0>4x} is not a valid instruction",
                                         addr);
                            }
                        }
                    },
                    "unset" => {
                        let addrs = (&args[1..]).iter()
                            .map(|addr| if addr.starts_with("0x") {
                                usize::from_str_radix(&addr[2..], 16)
                            } else {
                                usize::from_str_radix(addr, 16)
                            })
                            .filter(|addr| addr.is_ok())
                            .map(|addr| addr.unwrap());

                        for addr in addrs {
                            if dbg.breakpoints.contains(&addr) {
                                dbg.breakpoints.remove(&addr);
                                dbg.cpu.data.ram[addr] &= 0x00ff;
                                println!("Breakpoint 0x{:0>4x} removed", addr);
                            } else {
                                println!("Address 0x{:0>4x} is not a breakpoint.",
                                         addr);
                            }
                        }
                    },
                    _ => {
                        println!("{}", usage);
                        return;
                    }
                }
            },
            Memory => {
                let start = if let Some(word) = args.get(0) {
                    if let Ok(num) = if word.starts_with("0x") {
                        usize::from_str_radix(&word[2..], 16)
                    } else {
                        usize::from_str_radix(word, 16)
                    } {
                        num
                    } else {
                        dbg.cpu.pc as usize
                    }
                } else {
                    dbg.cpu.pc as usize
                };

                let lines = if let Some(word) = args.get(1) {
                    if let Ok(num) = word.parse::<usize>() {
                        num
                    } else {
                        10
                    }
                } else {
                    10
                };

                println!("addr  0000 1111 2222 3333 4444 5555 6666 7777  01234567");
                println!("-----|----|----|----|----|----|----|----|----||--------|");
                for j in 0..lines {
                    if start + 8*j > dbg.cpu.data.ram.len() {
                        break;
                    }
                    let mut hexs = String::new();
                    let mut printable = String::new();

                    print!("{:0>4x}: ", start + 8*j);

                    for i in 0..8 {
                        let offset = start + i + 8*j;
                        if offset >= dbg.cpu.data.ram.len() {
                            hexs.push_str("END!");
                            break;
                        }
                        let val = dbg.cpu.data.ram[offset];
                        if let Some(c) = char::from_u32(val as u32) {
                            if c.is_alphanumeric() {
                                printable.push(c);
                            } else {
                                printable.push('.');
                            }
                        } else {
                            printable.push('.');
                        }

                        hexs.push_str(&format!("{:0>4x} ", val));
                    }
                    println!("{:40} {}", hexs, printable);
                }
            }
            Quit | Unknown => {}
        }
    }
}

<commit_msg>Added a restart command to the debugger<commit_after>//! Debugger commands
use std::convert::From;
use std::char;

use super::Debugger;
use cpu::instruction::Operation;
use cpu::{SynCpu, Data};

/// The commands runnable by the debugger
#[derive(Debug, PartialEq, Eq)]
pub enum Command {
    Registers,
    Help,
    Unknown,
    Step,
    Run,
    Quit,
    Breakpoint,
    Memory,
    Restart,
}

impl<'a> From<&'a str> for Command {
    fn from(s: &'a str) -> Command {
        match s {
            "q" | "quit" => Command::Quit,
            "h" | "?" | "help" => Command::Help,
            "s" | "step" => Command::Step,
            "r" | "registers" => Command::Registers,
            "c" | "run" => Command::Run,
            "bp" | "breakpoint" => Command::Breakpoint,
            "m" | "memory" => Command::Memory,
            "restart" => Command::Restart,
            _ => Command::Unknown,
        }
    }
}

impl Command {
    pub fn execute(&self,
               dbg: &mut Debugger,
               args: &[&str]) {
        use self::Command::*;
        match *self {
            Help => {
                println!("The following commands are available. Short forms are listed\
                          in brackets after the long form. Options, if any are listed\
                          after the short forms");
                println!("\thelp (h, ?)               - Print this message");
                println!("\tstep (s) [n]              - Step through n instructions (default = 1)");
                println!("\tregisters (r)             - Print the registers");
                println!("\trun (c)                   - Run execution until a breakpoint is hit or the CPU halts.");
                println!("\tbreakpoint (bp)           - Set, unset, or list breakpoints.");
                println!("\tmemory (m) [addr] [lines] - Print 20 lines of 8 16-bit entries from RAM, starting at addr. Default lines = 10, default addr = pc");
                println!("\trestart                   - Restart the program.");
            },
            Step => {
                let times = if args.is_empty() {
                    1
                } else if let Ok(n) = args[0].parse::<usize>() {
                    n
                } else {
                    println!("Usage: step [n] - n is an optional integer (default: 1), the number of steps to take.");
                    return;
                };

                for _ in 0..times {
                    println!(" [0x{:0>4x}]: {}",
                             dbg.cpu.pc,
                             dbg.cpu.peek_op());
                    dbg.cpu.step();
                }

            },
            Run => {
                dbg.cpu.run();
            },
            Registers => {
                println!("r0 = 0x{:0>4x}, r1 = 0x{:0>4x}, r2 = 0x{:0>4x}, r3 = 0x{:0>4x}",
                         dbg.cpu.data.registers[0],
                         dbg.cpu.data.registers[1],
                         dbg.cpu.data.registers[2],
                         dbg.cpu.data.registers[3]);
                println!("r4 = 0x{:0>4x}, r5 = 0x{:0>4x}, r6 = 0x{:0>4x}, r7 = 0x{:0>4x}",
                         dbg.cpu.data.registers[4],
                         dbg.cpu.data.registers[5],
                         dbg.cpu.data.registers[6],
                         dbg.cpu.data.registers[7]);
            },
            Breakpoint => {
                let usage = "breakpoint list         - Lists all breakpoints.\n\
                             breakpoint set [addr]   - Set a breakpoint at the given address.\n\
                             breakpoint unset [addr] - Unset the breakpoint at the given address.";
                if args.is_empty() {
                    println!("{}", usage);
                    return;
                }

                match args[0] {
                    "list" => {
                        println!("Set breakpoints:");
                        for addr in dbg.breakpoints.iter() {
                            println!("\t0x{:0>4x}", addr);
                        }
                    },
                    "set" => {
                        let addrs = (&args[1..]).iter()
                            .map(|addr| if addr.starts_with("0x") {
                                usize::from_str_radix(&addr[2..], 16)
                            } else {
                                usize::from_str_radix(addr, 16)
                            })
                            .filter(|addr| addr.is_ok())
                            .map(|addr| addr.unwrap());

                        for addr in addrs {
                            if Operation::is_valid(addr, &dbg.cpu.data.ram) {
                                dbg.cpu.data.ram[addr] |= 0xcc00;
                                dbg.breakpoints.insert(addr);
                                println!("Added breakpoint at 0x{:0>4x}", addr);
                            } else {
                                println!("Address 0x{:0>4x} is not a valid instruction",
                                         addr);
                            }
                        }
                    },
                    "unset" => {
                        let addrs = (&args[1..]).iter()
                            .map(|addr| if addr.starts_with("0x") {
                                usize::from_str_radix(&addr[2..], 16)
                            } else {
                                usize::from_str_radix(addr, 16)
                            })
                            .filter(|addr| addr.is_ok())
                            .map(|addr| addr.unwrap());

                        for addr in addrs {
                            if dbg.breakpoints.contains(&addr) {
                                dbg.breakpoints.remove(&addr);
                                dbg.cpu.data.ram[addr] &= 0x00ff;
                                println!("Breakpoint 0x{:0>4x} removed", addr);
                            } else {
                                println!("Address 0x{:0>4x} is not a breakpoint.",
                                         addr);
                            }
                        }
                    },
                    _ => {
                        println!("{}", usage);
                        return;
                    }
                }
            },
            Memory => {
                let start = if let Some(word) = args.get(0) {
                    if let Ok(num) = if word.starts_with("0x") {
                        usize::from_str_radix(&word[2..], 16)
                    } else {
                        usize::from_str_radix(word, 16)
                    } {
                        num
                    } else {
                        dbg.cpu.pc as usize
                    }
                } else {
                    dbg.cpu.pc as usize
                };

                let lines = if let Some(word) = args.get(1) {
                    if let Ok(num) = word.parse::<usize>() {
                        num
                    } else {
                        10
                    }
                } else {
                    10
                };

                println!("addr  0000 1111 2222 3333 4444 5555 6666 7777  01234567");
                println!("-----|----|----|----|----|----|----|----|----||--------|");
                for j in 0..lines {
                    if start + 8*j > dbg.cpu.data.ram.len() {
                        break;
                    }
                    let mut hexs = String::new();
                    let mut printable = String::new();

                    print!("{:0>4x}: ", start + 8*j);

                    for i in 0..8 {
                        let offset = start + i + 8*j;
                        if offset >= dbg.cpu.data.ram.len() {
                            hexs.push_str("END!");
                            break;
                        }
                        let val = dbg.cpu.data.ram[offset];
                        if let Some(c) = char::from_u32(val as u32) {
                            if c.is_alphanumeric() {
                                printable.push(c);
                            } else {
                                printable.push('.');
                            }
                        } else {
                            printable.push('.');
                        }

                        hexs.push_str(&format!("{:0>4x} ", val));
                    }
                    println!("{:40} {}", hexs, printable);
                }
            },
            Restart => {
                let data = Data::from_bin(&dbg.original_binary).unwrap();
                dbg.cpu = SynCpu::new(data);
            }
            Quit | Unknown => {}
        }
    }
}

<|endoftext|>


<commit_before>//! Defines common interfaces for interacting with statistical distributions and provides
//! concrete implementations for a variety of distributions.

use rand::Rng;
use super::result::Result;

pub use self::bernoulli::Bernoulli;
pub use self::binomial::Binomial;
pub use self::chi::Chi;
pub use self::chi_squared::ChiSquared;
pub use self::discrete_uniform::DiscreteUniform;
pub use self::exponential::Exponential;
pub use self::gamma::Gamma;
pub use self::log_normal::LogNormal;
pub use self::normal::Normal;
pub use self::poisson::Poisson;
pub use self::student_t::StudentT;
pub use self::triangular::Triangular;
pub use self::uniform::Uniform;
pub use self::weibull::Weibull;

mod bernoulli;
mod binomial;
mod chi;
mod chi_squared;
mod discrete_uniform;
mod exponential;
mod gamma;
mod log_normal;
mod normal;
mod poisson;
mod student_t;
mod triangular;
mod uniform;
mod weibull;

/// The `Distribution` trait is used to specify an interface
/// for sampling distributions
///
/// # Examples
///
/// A trivial implementation that just samples from the supplied
/// random number generator
///
/// ```
/// use rand::StdRng;
///
/// struct Foo;
///
/// impl Distribution for Foo {
///     fn sample<R: Rng>(&self, r: &mut R) -> f64 {
///         r.next_f64()
///     }
/// }
/// ```
pub trait Distribution {
    /// Draws a random sample using the supplied random number generator
    fn sample<R: Rng>(&self, r: &mut R) -> f64;
}

/// The `Univariate` trait extends the `Distribution`
/// trait provides an interface for interacting with
/// univariate statistical distributions.
///
/// # Remarks
///
/// All methods provided by the `Univariate` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedUnivariate`
/// trait provides a panic-safe interface for univariate distributions
pub trait Univariate : Distribution {
    /// Returns the mean for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.mean());
    /// ```
    fn mean(&self) -> f64;

    /// Returns the variance for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(1.0 / 12.0, n.variance());
    /// ```
    fn variance(&self) -> f64;

    /// Returns the standard deviation for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!((1f64 / 12f64).sqrt(), n.std_dev());
    /// ```
    fn std_dev(&self) -> f64;

    /// Returns the entropy for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.entropy());
    /// ```
    fn entropy(&self) -> f64;

    /// Returns the skewness for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.skewness());
    /// ```
    fn skewness(&self) -> f64;

    /// Returns the median for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.median());
    /// ```
    fn median(&self) -> f64;

    /// Returns the cumulative distribution function calculated
    /// at `x` for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.cdf(0.5));
    /// ```
    fn cdf(&self, x: f64) -> f64;
}

/// The `CheckedUnivariate` trait extends the `Distribution` trait and
/// provides a checked interface for interacting with univariate statistical
/// distributions. This means implementors should return an `Err` instead of
/// panicking on an invalid state or input.
pub trait CheckedUnivariate : Distribution {
    /// Returns the mean for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic
    /// but return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.mean().unwrap());
    /// ```
    fn mean(&self) -> Result<f64>;

    /// Returns the variance for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic
    /// but return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(1.0 / 12.0, n.variance().unwrap());
    /// ```
    fn variance(&self) -> Result<f64>;

    /// Returns the standard deviation for a given distribution or
    /// a `StatsError` depending on the implementor. This method should
    /// not panic but return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!((1f64 / 12f64).sqrt(), n.std_dev().unwrap());
    /// ```
    fn std_dev(&self) -> Result<f64>;

    /// Returns the entropy for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic but
    /// return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.entropy().unwrap());
    /// ```
    fn entropy(&self) -> Result<f64>;

    /// Returns the skewness for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic but
    /// return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.skewness().unwrap());
    /// ```
    fn skewness(&self) -> Result<f64>;

    /// Returns the median for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic but
    /// return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.median());
    /// ```
    fn median(&self) -> Result<f64>;

    /// Returns the cumulative distribution function calculated
    /// at `x` for a given distribution or a `StatsError` depending
    /// on the implementor. This method should not panic but return a
    /// `StatsError` instead. `StatsError`s should be returned for argument
    /// bound violations.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.cdf(0.5));
    /// ```
    fn cdf(&self) -> Result<f64>;
}

/// The `Continuous` trait extends the `Univariate`
/// trait and provides an interface for interacting with continuous
/// univariate statistical distributions
///
/// # Remarks
///
/// All methods provided by the `Continuous` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedContinuous`
/// trait provides a panic-safe interface for continuous distributions
pub trait Continuous : Univariate {
    fn mode(&self) -> f64;
    fn min(&self) -> f64;
    fn max(&self) -> f64;
    fn pdf(&self, x: f64) -> f64;
    fn ln_pdf(&self, x: f64) -> f64;
}

/// The `CheckedContinous` trait extends the `CheckedUnivariate`
/// trait and provides a checked interface for interacting with
/// continous univariate statistical distributions. This means
/// implementors should return an `Err` instead of panicking on
/// an invalid state or input.
pub trait CheckedContinuous : CheckedUnivariate {
    fn mode(&self) -> Result<f64>;
    fn min(&self) -> Result<f64>;
    fn max(&self) -> Result<f64>;
    fn pdf(&self, x: f64) -> Result<f64>;
    fn ln_pdf(&self, x: f64) -> Result<f64>;
}

/// The `Discrete` trait extends the `Univariate`
/// trait and provides an interface for interacting with discrete
/// univariate statistical distributions
///
/// # Remakrs
///
/// All methods provided by the `Discrete` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedDiscrete` trait
/// provides a panic-safe interface for discrete distributions
pub trait Discrete : Univariate {
    fn mode(&self) -> i64;
    fn min(&self) -> i64;
    fn max(&self) -> i64;
    fn pmf(&self, x: i64) -> f64;
    fn ln_pmf(&self, x: i64) -> f64;
}

/// The `CheckedDiscrete` trait extends the `CheckedUnivariate` trait
/// and provides a checked interface for interacting with discrete
/// univariate statistical distributions. This means implementors
/// should return an `Err` instead of panicking on an invalid state
/// or input
pub trait CheckedDiscrete : CheckedUnivariate {
    fn mode(&self) -> Result<i64>;
    fn min(&self) -> Result<i64>;
    fn max(&self) -> Result<i64>;
    fn pmf(&self, x: i64) -> Result<f64>;
    fn ln_pmf(&self, x: i64) -> Result<f64>;
}<commit_msg>change `Err` to `StatsError` in doc comments<commit_after>//! Defines common interfaces for interacting with statistical distributions and provides
//! concrete implementations for a variety of distributions.

use rand::Rng;
use super::result::Result;

pub use self::bernoulli::Bernoulli;
pub use self::binomial::Binomial;
pub use self::chi::Chi;
pub use self::chi_squared::ChiSquared;
pub use self::discrete_uniform::DiscreteUniform;
pub use self::exponential::Exponential;
pub use self::gamma::Gamma;
pub use self::log_normal::LogNormal;
pub use self::normal::Normal;
pub use self::poisson::Poisson;
pub use self::student_t::StudentT;
pub use self::triangular::Triangular;
pub use self::uniform::Uniform;
pub use self::weibull::Weibull;

mod bernoulli;
mod binomial;
mod chi;
mod chi_squared;
mod discrete_uniform;
mod exponential;
mod gamma;
mod log_normal;
mod normal;
mod poisson;
mod student_t;
mod triangular;
mod uniform;
mod weibull;

/// The `Distribution` trait is used to specify an interface
/// for sampling distributions
///
/// # Examples
///
/// A trivial implementation that just samples from the supplied
/// random number generator
///
/// ```
/// use rand::StdRng;
///
/// struct Foo;
///
/// impl Distribution for Foo {
///     fn sample<R: Rng>(&self, r: &mut R) -> f64 {
///         r.next_f64()
///     }
/// }
/// ```
pub trait Distribution {
    /// Draws a random sample using the supplied random number generator
    fn sample<R: Rng>(&self, r: &mut R) -> f64;
}

/// The `Univariate` trait extends the `Distribution`
/// trait provides an interface for interacting with
/// univariate statistical distributions.
///
/// # Remarks
///
/// All methods provided by the `Univariate` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedUnivariate`
/// trait provides a panic-safe interface for univariate distributions
pub trait Univariate : Distribution {
    /// Returns the mean for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.mean());
    /// ```
    fn mean(&self) -> f64;

    /// Returns the variance for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(1.0 / 12.0, n.variance());
    /// ```
    fn variance(&self) -> f64;

    /// Returns the standard deviation for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!((1f64 / 12f64).sqrt(), n.std_dev());
    /// ```
    fn std_dev(&self) -> f64;

    /// Returns the entropy for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.entropy());
    /// ```
    fn entropy(&self) -> f64;

    /// Returns the skewness for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.skewness());
    /// ```
    fn skewness(&self) -> f64;

    /// Returns the median for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.median());
    /// ```
    fn median(&self) -> f64;

    /// Returns the cumulative distribution function calculated
    /// at `x` for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.cdf(0.5));
    /// ```
    fn cdf(&self, x: f64) -> f64;
}

/// The `CheckedUnivariate` trait extends the `Distribution` trait and
/// provides a checked interface for interacting with univariate statistical
/// distributions. This means implementors should return an `StatsError` instead of
/// panicking on an invalid state or input.
pub trait CheckedUnivariate : Distribution {
    /// Returns the mean for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic
    /// but return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.mean().unwrap());
    /// ```
    fn mean(&self) -> Result<f64>;

    /// Returns the variance for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic
    /// but return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(1.0 / 12.0, n.variance().unwrap());
    /// ```
    fn variance(&self) -> Result<f64>;

    /// Returns the standard deviation for a given distribution or
    /// a `StatsError` depending on the implementor. This method should
    /// not panic but return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!((1f64 / 12f64).sqrt(), n.std_dev().unwrap());
    /// ```
    fn std_dev(&self) -> Result<f64>;

    /// Returns the entropy for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic but
    /// return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.entropy().unwrap());
    /// ```
    fn entropy(&self) -> Result<f64>;

    /// Returns the skewness for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic but
    /// return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.skewness().unwrap());
    /// ```
    fn skewness(&self) -> Result<f64>;

    /// Returns the median for a given distribution or a `StatsError`
    /// depending on the implementor. This method should not panic but
    /// return a `StatsError` instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.median());
    /// ```
    fn median(&self) -> Result<f64>;

    /// Returns the cumulative distribution function calculated
    /// at `x` for a given distribution or a `StatsError` depending
    /// on the implementor. This method should not panic but return a
    /// `StatsError` instead. `StatsError`s should be returned for argument
    /// bound violations.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.cdf(0.5));
    /// ```
    fn cdf(&self) -> Result<f64>;
}

/// The `Continuous` trait extends the `Univariate`
/// trait and provides an interface for interacting with continuous
/// univariate statistical distributions
///
/// # Remarks
///
/// All methods provided by the `Continuous` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedContinuous`
/// trait provides a panic-safe interface for continuous distributions
pub trait Continuous : Univariate {
    fn mode(&self) -> f64;
    fn min(&self) -> f64;
    fn max(&self) -> f64;
    fn pdf(&self, x: f64) -> f64;
    fn ln_pdf(&self, x: f64) -> f64;
}

/// The `CheckedContinous` trait extends the `CheckedUnivariate`
/// trait and provides a checked interface for interacting with
/// continous univariate statistical distributions. This means
/// implementors should return an `StatsError` instead of panicking on
/// an invalid state or input.
pub trait CheckedContinuous : CheckedUnivariate {
    fn mode(&self) -> Result<f64>;
    fn min(&self) -> Result<f64>;
    fn max(&self) -> Result<f64>;
    fn pdf(&self, x: f64) -> Result<f64>;
    fn ln_pdf(&self, x: f64) -> Result<f64>;
}

/// The `Discrete` trait extends the `Univariate`
/// trait and provides an interface for interacting with discrete
/// univariate statistical distributions
///
/// # Remakrs
///
/// All methods provided by the `Discrete` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedDiscrete` trait
/// provides a panic-safe interface for discrete distributions
pub trait Discrete : Univariate {
    fn mode(&self) -> i64;
    fn min(&self) -> i64;
    fn max(&self) -> i64;
    fn pmf(&self, x: i64) -> f64;
    fn ln_pmf(&self, x: i64) -> f64;
}

/// The `CheckedDiscrete` trait extends the `CheckedUnivariate` trait
/// and provides a checked interface for interacting with discrete
/// univariate statistical distributions. This means implementors
/// should return an `StatsError` instead of panicking on an invalid state
/// or input
pub trait CheckedDiscrete : CheckedUnivariate {
    fn mode(&self) -> Result<i64>;
    fn min(&self) -> Result<i64>;
    fn max(&self) -> Result<i64>;
    fn pmf(&self, x: i64) -> Result<f64>;
    fn ln_pmf(&self, x: i64) -> Result<f64>;
}<|endoftext|>


<commit_before>#![feature(convert)]

extern crate gr;
use gr::*;

enum OpType {
    Func(String),
    Const(usize),
    Var(usize),
    UVar(usize),
    Op(String),
    Pow(i32)
}

struct FuncObj {
    user_vars: Vec<GI>,
    constants: Vec<GI>,
    instructions: Vec<OpType>,
    switched: bool,
    func: Box<fn(&Vec<GI>) -> GI>
}

fn dummy(_x: &Vec<GI>) -> GI {
    GI::new_c("1.0")
}

impl FuncObj {
    pub fn call(&self, _x: &Vec<GI>) -> GI {
        if self.switched {
            func(_x)
        }
        else {
            self.interpreted(_x)
        }
    }

    fn interpreted(&self, _x: &Vec<GI>) -> GI {
        let mut stack: Vec<GI> = Vec::new();
        for inst in &self.instructions {
            match inst {
                &OpType::Func(ref s) => {
                    let op = stack.pop().unwrap();
                    let result = match s.as_str() {
                        "abs" => abs(op),
                        "sin" => sin(op),
                        "cos" => cos(op),
                        "tan" => tan(op),
                        "exp" => exp(op),
                        "log" => log(op),
                        "neg" => -op,
                        _     => unreachable!()
                    };
                    stack.push(result);
                },
                &OpType::Const(i) => {
                    stack.push(self.constants[i]);
                },
                &OpType::Var(i) => {
                    stack.push(_x[i]);
                },
                &OpType::UVar(i) => {
                    stack.push(self.user_vars[i]);
                },
                &OpType::Op(ref s) => {
                    let right = stack.pop().unwrap();
                    let left = stack.pop().unwrap();
                    let result = match s.as_str() {
                        "+" => left + right,
                        "-" => left - right,
                        "*" => left * right,
                        "/" => left / right,
                        "p" => powi(left, right),
                        _   => unreachable!()
                    };
                    stack.push(result);
                },
                &OpType::Pow(exp) => {
                    let arg = stack.pop().unwrap();
                    stack.push(gr::pow(arg, exp));
                }
            }
        }
        stack[0]
    }

    fn new(consts: &Vec<GI>, instructions: &String) -> FuncObj {
        let mut insts = vec![];

        for inst in instructions.split(',') {
            let mut first = true;
            let mut tmp = "".to_string();
            let mut result = OpType::Const(0);
            for c in inst.to_string().trim().to_string().chars() {
                if first {
                    match c {
                        'c' => {result = OpType::Const(0)},
                        'i' => {result = OpType::Var(0)},
                        'v' => {result = OpType::UVar(0)},
                        'o' => {result = OpType::Op("".to_string())},
                        'f' => {result = OpType::Func("".to_string())},
                        'p' => {result = OpType::Pow(0)},
                        _   => unreachable!()
                    }
                    first = false;
                }
                else {tmp.push(c);}
            }
            insts.push(match result {
                OpType::Const(_) => OpType::Const(tmp.parse::<usize>().unwrap()),
                OpType::Var(_) => OpType::Var(tmp.parse::<usize>().unwrap()),
                OpType::UVar(_) => OpType::UVar(tmp.parse::<usize>().unwrap()),
                OpType::Op(_) => OpType::Op(tmp),
                OpType::Func(_) => OpType::Func(tmp),
                OpType::Pow(_) => OpType::Pow(tmp.parse::<i32>().unwrap()),
            });
        }

        FuncObj{user_vars: vec![],
                constants: consts.clone(),
                instructions: insts,
                switched: false,
                func: Box::new(dummy)}
    }
}

#[test]
fn test1() {
    let constants = vec![GI::new_c("1"), GI::new_c("2"), GI::new_c("3")];
    let f = FuncObj::new(&constants,
                         &"c0,c1,o-,c2,o+".to_string());
    let expected = ((GI::new_c("1") - GI::new_c("2")) + GI::new_c("3")).to_string();
    assert!(f.call(&vec![]).to_string() == expected);
}

#[test]
fn test2() {
    let consts = vec![GI::new_c("1"), GI::new_c("2"), GI::new_c("3")];
    let f = FuncObj::new(&consts,
                         &"c0,fsin,c1,o*,fcos,c2,o/".to_string());
    let expected = cos(sin(consts[0]) * consts[1])/consts[2];
    assert!(f.call(&vec![]).to_string() == expected.to_string());
}

#[test]
fn sum_inputs() {
    let consts = vec![];
    let v = vec![GI::new_d(1.0, 1.0), GI::new_d(1.0, 2.0), GI::new_d(1.0, 3.0),
                 GI::new_d(1.0, 4.0), GI::new_d(1.0, 5.0), GI::new_d(1.0, 6.0)];
    let f = FuncObj::new(&consts,
                         &"i0,i1, o+, i2, o+, i3, o+, i4, o+, i5, o+".to_string());
    let expected = (v[0] + v[1] + v[2] + v[3] + v[4] + v[5]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test3() {
    let consts = vec![GI::new_c("0.1")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fsin".to_string());
    let expected = sin(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test4() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fabs".to_string());
    let expected = abs(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test5() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fcos".to_string());
    let expected = cos(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test6() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, ftan".to_string());
    let expected = tan(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test7() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fexp".to_string());
    let expected = exp(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test8() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fneg".to_string());
    let expected = (-consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test9() {
    let consts = vec![GI::new_c("[0.1, .2]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, flog".to_string());
    let expected = log(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}
#[test]
fn test10() {
    let consts = vec![GI::new_c("[2.0, 3.0]"),
                      GI::new_c("[1.5, 2.5]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                         &"c0, c1, op".to_string());
    let expected = powi(consts[0], consts[1]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}
#[test]
fn test_power() {
    let consts = vec![GI::new_c("[2.0, 3.0]"),
                      GI::new_c("[1.5, 2.5]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                         &"c0, p-1, c1, p2, o+".to_string());
    let expected = (pow(consts[0], -1) + pow(consts[1], 2)).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}
<commit_msg>Simplified instruction parsing<commit_after>#![feature(str_split_at)]
#![feature(convert)]

extern crate gr;
use gr::*;

enum OpType {
    Func(String),
    Const(usize),
    Var(usize),
    UVar(usize),
    Op(String),
    Pow(i32)
}

struct FuncObj {
    user_vars: Vec<GI>,
    constants: Vec<GI>,
    instructions: Vec<OpType>,
    switched: bool,
    func: Box<fn(&Vec<GI>) -> GI>
}

fn dummy(_x: &Vec<GI>) -> GI {
    GI::new_c("1.0")
}

impl FuncObj {
    pub fn call(&self, _x: &Vec<GI>) -> GI {
        if self.switched {
            func(_x)
        }
        else {
            self.interpreted(_x)
        }
    }

    fn interpreted(&self, _x: &Vec<GI>) -> GI {
        let mut stack: Vec<GI> = Vec::new();
        for inst in &self.instructions {
            match inst {
                &OpType::Func(ref s) => {
                    let op = stack.pop().unwrap();
                    let result = match s.as_str() {
                        "abs" => abs(op),
                        "sin" => sin(op),
                        "cos" => cos(op),
                        "tan" => tan(op),
                        "exp" => exp(op),
                        "log" => log(op),
                        "neg" => -op,
                        _     => unreachable!()
                    };
                    stack.push(result);
                },
                &OpType::Const(i) => {
                    stack.push(self.constants[i]);
                },
                &OpType::Var(i) => {
                    stack.push(_x[i]);
                },
                &OpType::UVar(i) => {
                    stack.push(self.user_vars[i]);
                },
                &OpType::Op(ref s) => {
                    let right = stack.pop().unwrap();
                    let left = stack.pop().unwrap();
                    let result = match s.as_str() {
                        "+" => left + right,
                        "-" => left - right,
                        "*" => left * right,
                        "/" => left / right,
                        "p" => powi(left, right),
                        _   => unreachable!()
                    };
                    stack.push(result);
                },
                &OpType::Pow(exp) => {
                    let arg = stack.pop().unwrap();
                    stack.push(gr::pow(arg, exp));
                }
            }
        }
        stack[0]
    }

    fn new(consts: &Vec<GI>, instructions: &String) -> FuncObj {
        let mut insts = vec![];

        for inst in instructions.split(',') {
            let dummy = inst.trim().to_string();
            let (first, rest) = dummy.split_at(1);
            insts.push(match first {
                "c" => OpType::Const(rest.to_string().parse::<usize>().unwrap()),
                "i" => OpType::Var(rest.to_string().parse::<usize>().unwrap()),
                "v" => OpType::UVar(rest.to_string().parse::<usize>().unwrap()),
                "o" => OpType::Op(rest.to_string()),
                "f" => OpType::Func(rest.to_string()),
                "p" => OpType::Pow(rest.to_string().parse::<i32>().unwrap()),
                _   => panic!()
            });
        }

        FuncObj{user_vars: vec![],
                constants: consts.clone(),
                instructions: insts,
                switched: false,
                func: Box::new(dummy)}
    }
}

#[test]
fn test1() {
    let constants = vec![GI::new_c("1"), GI::new_c("2"), GI::new_c("3")];
    let f = FuncObj::new(&constants,
                         &"c0,c1,o-,c2,o+".to_string());
    let expected = ((GI::new_c("1") - GI::new_c("2")) + GI::new_c("3")).to_string();
    assert!(f.call(&vec![]).to_string() == expected);
}

#[test]
fn test2() {
    let consts = vec![GI::new_c("1"), GI::new_c("2"), GI::new_c("3")];
    let f = FuncObj::new(&consts,
                         &"c0,fsin,c1,o*,fcos,c2,o/".to_string());
    let expected = cos(sin(consts[0]) * consts[1])/consts[2];
    assert!(f.call(&vec![]).to_string() == expected.to_string());
}

#[test]
fn sum_inputs() {
    let consts = vec![];
    let v = vec![GI::new_d(1.0, 1.0), GI::new_d(1.0, 2.0), GI::new_d(1.0, 3.0),
                 GI::new_d(1.0, 4.0), GI::new_d(1.0, 5.0), GI::new_d(1.0, 6.0)];
    let f = FuncObj::new(&consts,
                         &"i0,i1, o+, i2, o+, i3, o+, i4, o+, i5, o+".to_string());
    let expected = (v[0] + v[1] + v[2] + v[3] + v[4] + v[5]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test3() {
    let consts = vec![GI::new_c("0.1")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fsin".to_string());
    let expected = sin(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test4() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fabs".to_string());
    let expected = abs(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test5() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fcos".to_string());
    let expected = cos(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test6() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, ftan".to_string());
    let expected = tan(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test7() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fexp".to_string());
    let expected = exp(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test8() {
    let consts = vec![GI::new_c("[-3, 4]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, fneg".to_string());
    let expected = (-consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}

#[test]
fn test9() {
    let consts = vec![GI::new_c("[0.1, .2]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                &"c0, flog".to_string());
    let expected = log(consts[0]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}
#[test]
fn test10() {
    let consts = vec![GI::new_c("[2.0, 3.0]"),
                      GI::new_c("[1.5, 2.5]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                         &"c0, c1, op".to_string());
    let expected = powi(consts[0], consts[1]).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}
#[test]
fn test_power() {
    let consts = vec![GI::new_c("[2.0, 3.0]"),
                      GI::new_c("[1.5, 2.5]")];
    let v = vec![];
    let f = FuncObj::new(&consts,
                         &"c0, p-1, c1, p2, o+".to_string());
    let expected = (pow(consts[0], -1) + pow(consts[1], 2)).to_string();
    let real = f.call(&v).to_string();
    assert!(real == expected, "real = {}, expected = {}", real, expected);
}
<|endoftext|>


<commit_before>//! Create window.

// External crates.
use collections::Deque;
use collections::ringbuf::RingBuf;
use glfw;
use glfw::Context;
use gl;
use piston::event;
use piston::keyboard;
use piston::mouse;
use piston::GameWindow;
use piston::GameWindowSettings;

/// Contains stuff for game window.
pub struct GameWindowGLFW {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: GameWindowSettings,
    event_queue: RingBuf<event::Event>,
}

impl GameWindowGLFW {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GameWindowGLFW {
        win.set_key_polling(true);
        win.set_mouse_button_polling(true);
        win.set_cursor_pos_polling(true);
        win.set_scroll_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        GameWindowGLFW {
            window: win,
            events: events,
            glfw: glfw,
            settings: GameWindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(settings: GameWindowSettings) -> GameWindowGLFW {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(3, 3));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_key_polling(true);
        window.set_mouse_button_polling(true);
        window.set_cursor_pos_polling(true);
        window.set_scroll_polling(true);
        // or polling all event
        //window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| glfw.get_proc_address(s));

        GameWindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                    if self.settings.exit_on_esc => {
                        self.window.set_should_close(true);
                    },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push_back(
                        event::KeyPressed(glfw_map_key(key)));
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push_back(
                        event::KeyReleased(glfw_map_key(key)));
                },
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push_back(
                        event::MouseButtonPressed(glfw_map_mouse(button)));
                },
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push_back(
                        event::MouseButtonReleased(glfw_map_mouse(button)));
                },
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push_back(
                        event::MouseMoved(x, y, None));
                },
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push_back(
                        event::MouseScrolled(x, y));
                },
                _ => {},
            }
        }
    }
}

impl GameWindow for GameWindowGLFW {
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        if enabled {
            self.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            self.window.set_cursor_mode(glfw::CursorNormal)
        }
    }

    fn poll_event(&mut self) -> event::Event {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front().unwrap()
        } else {
            event::NoEvent
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}

<commit_msg>Remove use of deprecated push_back<commit_after>//! Create window.

// External crates.
use collections::Deque;
use collections::ringbuf::RingBuf;
use glfw;
use glfw::Context;
use gl;
use piston::event;
use piston::keyboard;
use piston::mouse;
use piston::GameWindow;
use piston::GameWindowSettings;

/// Contains stuff for game window.
pub struct GameWindowGLFW {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: GameWindowSettings,
    event_queue: RingBuf<event::Event>,
}

impl GameWindowGLFW {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GameWindowGLFW {
        win.set_key_polling(true);
        win.set_mouse_button_polling(true);
        win.set_cursor_pos_polling(true);
        win.set_scroll_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        GameWindowGLFW {
            window: win,
            events: events,
            glfw: glfw,
            settings: GameWindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(settings: GameWindowSettings) -> GameWindowGLFW {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(3, 3));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_key_polling(true);
        window.set_mouse_button_polling(true);
        window.set_cursor_pos_polling(true);
        window.set_scroll_polling(true);
        // or polling all event
        //window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| glfw.get_proc_address(s));

        GameWindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                    if self.settings.exit_on_esc => {
                        self.window.set_should_close(true);
                    },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push(
                        event::KeyPressed(glfw_map_key(key)));
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push(
                        event::KeyReleased(glfw_map_key(key)));
                },
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push(
                        event::MouseButtonPressed(glfw_map_mouse(button)));
                },
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push(
                        event::MouseButtonReleased(glfw_map_mouse(button)));
                },
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push(
                        event::MouseMoved(x, y, None));
                },
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push(
                        event::MouseScrolled(x, y));
                },
                _ => {},
            }
        }
    }
}

impl GameWindow for GameWindowGLFW {
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        if enabled {
            self.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            self.window.set_cursor_mode(glfw::CursorNormal)
        }
    }

    fn poll_event(&mut self) -> event::Event {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front().unwrap()
        } else {
            event::NoEvent
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}

<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::mem::size_of;

use super::*;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) enum Data {
    Index(Vec<(IVec, PageId)>),
    Leaf(Vec<(IVec, IVec)>),
}

impl Data {
    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        let self_sz = size_of::<Self>() as u64;

        let inner_sz = match self {
            Data::Index(ref v) => {
                let mut sz = 0_u64;
                for (k, _p) in v.iter() {
                    sz = sz
                        .saturating_add(k.len() as u64)
                        .saturating_add(size_of::<IVec>() as u64)
                        .saturating_add(size_of::<PageId>() as u64);
                }
                sz.saturating_add(
                    size_of::<Vec<(IVec, PageId)>>() as u64
                )
            }
            Data::Leaf(ref v) => {
                let mut sz = 0_u64;
                for (k, value) in v.iter() {
                    sz = sz
                        .saturating_add(k.len() as u64)
                        .saturating_add(size_of::<IVec>() as u64)
                        .saturating_add(value.len() as u64)
                        .saturating_add(size_of::<IVec>() as u64);
                }
                sz.saturating_add(
                    size_of::<Vec<(IVec, IVec)>>() as u64
                )
            }
        };

        self_sz.saturating_add(inner_sz)
    }

    pub(crate) fn len(&self) -> usize {
        match *self {
            Data::Index(ref ptrs) => ptrs.len(),
            Data::Leaf(ref items) => items.len(),
        }
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub(crate) fn split(&self, lhs_prefix: &[u8]) -> (IVec, Data) {
        fn split_inner<T>(
            xs: &[(IVec, T)],
            lhs_prefix: &[u8],
        ) -> (IVec, Vec<(IVec, T)>)
        where
            T: Clone + Debug + Ord,
        {
            let mut decoded_xs: Vec<_> = xs
                .iter()
                .map(|&(ref k, ref v)| {
                    let decoded_k = prefix_decode(lhs_prefix, &*k);
                    (decoded_k, v.clone())
                })
                .collect();
            decoded_xs.sort();

            let (_lhs, rhs) =
                decoded_xs.split_at(decoded_xs.len() / 2 + 1);
            let split = rhs
                .first()
                .expect("rhs should contain at least one element")
                .0
                .clone();
            let rhs_data: Vec<_> = rhs
                .iter()
                .map(|&(ref k, ref v)| {
                    let new_k = prefix_encode(&*split, k);
                    (new_k, v.clone())
                })
                .collect();

            (split.into(), rhs_data)
        }

        match *self {
            Data::Index(ref ptrs) => {
                let (split, rhs) = split_inner(ptrs, lhs_prefix);
                (split, Data::Index(rhs))
            }
            Data::Leaf(ref items) => {
                let (split, rhs) = split_inner(items, lhs_prefix);
                (split, Data::Leaf(rhs))
            }
        }
    }

    pub(crate) fn drop_gte(&mut self, bound: &[u8], prefix: &[u8]) {
        match *self {
            Data::Index(ref mut ptrs) => {
                ptrs.retain(|&(ref k, _)| {
                    prefix_cmp_encoded(k, bound, prefix)
                        == std::cmp::Ordering::Less
                })
            }
            Data::Leaf(ref mut items) => {
                items.retain(|&(ref k, _)| {
                    prefix_cmp_encoded(k, bound, prefix)
                        == std::cmp::Ordering::Less
                })
            }
        }
    }

    pub(crate) fn leaf_ref(&self) -> Option<&Vec<(IVec, IVec)>> {
        match *self {
            Data::Index(_) => None,
            Data::Leaf(ref items) => Some(items),
        }
    }
}
<commit_msg>Rewrite the Data split method to be more efficient<commit_after>use std::mem::size_of;

use super::*;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) enum Data {
    Index(Vec<(IVec, PageId)>),
    Leaf(Vec<(IVec, IVec)>),
}

impl Data {
    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        let self_sz = size_of::<Self>() as u64;

        let inner_sz = match self {
            Data::Index(ref v) => {
                let mut sz = 0_u64;
                for (k, _p) in v.iter() {
                    sz = sz
                        .saturating_add(k.len() as u64)
                        .saturating_add(size_of::<IVec>() as u64)
                        .saturating_add(size_of::<PageId>() as u64);
                }
                sz.saturating_add(
                    size_of::<Vec<(IVec, PageId)>>() as u64
                )
            }
            Data::Leaf(ref v) => {
                let mut sz = 0_u64;
                for (k, value) in v.iter() {
                    sz = sz
                        .saturating_add(k.len() as u64)
                        .saturating_add(size_of::<IVec>() as u64)
                        .saturating_add(value.len() as u64)
                        .saturating_add(size_of::<IVec>() as u64);
                }
                sz.saturating_add(
                    size_of::<Vec<(IVec, IVec)>>() as u64
                )
            }
        };

        self_sz.saturating_add(inner_sz)
    }

    pub(crate) fn len(&self) -> usize {
        match *self {
            Data::Index(ref ptrs) => ptrs.len(),
            Data::Leaf(ref items) => items.len(),
        }
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub(crate) fn split(&self, lhs_prefix: &[u8]) -> (IVec, Data) {
        fn split_inner<T>(
            xs: &[(IVec, T)],
            lhs_prefix: &[u8],
        ) -> (IVec, Vec<(IVec, T)>)
        where
            T: Clone + Ord,
        {
            let (_lhs, rhs) = xs.split_at(xs.len() / 2 + 1);
            let split = prefix_decode(lhs_prefix, &rhs[0].0);

            let mut rhs_data = Vec::with_capacity(rhs.len());
            for (k, v) in rhs {
                let k = prefix_decode(lhs_prefix, k);
                let k = prefix_encode(&split, &k);
                rhs_data.push((k, v.clone()));
            }

            (IVec::from(split), rhs_data)
        }

        match *self {
            Data::Index(ref ptrs) => {
                let (split, rhs) = split_inner(ptrs, lhs_prefix);
                (split, Data::Index(rhs))
            }
            Data::Leaf(ref items) => {
                let (split, rhs) = split_inner(items, lhs_prefix);
                (split, Data::Leaf(rhs))
            }
        }
    }

    pub(crate) fn drop_gte(&mut self, bound: &[u8], prefix: &[u8]) {
        match *self {
            Data::Index(ref mut ptrs) => {
                ptrs.retain(|&(ref k, _)| {
                    prefix_cmp_encoded(k, bound, prefix)
                        == std::cmp::Ordering::Less
                })
            }
            Data::Leaf(ref mut items) => {
                items.retain(|&(ref k, _)| {
                    prefix_cmp_encoded(k, bound, prefix)
                        == std::cmp::Ordering::Less
                })
            }
        }
    }

    pub(crate) fn leaf_ref(&self) -> Option<&Vec<(IVec, IVec)>> {
        match *self {
            Data::Index(_) => None,
            Data::Leaf(ref items) => Some(items),
        }
    }
}
<|endoftext|>