<commit_before>extern crate rand;

//use std::process::Command;
use chip8::Chip8;

pub struct Interpreter;

impl Interpreter {
	pub fn execute_next_instruction(chip8: &mut Chip8) {
		// debug
		/*println!("PC= {:x}", chip8.register_pc);
		println!("I= {:x}", chip8.register_i);
		println!("DT= {:x}", chip8.register_dt);
		println!("ST= {:x}", chip8.register_st);
		println!("SP= {:x}", chip8.register_sp);

		for i in 0..16 as usize {
			println!("V{}= {:x}", i, chip8.register_v[i]);
		}

		let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();*/

		// fetch
		let high_byte = chip8.memory[chip8.register_pc as usize];
		let low_byte = chip8.memory[chip8.register_pc as usize + 1];
		let opcode = (high_byte >> 4, high_byte & 0x0F, low_byte >> 4, low_byte & 0x0F);
		chip8.register_pc += 2;

		// decode & execute
		let nnn = ((high_byte as u16 & 0x0F) << 8) | low_byte as u16;
		let x = high_byte as usize & 0x0F;
		let y = low_byte as usize >> 4;

		match opcode {
			(0x0, 0x0, 0xE, 0x0) => chip8.display.clear(),
			(0x0, 0x0, 0xE, 0xE) => {
				chip8.register_pc = chip8.stack[chip8.register_sp as usize];
				chip8.register_sp -= 1;
			},
			(0x1, ..) => chip8.register_pc = nnn,
			(0x2, ..) => {
				chip8.register_sp += 1;
				chip8.stack[chip8.register_sp as usize] = chip8.register_pc;
				chip8.register_pc = nnn;
			},
			(0x3, ..) => {
				if chip8.register_v[x] == low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x4, ..) => {
				if chip8.register_v[x] != low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x5, _, _, 0x0) => {
				if chip8.register_v[x] == chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0x6, ..) => chip8.register_v[x] = low_byte,
			(0x7, ..) => chip8.register_v[x] = chip8.register_v[x].wrapping_add(low_byte),
			(0x8, _, _, 0x0) => chip8.register_v[x] = chip8.register_v[y],
			(0x8, _, _, 0x1) => chip8.register_v[x] |= chip8.register_v[y],
			(0x8, _, _, 0x2) => chip8.register_v[x] &= chip8.register_v[y],
			(0x8, _, _, 0x3) => chip8.register_v[x] ^= chip8.register_v[y],
			(0x8, _, _, 0x4) => {
				let result = chip8.register_v[x] as u16 + chip8.register_v[y] as u16;
				chip8.register_v[x] = result as u8;
				chip8.register_v[0xF] = (result > 0xFF) as u8;
			},
			(0x8, _, _, 0x5) => {
				chip8.register_v[0xF] = (chip8.register_v[x] > chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[x].wrapping_sub(chip8.register_v[y]);
			},
			(0x8, _, _, 0x6) => {
				chip8.register_v[0xF] = chip8.register_v[x] & 1;
				chip8.register_v[x] >>= 1;
			},
			(0x8, _, _, 0x7) => {
				chip8.register_v[0xF] = (chip8.register_v[x] < chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[y].wrapping_sub(chip8.register_v[x]);
			},
			(0x8, _, _, 0xE) => {
				chip8.register_v[0xF] = chip8.register_v[x] >> 7;
				chip8.register_v[x] <<= 1;
			},
			(0x9, _, _, 0x0) => {
				if chip8.register_v[x] != chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0xA, ..) => chip8.register_i = nnn,
			(0xB, ..) => chip8.register_pc = nnn + chip8.register_v[0] as u16,
			(0xC, ..) => chip8.register_v[x] = rand::random::<u8>() & low_byte,
			(0xD, _, _, n) => {
				let sprite = &chip8.memory[chip8.register_i as usize .. chip8.register_i as usize + n as usize];
				chip8.register_v[0xF] = chip8.display.draw_sprite(chip8.register_v[x], chip8.register_v[y], sprite) as u8;
			},
			(0xE, _, 0x9, 0xE) => {
				if chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xE, _, 0xA, 0x1) => {
				if !chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xF, _, 0x0, 0x7) => chip8.register_v[x] = chip8.register_dt,
			(0xF, _, 0x0, 0xA) => chip8.register_v[x] = chip8.keyboard.wait_key_press(),
			(0xF, _, 0x1, 0x5) => chip8.register_dt = chip8.register_v[x],
			(0xF, _, 0x1, 0x8) => chip8.register_st = chip8.register_v[x],
			(0xF, _, 0x1, 0xE) => chip8.register_i += chip8.register_v[x] as u16,
			(0xF, _, 0x2, 0x9) => chip8.register_i = chip8.register_v[x] as u16 * 5,
			(0xF, _, 0x3, 0x3) => {
				chip8.memory[chip8.register_i as usize] = chip8.register_v[x] / 100;
				chip8.memory[chip8.register_i as usize + 1] = (chip8.register_v[x] % 100) / 10;
				chip8.memory[chip8.register_i as usize + 2] = chip8.register_v[x] % 10;
			},
			(0xF, _, 0x5, 0x5) => {
				for i in 0..(x + 1) {
					chip8.memory[chip8.register_i as usize + i] = chip8.register_v[i];
				}
			},
			(0xF, _, 0x6, 0x5) => {
				for i in 0..(x + 1) {
					chip8.register_v[i] = chip8.memory[chip8.register_i as usize + i];
				}
			},
			_ => panic!("unknown opcode")
		}
	}
}
<commit_msg>Interpreter: fix 8XY5 and 8XY7<commit_after>extern crate rand;

//use std::process::Command;
use chip8::Chip8;

pub struct Interpreter;

impl Interpreter {
	pub fn execute_next_instruction(chip8: &mut Chip8) {
		// debug
		/*println!("PC= {:x}", chip8.register_pc);
		println!("I= {:x}", chip8.register_i);
		println!("DT= {:x}", chip8.register_dt);
		println!("ST= {:x}", chip8.register_st);
		println!("SP= {:x}", chip8.register_sp);

		for i in 0..16 as usize {
			println!("V{}= {:x}", i, chip8.register_v[i]);
		}

		let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();*/

		// fetch
		let high_byte = chip8.memory[chip8.register_pc as usize];
		let low_byte = chip8.memory[chip8.register_pc as usize + 1];
		let opcode = (high_byte >> 4, high_byte & 0x0F, low_byte >> 4, low_byte & 0x0F);
		chip8.register_pc += 2;

		// decode & execute
		let nnn = ((high_byte as u16 & 0x0F) << 8) | low_byte as u16;
		let x = high_byte as usize & 0x0F;
		let y = low_byte as usize >> 4;

		match opcode {
			(0x0, 0x0, 0xE, 0x0) => chip8.display.clear(),
			(0x0, 0x0, 0xE, 0xE) => {
				chip8.register_pc = chip8.stack[chip8.register_sp as usize];
				chip8.register_sp -= 1;
			},
			(0x1, ..) => chip8.register_pc = nnn,
			(0x2, ..) => {
				chip8.register_sp += 1;
				chip8.stack[chip8.register_sp as usize] = chip8.register_pc;
				chip8.register_pc = nnn;
			},
			(0x3, ..) => {
				if chip8.register_v[x] == low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x4, ..) => {
				if chip8.register_v[x] != low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x5, _, _, 0x0) => {
				if chip8.register_v[x] == chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0x6, ..) => chip8.register_v[x] = low_byte,
			(0x7, ..) => chip8.register_v[x] = chip8.register_v[x].wrapping_add(low_byte),
			(0x8, _, _, 0x0) => chip8.register_v[x] = chip8.register_v[y],
			(0x8, _, _, 0x1) => chip8.register_v[x] |= chip8.register_v[y],
			(0x8, _, _, 0x2) => chip8.register_v[x] &= chip8.register_v[y],
			(0x8, _, _, 0x3) => chip8.register_v[x] ^= chip8.register_v[y],
			(0x8, _, _, 0x4) => {
				let result = chip8.register_v[x] as u16 + chip8.register_v[y] as u16;
				chip8.register_v[x] = result as u8;
				chip8.register_v[0xF] = (result > 0xFF) as u8;
			},
			(0x8, _, _, 0x5) => {
				chip8.register_v[0xF] = (chip8.register_v[x] >= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[x].wrapping_sub(chip8.register_v[y]);
			},
			(0x8, _, _, 0x6) => {
				chip8.register_v[0xF] = chip8.register_v[x] & 1;
				chip8.register_v[x] >>= 1;
			},
			(0x8, _, _, 0x7) => {
				chip8.register_v[0xF] = (chip8.register_v[x] <= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[y].wrapping_sub(chip8.register_v[x]);
			},
			(0x8, _, _, 0xE) => {
				chip8.register_v[0xF] = chip8.register_v[x] >> 7;
				chip8.register_v[x] <<= 1;
			},
			(0x9, _, _, 0x0) => {
				if chip8.register_v[x] != chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0xA, ..) => chip8.register_i = nnn,
			(0xB, ..) => chip8.register_pc = nnn + chip8.register_v[0] as u16,
			(0xC, ..) => chip8.register_v[x] = rand::random::<u8>() & low_byte,
			(0xD, _, _, n) => {
				let sprite = &chip8.memory[chip8.register_i as usize .. chip8.register_i as usize + n as usize];
				chip8.register_v[0xF] = chip8.display.draw_sprite(chip8.register_v[x], chip8.register_v[y], sprite) as u8;
			},
			(0xE, _, 0x9, 0xE) => {
				if chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xE, _, 0xA, 0x1) => {
				if !chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xF, _, 0x0, 0x7) => chip8.register_v[x] = chip8.register_dt,
			(0xF, _, 0x0, 0xA) => chip8.register_v[x] = chip8.keyboard.wait_key_press(),
			(0xF, _, 0x1, 0x5) => chip8.register_dt = chip8.register_v[x],
			(0xF, _, 0x1, 0x8) => chip8.register_st = chip8.register_v[x],
			(0xF, _, 0x1, 0xE) => chip8.register_i += chip8.register_v[x] as u16,
			(0xF, _, 0x2, 0x9) => chip8.register_i = chip8.register_v[x] as u16 * 5,
			(0xF, _, 0x3, 0x3) => {
				chip8.memory[chip8.register_i as usize] = chip8.register_v[x] / 100;
				chip8.memory[chip8.register_i as usize + 1] = (chip8.register_v[x] % 100) / 10;
				chip8.memory[chip8.register_i as usize + 2] = chip8.register_v[x] % 10;
			},
			(0xF, _, 0x5, 0x5) => {
				for i in 0..(x + 1) {
					chip8.memory[chip8.register_i as usize + i] = chip8.register_v[i];
				}
			},
			(0xF, _, 0x6, 0x5) => {
				for i in 0..(x + 1) {
					chip8.register_v[i] = chip8.memory[chip8.register_i as usize + i];
				}
			},
			_ => panic!("unknown opcode")
		}
	}
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::ffi;
use std::fmt;
use std::io;
use std::num;
use std::process::{Output, ExitStatus};
use std::str;
use std::string;

use curl;
use git2;
use rustc_serialize::json;
use semver;
use term;
use toml;
use url;

pub type CargoResult<T> = Result<T, Box<CargoError>>;

// =============================================================================
// CargoError trait

pub trait CargoError: Error + Send + 'static {
    fn is_human(&self) -> bool { false }
    fn cargo_cause(&self) -> Option<&CargoError>{ None }
}

impl Error for Box<CargoError> {
    fn description(&self) -> &str { (**self).description() }
    fn cause(&self) -> Option<&Error> { (**self).cause() }
}

impl CargoError for Box<CargoError> {
    fn is_human(&self) -> bool { (**self).is_human() }
    fn cargo_cause(&self) -> Option<&CargoError> { (**self).cargo_cause() }
}

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> CargoResult<T>
                         where E: CargoError, F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<CargoError>,
}

impl<'a, T, F> ChainError<T> for F where F: FnOnce() -> CargoResult<T> {
    fn chain_error<E, C>(self, callback: C) -> CargoResult<T>
                         where E: CargoError, C: FnOnce() -> E {
        self().chain_error(callback)
    }
}

impl<T, E: CargoError + 'static> ChainError<T> for Result<T, E> {
    fn chain_error<E2: 'static, C>(self, callback: C) -> CargoResult<T>
                         where E2: CargoError, C: FnOnce() -> E2 {
        self.map_err(move |err| {
            Box::new(ChainedError {
                error: callback(),
                cause: Box::new(err),
            }) as Box<CargoError>
        })
    }
}

impl<T> ChainError<T> for Box<CargoError> {
    fn chain_error<E2, C>(self, callback: C) -> CargoResult<T>
                         where E2: CargoError, C: FnOnce() -> E2 {
        Err(Box::new(ChainedError {
            error: callback(),
            cause: self,
        }))
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E: 'static, C>(self, callback: C) -> CargoResult<T>
                         where E: CargoError, C: FnOnce() -> E {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: Error> Error for ChainedError<E> {
    fn description(&self) -> &str { self.error.description() }
}

impl<E: fmt::Display> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.error, f)
    }
}

impl<E: CargoError> CargoError for ChainedError<E> {
    fn is_human(&self) -> bool { self.error.is_human() }
    fn cargo_cause(&self) -> Option<&CargoError> { Some(&*self.cause) }
}

// =============================================================================
// Process errors

pub struct ProcessError {
    pub desc: String,
    pub exit: Option<ExitStatus>,
    pub output: Option<Output>,
    cause: Option<Box<Error + Send>>,
}

impl Error for ProcessError {
    fn description(&self) -> &str { &self.desc }
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e as &Error)
    }
}

impl fmt::Display for ProcessError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.desc, f)
    }
}
impl fmt::Debug for ProcessError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

// =============================================================================
// Cargo test errors.

/// Error when testcases fail
pub struct CargoTestError {
    pub desc: String,
    pub exit: Option<ExitStatus>,
    pub causes: Vec<ProcessError>,
}

impl CargoTestError {
    pub fn new(errors: Vec<ProcessError>) -> Self {
        if errors.is_empty() {
            panic!("Cannot create CargoTestError from empty Vec")
        }
        let desc = errors.iter().map(|error| error.desc.clone())
                                .collect::<Vec<String>>()
                                .join("\n");
        CargoTestError {
            desc: desc,
            exit: errors[0].exit,
            causes: errors,
        }
    }
}

impl fmt::Display for CargoTestError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.desc, f)
    }
}

impl fmt::Debug for CargoTestError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for CargoTestError {
    fn description(&self) -> &str { &self.desc }
    fn cause(&self) -> Option<&Error> {
        self.causes.get(0).map(|s| s as &Error)
    }
}

// =============================================================================
// Concrete errors

struct ConcreteCargoError {
    description: String,
    detail: Option<String>,
    cause: Option<Box<Error+Send>>,
    is_human: bool,
}

impl fmt::Display for ConcreteCargoError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.description));
        if let Some(ref s) = self.detail {
            try!(write!(f, " ({})", s));
        }
        Ok(())
    }
}
impl fmt::Debug for ConcreteCargoError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for ConcreteCargoError {
    fn description(&self) -> &str { &self.description }
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|c| {
            let e: &Error = &**c; e
        })
    }
}

impl CargoError for ConcreteCargoError {
    fn is_human(&self) -> bool {
        self.is_human
    }
}

// =============================================================================
// Human errors

#[derive(Debug)]
pub struct Human<E>(pub E);

impl<E: Error> Error for Human<E> {
    fn description(&self) -> &str { self.0.description() }
    fn cause(&self) -> Option<&Error> { self.0.cause() }
}

impl<E: fmt::Display> fmt::Display for Human<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl<E: CargoError> CargoError for Human<E> {
    fn is_human(&self) -> bool { true }
    fn cargo_cause(&self) -> Option<&CargoError> { self.0.cargo_cause() }
}

// =============================================================================
// CLI errors

pub type CliResult<T> = Result<T, CliError>;

#[derive(Debug)]
pub struct CliError {
    pub error: Option<Box<CargoError>>,
    pub unknown: bool,
    pub exit_code: i32
}

impl Error for CliError {
    fn description(&self) -> &str {
        self.error.as_ref().map(|e| e.description())
            .unwrap_or("unknown cli error")
    }

    fn cause(&self) -> Option<&Error> {
        self.error.as_ref().and_then(|e| e.cause())
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref error) = self.error {
            error.fmt(f)
        } else {
            self.description().fmt(f)
        }
    }
}

impl CliError {
    pub fn new(error: Box<CargoError>, code: i32) -> CliError {
        let human = error.is_human();
        CliError { error: Some(error), exit_code: code, unknown: !human }
    }

    pub fn code(code: i32) -> CliError {
        CliError { error: None, exit_code: code, unknown: false }
    }
}

impl From<Box<CargoError>> for CliError {
    fn from(err: Box<CargoError>) -> CliError {
        CliError::new(err, 101)
    }
}

// =============================================================================
// NetworkError trait

pub trait NetworkError: CargoError {
    fn maybe_spurious(&self) -> bool;
}

impl NetworkError for git2::Error {
    fn maybe_spurious(&self) -> bool {
        match self.class() {
            git2::ErrorClass::Net |
            git2::ErrorClass::Os => true,
            _ => false
        }
    }
}
impl NetworkError for curl::Error {
    fn maybe_spurious(&self) -> bool {
        self.is_couldnt_connect() ||
            self.is_couldnt_resolve_proxy() ||
            self.is_couldnt_resolve_host() ||
            self.is_operation_timedout() ||
            self.is_recv_error()
    }
}

// =============================================================================
// various impls

macro_rules! from_error {
    ($($p:ty,)*) => (
        $(impl From<$p> for Box<CargoError> {
            fn from(t: $p) -> Box<CargoError> { Box::new(t) }
        })*
    )
}

from_error! {
    semver::ReqParseError,
    io::Error,
    ProcessError,
    git2::Error,
    json::DecoderError,
    json::EncoderError,
    curl::Error,
    CliError,
    toml::Error,
    url::ParseError,
    toml::DecodeError,
    ffi::NulError,
    term::Error,
    num::ParseIntError,
    str::ParseBoolError,
}

impl From<string::ParseError> for Box<CargoError> {
    fn from(t: string::ParseError) -> Box<CargoError> {
        match t {}
    }
}

impl<E: CargoError> From<Human<E>> for Box<CargoError> {
    fn from(t: Human<E>) -> Box<CargoError> { Box::new(t) }
}

impl CargoError for semver::ReqParseError {}
impl CargoError for io::Error {}
impl CargoError for git2::Error {}
impl CargoError for json::DecoderError {}
impl CargoError for json::EncoderError {}
impl CargoError for curl::Error {}
impl CargoError for ProcessError {}
impl CargoError for CargoTestError {}
impl CargoError for CliError {}
impl CargoError for toml::Error {}
impl CargoError for toml::DecodeError {}
impl CargoError for url::ParseError {}
impl CargoError for ffi::NulError {}
impl CargoError for term::Error {}
impl CargoError for num::ParseIntError {}
impl CargoError for str::ParseBoolError {}

// =============================================================================
// Construction helpers

pub fn process_error(msg: &str,
                     cause: Option<Box<Error + Send>>,
                     status: Option<&ExitStatus>,
                     output: Option<&Output>) -> ProcessError
{
    let exit = match status {
        Some(s) => status_to_string(s),
        None => "never executed".to_string(),
    };
    let mut desc = format!("{} ({})", &msg, exit);

    if let Some(out) = output {
        match str::from_utf8(&out.stdout) {
            Ok(s) if s.trim().len() > 0 => {
                desc.push_str("\n--- stdout\n");
                desc.push_str(s);
            }
            Ok(..) | Err(..) => {}
        }
        match str::from_utf8(&out.stderr) {
            Ok(s) if s.trim().len() > 0 => {
                desc.push_str("\n--- stderr\n");
                desc.push_str(s);
            }
            Ok(..) | Err(..) => {}
        }
    }

    return ProcessError {
        desc: desc,
        exit: status.cloned(),
        output: output.cloned(),
        cause: cause,
    };

    #[cfg(unix)]
    fn status_to_string(status: &ExitStatus) -> String {
        use std::os::unix::process::*;
        use libc;

        if let Some(signal) = status.signal() {
            let name = match signal as libc::c_int {
                libc::SIGABRT => ", SIGABRT: process abort signal",
                libc::SIGALRM => ", SIGALRM: alarm clock",
                libc::SIGFPE => ", SIGFPE: erroneous arithmetic operation",
                libc::SIGHUP => ", SIGHUP: hangup",
                libc::SIGILL => ", SIGILL: illegal instruction",
                libc::SIGINT => ", SIGINT: terminal interrupt signal",
                libc::SIGKILL => ", SIGKILL: kill",
                libc::SIGPIPE => ", SIGPIPE: write on a pipe with no one to read",
                libc::SIGQUIT => ", SIGQUIT: terminal quite signal",
                libc::SIGSEGV => ", SIGSEGV: invalid memory reference",
                libc::SIGTERM => ", SIGTERM: termination signal",
                libc::SIGBUS => ", SIGBUS: access to undefined memory",
                libc::SIGSYS => ", SIGSYS: bad system call",
                libc::SIGTRAP => ", SIGTRAP: trace/breakpoint trap",
                _ => "",
            };
            format!("signal: {}{}", signal, name)
        } else {
            status.to_string()
        }
    }

    #[cfg(windows)]
    fn status_to_string(status: &ExitStatus) -> String {
        status.to_string()
    }
}

pub fn internal_error(error: &str, detail: &str) -> Box<CargoError> {
    Box::new(ConcreteCargoError {
        description: error.to_string(),
        detail: Some(detail.to_string()),
        cause: None,
        is_human: false
    })
}

pub fn internal<S: fmt::Display>(error: S) -> Box<CargoError> {
    _internal(&error)
}

fn _internal(error: &fmt::Display) -> Box<CargoError> {
    Box::new(ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: None,
        is_human: false
    })
}

pub fn human<S: fmt::Display>(error: S) -> Box<CargoError> {
    _human(&error)
}

fn _human(error: &fmt::Display) -> Box<CargoError> {
    Box::new(ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: None,
        is_human: true
    })
}

pub fn caused_human<S, E>(error: S, cause: E) -> Box<CargoError>
    where S: fmt::Display,
          E: Error + Send + 'static
{
    Box::new(ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: Some(Box::new(cause)),
        is_human: true
    })
}
<commit_msg>Store CargoError inside the ProcessError<commit_after>use std::error::Error;
use std::ffi;
use std::fmt;
use std::io;
use std::num;
use std::process::{Output, ExitStatus};
use std::str;
use std::string;

use curl;
use git2;
use rustc_serialize::json;
use semver;
use term;
use toml;
use url;

pub type CargoResult<T> = Result<T, Box<CargoError>>;

// =============================================================================
// CargoError trait

pub trait CargoError: Error + Send + 'static {
    fn is_human(&self) -> bool { false }
    fn cargo_cause(&self) -> Option<&CargoError>{ None }
    fn as_error(&self) -> &Error where Self: Sized { self as &Error }
}

impl Error for Box<CargoError> {
    fn description(&self) -> &str { (**self).description() }
    fn cause(&self) -> Option<&Error> { (**self).cause() }
}

impl CargoError for Box<CargoError> {
    fn is_human(&self) -> bool { (**self).is_human() }
    fn cargo_cause(&self) -> Option<&CargoError> { (**self).cargo_cause() }
}

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> CargoResult<T>
                         where E: CargoError, F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<CargoError>,
}

impl<'a, T, F> ChainError<T> for F where F: FnOnce() -> CargoResult<T> {
    fn chain_error<E, C>(self, callback: C) -> CargoResult<T>
                         where E: CargoError, C: FnOnce() -> E {
        self().chain_error(callback)
    }
}

impl<T, E: CargoError + 'static> ChainError<T> for Result<T, E> {
    fn chain_error<E2: 'static, C>(self, callback: C) -> CargoResult<T>
                         where E2: CargoError, C: FnOnce() -> E2 {
        self.map_err(move |err| {
            Box::new(ChainedError {
                error: callback(),
                cause: Box::new(err),
            }) as Box<CargoError>
        })
    }
}

impl<T> ChainError<T> for Box<CargoError> {
    fn chain_error<E2, C>(self, callback: C) -> CargoResult<T>
                         where E2: CargoError, C: FnOnce() -> E2 {
        Err(Box::new(ChainedError {
            error: callback(),
            cause: self,
        }))
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E: 'static, C>(self, callback: C) -> CargoResult<T>
                         where E: CargoError, C: FnOnce() -> E {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: Error> Error for ChainedError<E> {
    fn description(&self) -> &str { self.error.description() }
}

impl<E: fmt::Display> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.error, f)
    }
}

impl<E: CargoError> CargoError for ChainedError<E> {
    fn is_human(&self) -> bool { self.error.is_human() }
    fn cargo_cause(&self) -> Option<&CargoError> { Some(&*self.cause) }
}

// =============================================================================
// Process errors

pub struct ProcessError {
    pub desc: String,
    pub exit: Option<ExitStatus>,
    pub output: Option<Output>,
    cause: Option<Box<CargoError>>,
}

impl Error for ProcessError {
    fn description(&self) -> &str { &self.desc }
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| e.as_error())
    }
}

impl fmt::Display for ProcessError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.desc, f)
    }
}
impl fmt::Debug for ProcessError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

// =============================================================================
// Cargo test errors.

/// Error when testcases fail
pub struct CargoTestError {
    pub desc: String,
    pub exit: Option<ExitStatus>,
    pub causes: Vec<ProcessError>,
}

impl CargoTestError {
    pub fn new(errors: Vec<ProcessError>) -> Self {
        if errors.is_empty() {
            panic!("Cannot create CargoTestError from empty Vec")
        }
        let desc = errors.iter().map(|error| error.desc.clone())
                                .collect::<Vec<String>>()
                                .join("\n");
        CargoTestError {
            desc: desc,
            exit: errors[0].exit,
            causes: errors,
        }
    }
}

impl fmt::Display for CargoTestError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.desc, f)
    }
}

impl fmt::Debug for CargoTestError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for CargoTestError {
    fn description(&self) -> &str { &self.desc }
    fn cause(&self) -> Option<&Error> {
        self.causes.get(0).map(|s| s as &Error)
    }
}

// =============================================================================
// Concrete errors

struct ConcreteCargoError {
    description: String,
    detail: Option<String>,
    cause: Option<Box<Error+Send>>,
    is_human: bool,
}

impl fmt::Display for ConcreteCargoError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.description));
        if let Some(ref s) = self.detail {
            try!(write!(f, " ({})", s));
        }
        Ok(())
    }
}
impl fmt::Debug for ConcreteCargoError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for ConcreteCargoError {
    fn description(&self) -> &str { &self.description }
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|c| {
            let e: &Error = &**c; e
        })
    }
}

impl CargoError for ConcreteCargoError {
    fn is_human(&self) -> bool {
        self.is_human
    }
}

// =============================================================================
// Human errors

#[derive(Debug)]
pub struct Human<E>(pub E);

impl<E: Error> Error for Human<E> {
    fn description(&self) -> &str { self.0.description() }
    fn cause(&self) -> Option<&Error> { self.0.cause() }
}

impl<E: fmt::Display> fmt::Display for Human<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl<E: CargoError> CargoError for Human<E> {
    fn is_human(&self) -> bool { true }
    fn cargo_cause(&self) -> Option<&CargoError> { self.0.cargo_cause() }
}

// =============================================================================
// CLI errors

pub type CliResult<T> = Result<T, CliError>;

#[derive(Debug)]
pub struct CliError {
    pub error: Option<Box<CargoError>>,
    pub unknown: bool,
    pub exit_code: i32
}

impl Error for CliError {
    fn description(&self) -> &str {
        self.error.as_ref().map(|e| e.description())
            .unwrap_or("unknown cli error")
    }

    fn cause(&self) -> Option<&Error> {
        self.error.as_ref().and_then(|e| e.cause())
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref error) = self.error {
            error.fmt(f)
        } else {
            self.description().fmt(f)
        }
    }
}

impl CliError {
    pub fn new(error: Box<CargoError>, code: i32) -> CliError {
        let human = error.is_human();
        CliError { error: Some(error), exit_code: code, unknown: !human }
    }

    pub fn code(code: i32) -> CliError {
        CliError { error: None, exit_code: code, unknown: false }
    }
}

impl From<Box<CargoError>> for CliError {
    fn from(err: Box<CargoError>) -> CliError {
        CliError::new(err, 101)
    }
}

// =============================================================================
// NetworkError trait

pub trait NetworkError: CargoError {
    fn maybe_spurious(&self) -> bool;
}

impl NetworkError for git2::Error {
    fn maybe_spurious(&self) -> bool {
        match self.class() {
            git2::ErrorClass::Net |
            git2::ErrorClass::Os => true,
            _ => false
        }
    }
}
impl NetworkError for curl::Error {
    fn maybe_spurious(&self) -> bool {
        self.is_couldnt_connect() ||
            self.is_couldnt_resolve_proxy() ||
            self.is_couldnt_resolve_host() ||
            self.is_operation_timedout() ||
            self.is_recv_error()
    }
}

// =============================================================================
// various impls

macro_rules! from_error {
    ($($p:ty,)*) => (
        $(impl From<$p> for Box<CargoError> {
            fn from(t: $p) -> Box<CargoError> { Box::new(t) }
        })*
    )
}

from_error! {
    semver::ReqParseError,
    io::Error,
    ProcessError,
    git2::Error,
    json::DecoderError,
    json::EncoderError,
    curl::Error,
    CliError,
    toml::Error,
    url::ParseError,
    toml::DecodeError,
    ffi::NulError,
    term::Error,
    num::ParseIntError,
    str::ParseBoolError,
}

impl From<string::ParseError> for Box<CargoError> {
    fn from(t: string::ParseError) -> Box<CargoError> {
        match t {}
    }
}

impl<E: CargoError> From<Human<E>> for Box<CargoError> {
    fn from(t: Human<E>) -> Box<CargoError> { Box::new(t) }
}

impl CargoError for semver::ReqParseError {}
impl CargoError for io::Error {}
impl CargoError for git2::Error {}
impl CargoError for json::DecoderError {}
impl CargoError for json::EncoderError {}
impl CargoError for curl::Error {}
impl CargoError for ProcessError {}
impl CargoError for CargoTestError {}
impl CargoError for CliError {}
impl CargoError for toml::Error {}
impl CargoError for toml::DecodeError {}
impl CargoError for url::ParseError {}
impl CargoError for ffi::NulError {}
impl CargoError for term::Error {}
impl CargoError for num::ParseIntError {}
impl CargoError for str::ParseBoolError {}

// =============================================================================
// Construction helpers

pub fn process_error(msg: &str,
                     cause: Option<Box<CargoError>>,
                     status: Option<&ExitStatus>,
                     output: Option<&Output>) -> ProcessError
{
    let exit = match status {
        Some(s) => status_to_string(s),
        None => "never executed".to_string(),
    };
    let mut desc = format!("{} ({})", &msg, exit);

    if let Some(out) = output {
        match str::from_utf8(&out.stdout) {
            Ok(s) if s.trim().len() > 0 => {
                desc.push_str("\n--- stdout\n");
                desc.push_str(s);
            }
            Ok(..) | Err(..) => {}
        }
        match str::from_utf8(&out.stderr) {
            Ok(s) if s.trim().len() > 0 => {
                desc.push_str("\n--- stderr\n");
                desc.push_str(s);
            }
            Ok(..) | Err(..) => {}
        }
    }

    return ProcessError {
        desc: desc,
        exit: status.cloned(),
        output: output.cloned(),
        cause: cause,
    };

    #[cfg(unix)]
    fn status_to_string(status: &ExitStatus) -> String {
        use std::os::unix::process::*;
        use libc;

        if let Some(signal) = status.signal() {
            let name = match signal as libc::c_int {
                libc::SIGABRT => ", SIGABRT: process abort signal",
                libc::SIGALRM => ", SIGALRM: alarm clock",
                libc::SIGFPE => ", SIGFPE: erroneous arithmetic operation",
                libc::SIGHUP => ", SIGHUP: hangup",
                libc::SIGILL => ", SIGILL: illegal instruction",
                libc::SIGINT => ", SIGINT: terminal interrupt signal",
                libc::SIGKILL => ", SIGKILL: kill",
                libc::SIGPIPE => ", SIGPIPE: write on a pipe with no one to read",
                libc::SIGQUIT => ", SIGQUIT: terminal quite signal",
                libc::SIGSEGV => ", SIGSEGV: invalid memory reference",
                libc::SIGTERM => ", SIGTERM: termination signal",
                libc::SIGBUS => ", SIGBUS: access to undefined memory",
                libc::SIGSYS => ", SIGSYS: bad system call",
                libc::SIGTRAP => ", SIGTRAP: trace/breakpoint trap",
                _ => "",
            };
            format!("signal: {}{}", signal, name)
        } else {
            status.to_string()
        }
    }

    #[cfg(windows)]
    fn status_to_string(status: &ExitStatus) -> String {
        status.to_string()
    }
}

pub fn internal_error(error: &str, detail: &str) -> Box<CargoError> {
    Box::new(ConcreteCargoError {
        description: error.to_string(),
        detail: Some(detail.to_string()),
        cause: None,
        is_human: false
    })
}

pub fn internal<S: fmt::Display>(error: S) -> Box<CargoError> {
    _internal(&error)
}

fn _internal(error: &fmt::Display) -> Box<CargoError> {
    Box::new(ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: None,
        is_human: false
    })
}

pub fn human<S: fmt::Display>(error: S) -> Box<CargoError> {
    _human(&error)
}

fn _human(error: &fmt::Display) -> Box<CargoError> {
    Box::new(ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: None,
        is_human: true
    })
}

pub fn caused_human<S, E>(error: S, cause: E) -> Box<CargoError>
    where S: fmt::Display,
          E: Error + Send + 'static
{
    Box::new(ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: Some(Box::new(cause)),
        is_human: true
    })
}
<|endoftext|>


<commit_before>use libc::{c_int, c_uint, c_void, size_t};
use std::fmt::{Debug, Formatter};
use std::ffi::CStr;
use std::mem::transmute;
use std::ptr;
use std::str::from_utf8;
use capstone_m68k::cs_detail;

#[repr(C)]
pub struct Insn {
    pub id: c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16],
    pub mnemonic: [i8; 32],
    pub op_str: [i8; 160],
    pub detail: *const c_void,
}

#[repr(C)]
pub struct CCapstone1 {
    version: extern "C" fn(major: *mut c_int, minor: *mut c_int) -> c_uint,
    support: extern "C" fn(query: c_int) -> c_int,
    open: extern "C" fn(arch: c_int, mode: c_int, handle: *mut *const c_void) -> c_int,
    close: extern "C" fn(handle: *mut *const c_void) -> c_int,
    option: extern "C" fn(handle: *const c_void, _type: c_int, value: size_t) -> c_int,
    err: extern "C" fn(handle: *const c_void) -> c_int,
    disasm: extern "C" fn(handle: *const c_void,
                          code: *const u8,
                          code_size: size_t,
                          address: u64,
                          count: size_t,
                          insn: &mut *const Insn)
                          -> size_t,
    free: extern "C" fn(insn: *const Insn, count: size_t),
}

#[derive(Clone, Copy, Debug)]
pub enum Arch {
    Arm = 0,
    Arm64,
    MIPS,
    X86,
    PowerPC,
    Sparc,
    SystemZ,
    XCore,
    M68K,
}

bitflags!(
    flags Mode: u32 {
        const MODE_LITTLE_ENDIAN = 0,
        const MODE_ARM = 0,
        const MODE_16 = 1 << 1,
        const MODE_32 = 1 << 2,
        const MODE_64 = 1 << 3,
        const MODE_THUMB = 1 << 4,
        const MODE_MCLASS = 1 << 5,
        const MODE_V8 = 1 << 6,
        const MODE_MICRO = 1 << 4,
        const MODE_MIPS3 = 1 << 5,
        const MODE_MIPS32R6 = 1 << 6,
        const MODE_MIPSGP64 = 1 << 7,
        const MODE_V9 = 1 << 4,
        const CS_MODE_QPX = 1 << 4,
        const CS_MODE_M68K_000 = 1 << 1,
        const CS_MODE_M68K_010 = 1 << 2,
        const CS_MODE_M68K_020 = 1 << 3,
        const CS_MODE_M68K_030 = 1 << 4,
        const CS_MODE_M68K_040 = 1 << 5,
        const CS_MODE_M68K_060 = 1 << 6,
        const MODE_BIG_ENDIAN= 1 << 31,
        const MODE_MIPS32 = 1 << 2,
        const MODE_MIPS64 = 1 << 3,
    }
);

#[derive(Clone, Copy, Debug)]
pub enum Opt {
    Syntax = 1,
    Detail,
    Mode, // OptMem
}

#[repr(i32)]
pub enum Error {
    /// No error: everything was fine
    Ok,
    /// Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    Mem,
    /// Unsupported architecture: cs_open()
    Arch,
    /// Invalid handle: cs_op_count(), cs_op_index()
    Handle,
    /// Invalid csh argument: cs_close(), cs_errno(), cs_option()
    Csh,
    /// Invalid/unsupported mode: cs_open()
    Mode,
    /// Invalid/unsupported option: cs_option()
    InvOption,
    /// Information is unavailable because detail option is OFF
    Detail,
    /// Dynamic memory management uninitialized (see CS_OPT_MEM)
    MemSetup,
    /// Unsupported version (bindings)
    Version,
    /// Access irrelevant data in "diet" engine
    Diet,
    /// Access irrelevant data for "data" instruction in SKIPDATA mode
    Skipdata,
    /// X86 AT&T syntax is unsupported (opt-out at compile time)
    Att,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Intel,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Mask,
}

pub struct Capstone {
    pub api: *mut CCapstone1,
    pub handle: *const c_void,
}

impl Capstone {
    pub fn open(&mut self, arch: Arch, mode: Mode) -> Result<(), Error> {
        // If handle is already setup we just return from here
        if self.handle != ptr::null_mut() {
            return Ok(());
        }

        let mut handle: *const c_void = 0 as *const c_void;
        unsafe {
            match ((*self.api).open)(arch as c_int, mode.bits as c_int, &mut handle) {
                0 => {
                    self.handle = handle;
                    Ok(())
                }
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn set_option(&self, option: Opt, value: usize) -> Result<(), Error> {
        unsafe {
            match ((*self.api).option)(self.handle, option as c_int, value as size_t) {
                0 => Ok(()),
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn disasm(&self, code: &[u8], addr: u64, count: usize) -> Result<Instructions, Error> {
        let mut ptr: *const Insn = ptr::null();
        let insn_count;
        unsafe {
            insn_count = ((*self.api).disasm)(self.handle,
                                              code.as_ptr(),
                                              code.len() as size_t,
                                              addr,
                                              count as size_t,
                                              &mut ptr) as isize;
        }

        if insn_count == 0 {
            unsafe {
                let num = ((*self.api).err)(self.handle);
                let err: Error = transmute(num);
                return Err(err);
            }
        }

        Ok(Instructions::from_raw_parts(self.api, ptr, insn_count as isize))
    }
}

// Using an actual slice is causing issues with auto deref, instead implement a custom iterator and
// drop trait
pub struct Instructions {
    pub api: *mut CCapstone1,
    ptr: *const Insn,
    len: isize,
}

impl Instructions {
    // This method really shouldn't be public, but it was unclear how to make it visible in lib.rs
    // but not globally visible.
    fn from_raw_parts(api: *mut CCapstone1, ptr: *const Insn, len: isize) -> Instructions {
        Instructions {
            api: api,
            ptr: ptr,
            len: len,
        }
    }

    pub fn len(&self) -> isize {
        self.len
    }

    pub fn iter(&self) -> InstructionIterator {
        InstructionIterator {
            insns: &self,
            cur: 0,
        }
    }
}

impl Drop for Instructions {
    fn drop(&mut self) {
        unsafe {
            ((*self.api).free)(self.ptr, self.len as size_t);
        }
    }
}

pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { ptr::read(obj) })
        }
    }
}

impl Insn {
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.mnemonic.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.op_str.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn detail(&self) -> Option<&cs_detail> {
        unsafe {
            if self.detail == ptr::null() {
                return None;
            }

            let d: &cs_detail = transmute(self.detail);
            Some(d)
        }
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        fmt.debug_struct("Insn")
           .field("address", &self.address)
           .field("size", &self.size)
           .field("mnemonic", &self.mnemonic())
           .field("op_str", &self.op_str())
           .finish()
    }
}
<commit_msg>Added support to get rw regs list and reg_name<commit_after>use libc::{c_int, c_uint, c_void, size_t};
use std::fmt::{Debug, Formatter};
use std::ffi::CStr;
use std::mem::transmute;
use std::slice;
use std::ptr;
use std::str::from_utf8;
use capstone_m68k::cs_detail;

#[repr(C)]
pub struct Insn {
    pub id: c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16],
    pub mnemonic: [i8; 32],
    pub op_str: [i8; 160],
    pub detail: *const c_void,
}

#[repr(C)]
pub struct CCapstone1 {
    version: extern "C" fn(major: *mut c_int, minor: *mut c_int) -> c_uint,
    support: extern "C" fn(query: c_int) -> c_int,
    open: extern "C" fn(arch: c_int, mode: c_int, handle: *mut *const c_void) -> c_int,
    close: extern "C" fn(handle: *mut *const c_void) -> c_int,
    option: extern "C" fn(handle: *const c_void, _type: c_int, value: size_t) -> c_int,
    err: extern "C" fn(handle: *const c_void) -> c_int,
    disasm: extern "C" fn(handle: *const c_void,
                          code: *const u8,
                          code_size: size_t,
                          address: u64,
                          count: size_t,
                          insn: &mut *const Insn)
                          -> size_t,
    free: extern "C" fn(insn: *const Insn, count: size_t),

    disasm_iter: extern "C" fn(handle: *const c_void,
                              code: *const u8,
                              code_size: *const size_t) -> size_t,
    regname: extern "C" fn(handle: *const c_void, id: u16) -> *const i8,
}

#[derive(Clone, Copy, Debug)]
pub enum Arch {
    Arm = 0,
    Arm64,
    MIPS,
    X86,
    PowerPC,
    Sparc,
    SystemZ,
    XCore,
    M68K,
}

bitflags!(
    flags Mode: u32 {
        const MODE_LITTLE_ENDIAN = 0,
        const MODE_ARM = 0,
        const MODE_16 = 1 << 1,
        const MODE_32 = 1 << 2,
        const MODE_64 = 1 << 3,
        const MODE_THUMB = 1 << 4,
        const MODE_MCLASS = 1 << 5,
        const MODE_V8 = 1 << 6,
        const MODE_MICRO = 1 << 4,
        const MODE_MIPS3 = 1 << 5,
        const MODE_MIPS32R6 = 1 << 6,
        const MODE_MIPSGP64 = 1 << 7,
        const MODE_V9 = 1 << 4,
        const CS_MODE_QPX = 1 << 4,
        const CS_MODE_M68K_000 = 1 << 1,
        const CS_MODE_M68K_010 = 1 << 2,
        const CS_MODE_M68K_020 = 1 << 3,
        const CS_MODE_M68K_030 = 1 << 4,
        const CS_MODE_M68K_040 = 1 << 5,
        const CS_MODE_M68K_060 = 1 << 6,
        const MODE_BIG_ENDIAN= 1 << 31,
        const MODE_MIPS32 = 1 << 2,
        const MODE_MIPS64 = 1 << 3,
    }
);

#[derive(Clone, Copy, Debug)]
pub enum Opt {
    Syntax = 1,
    Detail,
    Mode, // OptMem
}

#[repr(i32)]
pub enum Error {
    /// No error: everything was fine
    Ok,
    /// Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    Mem,
    /// Unsupported architecture: cs_open()
    Arch,
    /// Invalid handle: cs_op_count(), cs_op_index()
    Handle,
    /// Invalid csh argument: cs_close(), cs_errno(), cs_option()
    Csh,
    /// Invalid/unsupported mode: cs_open()
    Mode,
    /// Invalid/unsupported option: cs_option()
    InvOption,
    /// Information is unavailable because detail option is OFF
    Detail,
    /// Dynamic memory management uninitialized (see CS_OPT_MEM)
    MemSetup,
    /// Unsupported version (bindings)
    Version,
    /// Access irrelevant data in "diet" engine
    Diet,
    /// Access irrelevant data for "data" instruction in SKIPDATA mode
    Skipdata,
    /// X86 AT&T syntax is unsupported (opt-out at compile time)
    Att,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Intel,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Mask,
}

pub struct Capstone {
    pub api: *mut CCapstone1,
    pub handle: *const c_void,
}

impl Capstone {
    pub fn open(&mut self, arch: Arch, mode: Mode) -> Result<(), Error> {
        // If handle is already setup we just return from here
        if self.handle != ptr::null_mut() {
            return Ok(());
        }

        let mut handle: *const c_void = 0 as *const c_void;
        unsafe {
            match ((*self.api).open)(arch as c_int, mode.bits as c_int, &mut handle) {
                0 => {
                    self.handle = handle;
                    Ok(())
                }
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn set_option(&self, option: Opt, value: usize) -> Result<(), Error> {
        unsafe {
            match ((*self.api).option)(self.handle, option as c_int, value as size_t) {
                0 => Ok(()),
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn disasm(&self, code: &[u8], addr: u64, count: usize) -> Result<Instructions, Error> {
        let mut ptr: *const Insn = ptr::null();
        let insn_count;
        unsafe {
            insn_count = ((*self.api).disasm)(self.handle,
                                              code.as_ptr(),
                                              code.len() as size_t,
                                              addr,
                                              count as size_t,
                                              &mut ptr) as isize;
        }

        if insn_count == 0 {
            unsafe {
                let num = ((*self.api).err)(self.handle);
                let err: Error = transmute(num);
                return Err(err);
            }
        }

        Ok(Instructions::from_raw_parts(self.api, ptr, insn_count as isize))
    }

    pub fn reg_name(&self, reg_id: u16) -> &str {
        unsafe {
            let name = ((*self.api).regname)(self.handle, reg_id);

            // very lange slice so this is kinda hacky but should work
            let t = slice::from_raw_parts(name, 16834);
            let mut count = 0;

            loop {
                if t[count] == 0 { break; }
                count += 1;
            }

            let slice = slice::from_raw_parts(name as *const u8, count);
            from_utf8(slice).unwrap()
        }
    }
}

// Using an actual slice is causing issues with auto deref, instead implement a custom iterator and
// drop trait
pub struct Instructions {
    pub api: *mut CCapstone1,
    ptr: *const Insn,
    len: isize,
}

impl Instructions {
    // This method really shouldn't be public, but it was unclear how to make it visible in lib.rs
    // but not globally visible.
    fn from_raw_parts(api: *mut CCapstone1, ptr: *const Insn, len: isize) -> Instructions {
        Instructions {
            api: api,
            ptr: ptr,
            len: len,
        }
    }

    pub fn len(&self) -> isize {
        self.len
    }

    pub fn iter(&self) -> InstructionIterator {
        InstructionIterator {
            insns: &self,
            cur: 0,
        }
    }
}

impl Drop for Instructions {
    fn drop(&mut self) {
        unsafe {
            ((*self.api).free)(self.ptr, self.len as size_t);
        }
    }
}

pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { ptr::read(obj) })
        }
    }
}

impl Insn {
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.mnemonic.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.op_str.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn detail(&self) -> Option<&cs_detail> {
        unsafe {
            if self.detail == ptr::null() {
                return None;
            }

            let d: &cs_detail = transmute(self.detail);
            Some(d)
        }
    }

    pub fn regs_read(&self) -> Option<&[u16]> {
        unsafe {
            if self.detail == ptr::null() {
                return None;
            }

            let detail: &cs_detail = transmute(self.detail);
            Some(&slice::from_raw_parts(detail.regs_read.as_ptr(), detail.regs_read_count as usize))
            //Some(&detail.regs_read)
        }
    }

    pub fn regs_write(&self) -> Option<&[u16]> {
        unsafe {
            if self.detail == ptr::null() {
                return None;
            }

            let detail: &cs_detail = transmute(self.detail);
            Some(&slice::from_raw_parts(detail.regs_write.as_ptr(), detail.regs_write_count as usize))
        }
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        fmt.debug_struct("Insn")
           .field("address", &self.address)
           .field("size", &self.size)
           .field("mnemonic", &self.mnemonic())
           .field("op_str", &self.op_str())
           .finish()
    }
}
<|endoftext|>


<commit_before>
use std::ops::{Add, Sub, Mul, Div};
use std::ops::{MulAssign, DivAssign};

use vec::{Vec3, Vec4};
use mat::{Mat4, Mat3};
use traits::{Number, Float};

#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub struct Quaternion<T> {
    pub x: T,
    pub y: T,
    pub w: T,
    pub z: T,
}

impl<T: Copy> Copy for Quaternion<T> {}

impl<T: Number + Float> Default for Quaternion<T> {
    fn default() -> Quaternion<T> {
        Quaternion::IDENTITY
    }
}

impl<T: Number + Float> Quaternion<T> {
    /// Creates a new identity quaternion
    pub const IDENTITY: Quaternion<T> = Quaternion {
            x: T::ZERO,
            y: T::ZERO,
            z: T::ZERO,
            w: T::ONE,
    };

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// given axis. This function normalizes the axis, but if the axis is `(0, 0, 0)` the quaternion
    /// will have its `x`, `y` and `z` fields set to 0.
    pub fn rotation(angle: T, axis: Vec3<T>) -> Quaternion<T> {
        let axis = axis.normalize();
        let angle = angle / (T::ONE + T::ONE);
        let (sin, cos) = angle.sin_cos();

        Quaternion {
            x: axis.x*sin,
            y: axis.y*sin,
            z: axis.z*sin,
            w: cos,
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// x-axis.
    pub fn rotation_x(angle: T) -> Quaternion<T> {
        let angle = angle / (T::ONE + T::ONE);
        let (sin, cos) = angle.sin_cos();

        Quaternion {
            x: sin,
            y: T::ZERO,
            z: T::ZERO,
            w: cos,
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// y-axis.
    pub fn rotation_y(angle: T) -> Quaternion<T> {
        let angle = angle / (T::ONE + T::ONE);
        let (sin, cos) = angle.sin_cos();

        Quaternion {
            x: T::ZERO,
            y: sin,
            z: T::ZERO,
            w: cos,
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// z-axis.
    pub fn rotation_z(angle: T) -> Quaternion<T> {
        let angle = angle / (T::ONE + T::ONE);
        let (sin, cos) = angle.sin_cos();

        Quaternion {
            x: T::ZERO,
            y: T::ZERO,
            z: sin,
            w: cos,
        }
    }

    /// Calculates the length of this quaternion, raised to the power of two. Note that this is
    /// cheaper than computing the actual length.
    pub fn len_sqr(&self) -> T {
        self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w
    }

    /// Calculates the length of this quaternion.
    pub fn len(&self) -> T {
        (self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w).sqrt()
    }

    /// Normalizes this quaternion, returning a new quaternion with length 1.
    pub fn normalize(&self) -> Quaternion<T> {
        *self / self.len()
    }

    /// Calculates the dot (inner) product of the two given quaternions.
    pub fn dot(a: Quaternion<T>, b: Quaternion<T>) -> T {
        a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w
    }

    /// Calculates the angle between the two given quaternions
    pub fn angle_between(a: Quaternion<T>, b: Quaternion<T>) -> T {
        Quaternion::dot(a, b).acos()
    }

    /// Interpolates linearly between the two given quaternions. This works well as long as the
    /// quaternions are not to different. `t` should be in the range `0..1`.
    ///
    /// nlerp stands for normalized linear interpolation.
    pub fn nlerp(a: Quaternion<T>, b: Quaternion<T>, t: T) -> Quaternion<T> {
        if Quaternion::dot(a, b) < T::ZERO {
            (a*(T::ONE - t) - b*t).normalize()
        } else {
            (a*(T::ONE - t) + b*t).normalize()
        }
    }

    /// Returns a quaternion represention the oposite rotation. This inverts the x, y and z
    /// components of this quaternion.
    pub fn conjugate(self) -> Quaternion<T> {
        Quaternion {
            x: -self.x,
            y: -self.y,
            z: -self.z,
            w: self.w,
        }
    }
}

// Quaternion vector multiplication
impl<T: Number + Float> Mul<Vec3<T>> for Quaternion<T> {
    type Output = Vec3<T>;
    fn mul(self, vec: Vec3<T>) -> Vec3<T> {
        let one = T::ONE;
        let two = one + one;

        let a11 = one - two*self.y*self.y - two*self.z*self.z;
        let a12 = two*self.x*self.y - two*self.z*self.w;
        let a13 = two*self.x*self.z + two*self.y*self.w;

        let a21 = two*self.x*self.y + two*self.w*self.z;
        let a22 = one - two*self.x*self.x - two*self.z*self.z;
        let a23 = two*self.y*self.z - two*self.w*self.x;

        let a31 = two*self.x*self.z - two*self.w*self.y;
        let a32 = two*self.y*self.z + two*self.w*self.x;
        let a33 = one - two*self.x*self.x - two*self.y*self.y;

        Vec3 {
            x: vec.x*a11 + vec.y*a12 + vec.z*a13,
            y: vec.x*a21 + vec.y*a22 + vec.z*a23,
            z: vec.x*a31 + vec.y*a32 + vec.z*a33,
        }
    }
}

// Quaternion quaternion multiplication
impl<T: Number + Float> Mul for Quaternion<T> {
    type Output = Self;
    fn mul(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y,
            y: self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z,
            z: self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x,
            w: self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z,
        }
    }
}
impl<T: Number + Float> MulAssign for Quaternion<T> {
    fn mul_assign(&mut self, other: Quaternion<T>) {
        let x = self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y;
        let y = self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z;
        let z = self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x;
        let w = self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z;
        self.x = x;
        self.y = y;
        self.z = z;
        self.w = w;
    }
}

// Quaternion quaternion addition
impl<T: Number + Float> Add for Quaternion<T> {
    type Output = Self;
    fn add(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
            w: self.w + other.w,
        }
    }
}
impl<T: Number + Float> Sub for Quaternion<T> {
    type Output = Self;
    fn sub(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
            w: self.w - other.w,
        }
    }
}

// Quaternion scalar multiplication
impl<T: Number + Float> Mul<T> for Quaternion<T> {
    type Output = Self;
    fn mul(self, scalar: T) -> Self {
        Quaternion {
            x: self.x * scalar,
            y: self.y * scalar,
            z: self.z * scalar,
            w: self.w * scalar,
        }
    }
}
impl<T: Number + Float> MulAssign<T> for Quaternion<T> {
    fn mul_assign(&mut self, scalar: T) {
        self.x = self.x * scalar;
        self.y = self.y * scalar;
        self.z = self.z * scalar;
        self.w = self.w * scalar;
    }
}
impl<T: Number + Float> Div<T> for Quaternion<T> {
    type Output = Self;
    fn div(self, scalar: T) -> Self {
        Quaternion {
            x: self.x / scalar,
            y: self.y / scalar,
            z: self.z / scalar,
            w: self.w / scalar,
        }
    }
}
impl<T: Number + Float> DivAssign<T> for Quaternion<T> {
    fn div_assign(&mut self, scalar: T) {
        self.x = self.x / scalar;
        self.y = self.y / scalar;
        self.z = self.z / scalar;
        self.w = self.w / scalar;
    }
}

impl<T: Number + Float> From<Quaternion<T>> for Mat4<T> {
    fn from(quat: Quaternion<T>) -> Mat4<T> {
        Mat4::from_quaternion(quat.x, quat.y, quat.z, quat.w)
    }
}

impl<T: Number + Float> From<Quaternion<T>> for Mat3<T> {
    fn from(quat: Quaternion<T>) -> Mat3<T> {
        Mat3::from_quaternion(quat.x, quat.y, quat.z, quat.w)
    }
}

impl<T: Number + Float> From<Quaternion<T>> for Vec4<T> {
    fn from(quat: Quaternion<T>) -> Vec4<T> {
        Vec4::new(quat.x, quat.y, quat.z, quat.w)
    }
}

#[cfg(test)]
mod tests {
    use std::f32;
    use super::*;
    use {Mat4, Vec4};

    #[test]
    fn identity() {
        let identity = Quaternion::<f32>::IDENTITY;
        assert_eq!(identity, identity*identity);
        assert_eq!(identity, identity*identity*identity);
    }

    #[test]
    fn matrix_rotation() {
        let quat = Quaternion::<f32>::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0));
        let mat: Mat4<f32> = quat.into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);
        let b = Vec4::new(0.0, 0.0, 1.0, 1.0);

        let diff = (mat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn matrix_rotation_reverse() {
        let mat_a: Mat4<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let mat_b: Mat4<f32> = Quaternion::rotation(-f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);

        let diff = (mat_a*mat_b*a - a).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn quaternion_rotation() {
        let quat: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec3::new(0.0, 1.0, 0.0);
        let b = Vec3::new(0.0, 0.0, 1.0);

        let diff = (quat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn angle_between() {
        let a: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(0.0, 1.0, 0.0)).into();

        let diff = Quaternion::angle_between(a, b) - f32::consts::PI/2.0;
        assert!(diff < 0.001);
    }

    #[test]
    fn nlerp() {
        let a = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b = Quaternion::IDENTITY;

        let c = Quaternion::nlerp(a, b, 0.5);
        let expected = Quaternion::rotation(f32::consts::PI/4.0, Vec3::new(1.0, 0.0, 0.0));

        let diff = Quaternion::angle_between(c, expected);
        assert!(diff < 0.001);
    }
}
<commit_msg>Conversion from vec4 to quaternion<commit_after>
use std::ops::{Add, Sub, Mul, Div};
use std::ops::{MulAssign, DivAssign};

use vec::{Vec3, Vec4};
use mat::{Mat4, Mat3};
use traits::{Number, Float};

#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub struct Quaternion<T> {
    pub x: T,
    pub y: T,
    pub w: T,
    pub z: T,
}

impl<T: Copy> Copy for Quaternion<T> {}

impl<T: Number + Float> Default for Quaternion<T> {
    fn default() -> Quaternion<T> {
        Quaternion::IDENTITY
    }
}

impl<T: Number + Float> Quaternion<T> {
    /// Creates a new identity quaternion
    pub const IDENTITY: Quaternion<T> = Quaternion {
            x: T::ZERO,
            y: T::ZERO,
            z: T::ZERO,
            w: T::ONE,
    };

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// given axis. This function normalizes the axis, but if the axis is `(0, 0, 0)` the quaternion
    /// will have its `x`, `y` and `z` fields set to 0.
    pub fn rotation(angle: T, axis: Vec3<T>) -> Quaternion<T> {
        let axis = axis.normalize();
        let angle = angle / (T::ONE + T::ONE);
        let (sin, cos) = angle.sin_cos();

        Quaternion {
            x: axis.x*sin,
            y: axis.y*sin,
            z: axis.z*sin,
            w: cos,
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// x-axis.
    pub fn rotation_x(angle: T) -> Quaternion<T> {
        let angle = angle / (T::ONE + T::ONE);
        let (sin, cos) = angle.sin_cos();

        Quaternion {
            x: sin,
            y: T::ZERO,
            z: T::ZERO,
            w: cos,
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// y-axis.
    pub fn rotation_y(angle: T) -> Quaternion<T> {
        let angle = angle / (T::ONE + T::ONE);
        let (sin, cos) = angle.sin_cos();

        Quaternion {
            x: T::ZERO,
            y: sin,
            z: T::ZERO,
            w: cos,
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// z-axis.
    pub fn rotation_z(angle: T) -> Quaternion<T> {
        let angle = angle / (T::ONE + T::ONE);
        let (sin, cos) = angle.sin_cos();

        Quaternion {
            x: T::ZERO,
            y: T::ZERO,
            z: sin,
            w: cos,
        }
    }

    /// Calculates the length of this quaternion, raised to the power of two. Note that this is
    /// cheaper than computing the actual length.
    pub fn len_sqr(&self) -> T {
        self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w
    }

    /// Calculates the length of this quaternion.
    pub fn len(&self) -> T {
        (self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w).sqrt()
    }

    /// Normalizes this quaternion, returning a new quaternion with length 1.
    pub fn normalize(&self) -> Quaternion<T> {
        *self / self.len()
    }

    /// Calculates the dot (inner) product of the two given quaternions.
    pub fn dot(a: Quaternion<T>, b: Quaternion<T>) -> T {
        a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w
    }

    /// Calculates the angle between the two given quaternions
    pub fn angle_between(a: Quaternion<T>, b: Quaternion<T>) -> T {
        Quaternion::dot(a, b).acos()
    }

    /// Interpolates linearly between the two given quaternions. This works well as long as the
    /// quaternions are not to different. `t` should be in the range `0..1`.
    ///
    /// nlerp stands for normalized linear interpolation.
    pub fn nlerp(a: Quaternion<T>, b: Quaternion<T>, t: T) -> Quaternion<T> {
        if Quaternion::dot(a, b) < T::ZERO {
            (a*(T::ONE - t) - b*t).normalize()
        } else {
            (a*(T::ONE - t) + b*t).normalize()
        }
    }

    /// Returns a quaternion represention the oposite rotation. This inverts the x, y and z
    /// components of this quaternion.
    pub fn conjugate(self) -> Quaternion<T> {
        Quaternion {
            x: -self.x,
            y: -self.y,
            z: -self.z,
            w: self.w,
        }
    }
}

// Quaternion vector multiplication
impl<T: Number + Float> Mul<Vec3<T>> for Quaternion<T> {
    type Output = Vec3<T>;
    fn mul(self, vec: Vec3<T>) -> Vec3<T> {
        let one = T::ONE;
        let two = one + one;

        let a11 = one - two*self.y*self.y - two*self.z*self.z;
        let a12 = two*self.x*self.y - two*self.z*self.w;
        let a13 = two*self.x*self.z + two*self.y*self.w;

        let a21 = two*self.x*self.y + two*self.w*self.z;
        let a22 = one - two*self.x*self.x - two*self.z*self.z;
        let a23 = two*self.y*self.z - two*self.w*self.x;

        let a31 = two*self.x*self.z - two*self.w*self.y;
        let a32 = two*self.y*self.z + two*self.w*self.x;
        let a33 = one - two*self.x*self.x - two*self.y*self.y;

        Vec3 {
            x: vec.x*a11 + vec.y*a12 + vec.z*a13,
            y: vec.x*a21 + vec.y*a22 + vec.z*a23,
            z: vec.x*a31 + vec.y*a32 + vec.z*a33,
        }
    }
}

// Quaternion quaternion multiplication
impl<T: Number + Float> Mul for Quaternion<T> {
    type Output = Self;
    fn mul(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y,
            y: self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z,
            z: self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x,
            w: self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z,
        }
    }
}
impl<T: Number + Float> MulAssign for Quaternion<T> {
    fn mul_assign(&mut self, other: Quaternion<T>) {
        let x = self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y;
        let y = self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z;
        let z = self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x;
        let w = self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z;
        self.x = x;
        self.y = y;
        self.z = z;
        self.w = w;
    }
}

// Quaternion quaternion addition
impl<T: Number + Float> Add for Quaternion<T> {
    type Output = Self;
    fn add(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
            w: self.w + other.w,
        }
    }
}
impl<T: Number + Float> Sub for Quaternion<T> {
    type Output = Self;
    fn sub(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
            w: self.w - other.w,
        }
    }
}

// Quaternion scalar multiplication
impl<T: Number + Float> Mul<T> for Quaternion<T> {
    type Output = Self;
    fn mul(self, scalar: T) -> Self {
        Quaternion {
            x: self.x * scalar,
            y: self.y * scalar,
            z: self.z * scalar,
            w: self.w * scalar,
        }
    }
}
impl<T: Number + Float> MulAssign<T> for Quaternion<T> {
    fn mul_assign(&mut self, scalar: T) {
        self.x = self.x * scalar;
        self.y = self.y * scalar;
        self.z = self.z * scalar;
        self.w = self.w * scalar;
    }
}
impl<T: Number + Float> Div<T> for Quaternion<T> {
    type Output = Self;
    fn div(self, scalar: T) -> Self {
        Quaternion {
            x: self.x / scalar,
            y: self.y / scalar,
            z: self.z / scalar,
            w: self.w / scalar,
        }
    }
}
impl<T: Number + Float> DivAssign<T> for Quaternion<T> {
    fn div_assign(&mut self, scalar: T) {
        self.x = self.x / scalar;
        self.y = self.y / scalar;
        self.z = self.z / scalar;
        self.w = self.w / scalar;
    }
}

impl<T: Number + Float> From<Quaternion<T>> for Mat4<T> {
    fn from(quat: Quaternion<T>) -> Mat4<T> {
        Mat4::from_quaternion(quat.x, quat.y, quat.z, quat.w)
    }
}

impl<T: Number + Float> From<Quaternion<T>> for Mat3<T> {
    fn from(quat: Quaternion<T>) -> Mat3<T> {
        Mat3::from_quaternion(quat.x, quat.y, quat.z, quat.w)
    }
}

impl<T: Number + Float> From<Quaternion<T>> for Vec4<T> {
    fn from(quat: Quaternion<T>) -> Vec4<T> {
        Vec4::new(quat.x, quat.y, quat.z, quat.w)
    }
}

impl<T: Number + Float> From<Vec4<T>> for Quaternion<T> {
    fn from(vec: Vec4<T>) -> Quaternion<T> {
        Quaternion {
            x: vec.x,
            y: vec.y,
            z: vec.z,
            w: vec.w,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::f32;
    use super::*;
    use {Mat4, Vec4};

    #[test]
    fn identity() {
        let identity = Quaternion::<f32>::IDENTITY;
        assert_eq!(identity, identity*identity);
        assert_eq!(identity, identity*identity*identity);
    }

    #[test]
    fn matrix_rotation() {
        let quat = Quaternion::<f32>::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0));
        let mat: Mat4<f32> = quat.into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);
        let b = Vec4::new(0.0, 0.0, 1.0, 1.0);

        let diff = (mat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn matrix_rotation_reverse() {
        let mat_a: Mat4<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let mat_b: Mat4<f32> = Quaternion::rotation(-f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);

        let diff = (mat_a*mat_b*a - a).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn quaternion_rotation() {
        let quat: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec3::new(0.0, 1.0, 0.0);
        let b = Vec3::new(0.0, 0.0, 1.0);

        let diff = (quat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn angle_between() {
        let a: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(0.0, 1.0, 0.0)).into();

        let diff = Quaternion::angle_between(a, b) - f32::consts::PI/2.0;
        assert!(diff < 0.001);
    }

    #[test]
    fn nlerp() {
        let a = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b = Quaternion::IDENTITY;

        let c = Quaternion::nlerp(a, b, 0.5);
        let expected = Quaternion::rotation(f32::consts::PI/4.0, Vec3::new(1.0, 0.0, 0.0));

        let diff = Quaternion::angle_between(c, expected);
        assert!(diff < 0.001);
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project\n");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = Command::new(format!("cargo-{}", cmd))
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_str());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<commit_msg>Add command line help text for new subcommand 'cargo test'<commit_after>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project\n");
            println!("  test           # run the tests\n");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = Command::new(format!("cargo-{}", cmd))
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_str());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]
extern crate script;
extern crate collections;
use script::lexer::Lexer;
use script::parser::Parser;
use script::exec::{Executor, Interpreter};
use script::ast::{Token, TComment};
use script::js::value::{Value, ResultValue, to_value, from_value};
use collections::treemap::TreeMap;
use std::path::posix::Path;
use std::io::fs::{File, walk_dir};
use std::io::BufferedReader;
fn find_attrs(tokens: Vec<Token>) -> TreeMap<~str, ~str> {
	let mut map = TreeMap::new();
	for tk in tokens.iter() {
		match tk.data {
			TComment(ref comm) => {
				let current = comm.as_slice();
				if current.starts_with(" @") {
					let space_ind = current.slice_from(1).find(' ').unwrap() + 1;
					let key = comm.slice_chars(2, space_ind);
					let value = comm.slice_from(space_ind);
					map.insert(key.into_owned(), value.into_owned());
				}
			},
			_ => ()
		}
	}
	map
}
fn assert(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let val : bool = from_value(*args.get(0)).unwrap();
	if val {
		Ok(to_value(true))
	} else {
		Err(to_value(false))
	}
}
fn main() {
	for file in walk_dir(&Path::new("../tests/")).unwrap() {
		if file.is_file() && file.extension_str() == Some("js") {
			let file_str = file.as_str().unwrap();
			let mut lexer = Lexer::new(BufferedReader::new(File::open(&file).unwrap()));
			lexer.lex().unwrap();
			let attributes = find_attrs(lexer.tokens.clone());
			let description = match attributes.find(&"description".into_owned()) {
				Some(desc) => desc,
				None => fail!("{} does not have @description metadata", file_str)
			};
			let mut parser = Parser::new(lexer.tokens);
			let expr = match parser.parse_all() {
				Ok(v) => v,
				Err(v) => fail!("{}: {}", file_str, v)
			};
			let mut engine : Interpreter = Executor::new();
			engine.set_global("assert".into_maybe_owned(), to_value(assert));
			let result : Result<Value, Value> = engine.run(&expr);
			match result {
				Ok(_) => println!("All tests passed: {} - {}", file_str, description),
				Err(v) => fail!("Test failed: {} - {}: {}", file_str, description, v.borrow())
			}
		}
	}
}<commit_msg>Make tests more verbose<commit_after>#![crate_type = "bin"]
extern crate script;
extern crate collections;
use script::lexer::Lexer;
use script::parser::Parser;
use script::exec::{Executor, Interpreter};
use script::ast::{Token, TComment};
use script::js::value::{Value, ResultValue, to_value, from_value};
use collections::treemap::TreeMap;
use std::path::posix::Path;
use std::io::fs::{File, walk_dir};
use std::io::BufferedReader;
fn find_attrs(tokens: Vec<Token>) -> TreeMap<~str, ~str> {
	let mut map = TreeMap::new();
	for tk in tokens.iter() {
		match tk.data {
			TComment(ref comm) => {
				let current = comm.as_slice();
				if current.starts_with(" @") {
					let space_ind = current.slice_from(1).find(' ').unwrap() + 1;
					let key = comm.slice_chars(2, space_ind);
					let value = comm.slice_from(space_ind);
					map.insert(key.into_owned(), value.into_owned());
				}
			},
			_ => ()
		}
	}
	map
}
fn assert(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let val : bool = from_value(*args.get(0)).unwrap();
	let desc : Value = *args.get(1);
	if val {
		Ok(desc)
	} else {
		Err(desc)
	}
}
fn main() {
	let mut path = Path::new("tests");
	if !path.is_dir() {
		path = Path::new("../tests");
	}
	if !path.is_dir() {
		fail!("Could not find tests directory");
	}
	for file in walk_dir(&path).unwrap() {
		if file.is_file() && file.extension_str() == Some("js") {
			let file_str = file.as_str().unwrap();
			let mut lexer = Lexer::new(BufferedReader::new(File::open(&file).unwrap()));
			lexer.lex().unwrap();
			let attributes = find_attrs(lexer.tokens.clone());
			let description = match attributes.find(&"description".into_owned()) {
				Some(desc) => desc,
				None => fail!("{} does not have @description metadata", file_str)
			};
			let mut parser = Parser::new(lexer.tokens);
			let expr = match parser.parse_all() {
				Ok(v) => v,
				Err(v) => fail!("{}: {}", file_str, v)
			};
			let mut engine : Interpreter = Executor::new();
			engine.set_global("assert".into_maybe_owned(), to_value(assert));
			let result : Result<Value, Value> = engine.run(&expr);
			match result {
				Ok(_) => println!("All tests passed: {} - {}", file_str, description),
				Err(v) => fail!("Test failed: {} - {}: {}", file_str, description, v.borrow())
			}
		}
	}
}<|endoftext|>