<commit_before>extern crate daemon;
extern crate iron;
extern crate router;
extern crate fern;
extern crate time;
extern crate rustc_serialize;
#[macro_use]
extern crate log;

use daemon::State;
use daemon::Daemon;
use daemon::DaemonRunner;
use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;
use std::io::Read;
use std::net::IpAddr;
use std::net::SocketAddr;
use std::path::Path;
use std::sync::mpsc::Receiver;
use std::sync::{Mutex, Arc};

#[derive(RustcEncodable, RustcDecodable)]
struct BuilderInfo {
    pub id: String,
    pub endpoints: Vec<String>,
}

struct CoordinatorService {
    pub builders: Mutex<Vec<BuilderInfo>>,
}

macro_rules! service_router {
    ($service:expr,$($method:ident $glob:expr => $handler:ident),+ $(,)*) => ({
        let mut router = router::Router::new();
        let service = Arc::new($service);
        $({
            let service_clone = service.clone();
            router.$method($glob, move |r: &mut Request| service_clone.$handler(r) );
        })*
        router
    });
}

impl CoordinatorService {
    pub fn new() -> CoordinatorService {
        let mut builders: Vec<BuilderInfo> = Vec::new();
        builders.push(BuilderInfo {
            id: "builder-1".to_string(),
            endpoints: vec!("127.0.0.1:1234".to_string(), "[::1]:1234".to_string()),
        });
        builders.push(BuilderInfo {
            id: "builder-2".to_string(),
            endpoints: vec!("127.0.0.2:1234".to_string(), "[::1]:1235".to_string()),
        });
        CoordinatorService {
            builders: Mutex::new(builders),
        }
    }

    pub fn rpc_agent_list(&self, _: &mut Request) -> IronResult<Response> {
        let holder = self.builders.lock().unwrap();
        let builders: &Vec<BuilderInfo> = &holder;
        let payload = json::encode(builders).unwrap();
        Ok(Response::with((status::Ok, payload)))
    }

    pub fn rpc_agent_updaet(&self, request: &mut Request) -> IronResult<Response> {
        let mut payload = String::new();
        request.body.read_to_string(&mut payload).unwrap();
        let builder: BuilderInfo = json::decode(&payload).unwrap();
        {
            let mut holder = self.builders.lock().unwrap();
            holder.push(builder);
        }
        Ok(Response::with((status::Ok, "Foo")))
    }
}

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello World!")))
}

fn main() {
    let daemon = Daemon {
        name: "octobuild_coordinator".to_string()
    };

    daemon.run(move |rx: Receiver<State>| {
        init_logger();

        info!("Coordinator started.");
        let mut web = None;
        for signal in rx.iter() {
            match signal {
                State::Start => {
                    info!("Coordinator: Starting on 3000");
                    let router = service_router!(CoordinatorService::new(),
                        get "/rpc/v1/agent/list" => rpc_agent_list,
                        post "/rpc/v1/agent/update" => rpc_agent_list,
                    );
                    web = Some(Iron::new(router).http("localhost:3000").unwrap());
                    info!("Coordinator: Readly");
                },
                State::Reload => {
                    info!("Coordinator: Reload");
                }
                State::Stop => {
                    info!("Coordinator: Stoping");
                    match web.take() {
                        Some(mut v) => { v.close().unwrap(); }
                        None => {}
                    }
                    info!("Coordinator: Stoped");
                }
            };
        }
        info!("Coordinator shutdowned.");
    }).unwrap();
}

fn init_logger() {
    let log_file = Path::new("octo_coordinator.log").to_path_buf();

    // Create a basic logger configuration
    let logger_config = fern::DispatchConfig {
        format: Box::new(|msg, level, _location| {
            // This format just displays [{level}] {message}
            format!("{} [{}] {}", time::now().rfc3339(), level, msg)
        }),
        // Output to stdout and the log file in the temporary directory we made above to test
        output: vec![fern::OutputConfig::stdout(), fern::OutputConfig::file(&log_file)],
        // Only log messages Info and above
        level: log::LogLevelFilter::Info,
    };

    if let Err(e) = fern::init_global_logger(logger_config, log::LogLevelFilter::Trace) {
        panic!("Failed to initialize global logger: {}", e);
    }
}<commit_msg>fixup! Simple coordinator<commit_after>extern crate daemon;
extern crate iron;
extern crate router;
extern crate fern;
extern crate time;
extern crate rustc_serialize;
#[macro_use]
extern crate log;

use daemon::State;
use daemon::Daemon;
use daemon::DaemonRunner;
use iron::prelude::*;
use iron::status;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;
use time::{Duration, Timespec};
use std::io::Read;
use std::net::IpAddr;
use std::net::SocketAddr;
use std::path::Path;
use std::sync::mpsc::Receiver;
use std::sync::{Mutex, Arc};

#[derive(RustcEncodable, RustcDecodable)]
struct BuilderInfo {
    pub id: String,
    pub endpoints: Vec<String>,
    pub timeout: i64,
}

struct CoordinatorService {
    pub builders: Mutex<Vec<BuilderInfo>>,
}

macro_rules! service_router {
    ($service:expr,$($method:ident $glob:expr => $handler:ident),+ $(,)*) => ({
        let mut router = router::Router::new();
        let service = Arc::new($service);
        $({
            let service_clone = service.clone();
            router.$method($glob, move |r: &mut Request| service_clone.$handler(r) );
        })*
        router
    });
}

impl CoordinatorService {
    pub fn new() -> CoordinatorService {
        let mut builders: Vec<BuilderInfo> = Vec::new();
        builders.push(BuilderInfo {
            id: "builder-1".to_string(),
            endpoints: vec!("127.0.0.1:1234".to_string(), "[::1]:1234".to_string()),
            timeout: 0,
        });
        builders.push(BuilderInfo {
            id: "builder-2".to_string(),
            endpoints: vec!("127.0.0.2:1234".to_string(), "[::1]:1235".to_string()),
            timeout: 0,
        });
        CoordinatorService {
            builders: Mutex::new(builders),
        }
    }

    pub fn rpc_agent_list(&self, _: &mut Request) -> IronResult<Response> {
        let mut holder = self.builders.lock().unwrap();
        let builders: &mut Vec<BuilderInfo> = &mut holder;
        let now = time::get_time().sec;
        builders.retain(|e| e.timeout >= now);
        Ok(Response::with((status::Ok, json::encode(builders).unwrap())))
    }

    pub fn rpc_agent_update(&self, request: &mut Request) -> IronResult<Response> {
        let mut payload = String::new();
        request.body.read_to_string(&mut payload).unwrap();
        let mut builder: BuilderInfo = json::decode(&payload).unwrap();
        {
            let mut holder = self.builders.lock().unwrap();
            holder.retain(|e| e.id != builder.id);
            builder.timeout = (time::get_time() + Duration::seconds(5)).sec;
            payload = json::encode(&builder).unwrap();
            holder.push(builder);
        }
        Ok(Response::with((status::Ok, payload)))
    }
}

fn main() {
    let daemon = Daemon {
        name: "octobuild_coordinator".to_string()
    };

    daemon.run(move |rx: Receiver<State>| {
        init_logger();

        info!("Coordinator started.");
        let mut web = None;
        for signal in rx.iter() {
            match signal {
                State::Start => {
                    info!("Coordinator: Starting on 3000");
                    let router = service_router!(CoordinatorService::new(),
                        get "/rpc/v1/agent/list" => rpc_agent_list,
                        post "/rpc/v1/agent/update" => rpc_agent_update,
                    );
                    web = Some(Iron::new(router).http("localhost:3000").unwrap());
                    info!("Coordinator: Readly");
                },
                State::Reload => {
                    info!("Coordinator: Reload");
                }
                State::Stop => {
                    info!("Coordinator: Stoping");
                    match web.take() {
                        Some(mut v) => { v.close().unwrap(); }
                        None => {}
                    }
                    info!("Coordinator: Stoped");
                }
            };
        }
        info!("Coordinator shutdowned.");
    }).unwrap();
}

fn init_logger() {
    let log_file = Path::new("octo_coordinator.log").to_path_buf();

    // Create a basic logger configuration
    let logger_config = fern::DispatchConfig {
        format: Box::new(|msg, level, _location| {
            // This format just displays [{level}] {message}
            format!("{} [{}] {}", time::now().rfc3339(), level, msg)
        }),
        // Output to stdout and the log file in the temporary directory we made above to test
        output: vec![fern::OutputConfig::stdout(), fern::OutputConfig::file(&log_file)],
        // Only log messages Info and above
        level: log::LogLevelFilter::Info,
    };

    if let Err(e) = fern::init_global_logger(logger_config, log::LogLevelFilter::Trace) {
        panic!("Failed to initialize global logger: {}", e);
    }
}<|endoftext|>


<commit_before>use executor::*;
use il::*;
use std::rc::Rc;
use translator::mips::*;
use types::Endian;

fn init_driver_block<'d>(
    instruction_bytes: &[u8],
    scalars: Vec<(&str, Expression)>,
    memory: memory::Memory,
    arch: &'d ::translator::Arch
) -> driver::Driver<'d> {
    let mut bytes = vec![0x00, 0x00, 0x00, 0x00];
    bytes.append(&mut instruction_bytes.to_vec());
    bytes.append(&mut vec![0x00, 0x00, 0x00, 0x00]);

    let block_translation_result = Mips::new().translate_block(&bytes, 0).unwrap();
    let control_flow_graph = block_translation_result.control_flow_graph();
    let function = Function::new(0, control_flow_graph.clone());
    let mut program = Program::new();

    program.add_function(function);

    let location = ProgramLocation::new(0, FunctionLocation::EmptyBlock(0));

    let mut engine = engine::Engine::new(memory);
    for scalar in scalars {
        engine.set_scalar(scalar.0, scalar.1);
    }

    driver::Driver::new(Rc::new(program), location, engine, arch)
}

fn init_driver_function<'d>(
    instruction_bytes: &[u8],
    scalars: Vec<(&str, Expression)>,
    mut memory: memory::Memory,
    arch: &'d ::translator::Arch
) -> driver::Driver<'d> {
    for i in 0..instruction_bytes.len() {
        memory.store(i as u64, expr_const(instruction_bytes[i] as u64, 8))
              .unwrap();
    }

    let function = arch.translate_function(&memory, 0).unwrap();
    let mut program = Program::new();

    program.add_function(function);

    let location = ProgramLocation::new(0, FunctionLocation::Instruction(0, 0));

    let mut engine = engine::Engine::new(memory);
    for scalar in scalars {
        engine.set_scalar(scalar.0, scalar.1);
    }

    driver::Driver::new(Rc::new(program), location, engine, arch)
}

#[cfg(test)]
fn get_scalar(
    instruction_bytes: &[u8],
    scalars: Vec<(&str, Expression)>,
    memory: memory::Memory,
    result_scalar: &str
) -> Constant {

    let arch = Mips::new();

    let mut driver = init_driver_block(instruction_bytes, scalars, memory, &arch);
    let num_blocks = driver.program()
                           .function(0)
                           .unwrap()
                           .control_flow_graph()
                           .blocks()
                           .len();

    loop {
        driver = driver.step().unwrap();
        if let Some(index) = driver.location().block_index() {
            if index == num_blocks as u64 - 1 {
                break;
            }
        }
    }

    return driver.engine()
                 .symbolize_and_eval(driver.engine().get_scalar(result_scalar).unwrap())
                 .unwrap();
}

#[cfg(test)]
fn get_raise(
    instruction_bytes: &[u8],
    scalars: Vec<(&str, Expression)>,
    memory: memory::Memory
) -> Option<Expression> {

    let arch = Mips::new();

    let mut driver = init_driver_block(instruction_bytes, scalars, memory, &arch);
    let num_blocks = driver.program()
                           .function(0)
                           .unwrap()
                           .control_flow_graph()
                           .blocks()
                           .len();

    loop {
        driver = driver.step().unwrap();
        let location = driver.location().apply(driver.program()).unwrap();
        if let Some(instruction) = location.instruction() {
            if let Operation::Raise { ref expr } = *instruction.operation() {
                return Some(expr.clone());
            }
        }
        if let Some(index) = driver.location().block_index() {
            if index == num_blocks as u64 - 1 {
                break;
            }
        }
    }

    None
}

#[test]
fn add() {
    // add $a0, $a1, $a2
    let instruction_bytes = &[0x00, 0xa6, 0x20, 0x20];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(1, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 2);

    let result = get_raise(
        instruction_bytes,
        vec![("$a1", expr_const(0x7fffffff, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big)
    ).unwrap();
    if let Expression::Scalar(ref scalar) = result {
        assert_eq!(scalar.name(), "IntegerOverflow");
    }
    else {
        assert!(false);
    }

    let result = get_raise(
        instruction_bytes,
        vec![("$a1", expr_const(0xffffffff, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big)
    ).unwrap();
    if let Expression::Scalar(ref scalar) = result {
        assert_eq!(scalar.name(), "IntegerOverflow");
    }
    else {
        assert!(false);
    }
}

#[test]
fn addi() {
    // addi $a0, $a1, 0x1234
    let instruction_bytes = &[0x20, 0xa4, 0x12, 0x34];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x1235);

    let result = get_raise(
        instruction_bytes,
        vec![("$a1", expr_const(0x7fffffff, 32))],
        memory::Memory::new(Endian::Big)
    ).unwrap();
    if let Expression::Scalar(ref scalar) = result {
        assert_eq!(scalar.name(), "IntegerOverflow");
    }
    else {
        assert!(false);
    }
}

#[test]
fn addiu() {
    // addiu $a0, $a1, 0x1234
    let instruction_bytes = &[0x24, 0xa4, 0x12, 0x34];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x1235);

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0x7fffffff, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x80001233);
}

#[test]
fn addu() {
    // addu $a0, $a1, $a2
    let instruction_bytes = &[0x00, 0xa6, 0x20, 0x21];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(1, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 2);

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0x7fffffff, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x80000000);

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0xffffffff, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0);
}

#[test]
fn and() {
    // and $a0, $a1, $a2
    let instruction_bytes = &[0x00, 0xa6, 0x20, 0x24];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0x8000ffff, 32)),
             ("$a2", expr_const(0x1234, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x1234);
}

#[test]
fn andi() {
    // andi $a0, $a1, 0x1234
    let instruction_bytes = &[0x30, 0xa4, 0x12, 0x34];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0x8000ffff, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x1234);
}

#[test]
fn b() {

    /*
    b target
    ori $a0, $a0, 0
    ori $a0, $a0, 1
    ori $a0, $a0, 1
    target :
    ori $a0, $a0, 2
    jr $ra
    nop
    */
    let instruction_bytes = &[
        0x10, 0x00, 0x00, 0x03,
        0x34, 0x84, 0x00, 0x00,
        0x34, 0x84, 0x00, 0x01,
        0x34, 0x84, 0x00, 0x01,
        0x34, 0x84, 0x00, 0x02,
        0x03, 0xe0, 0x00, 0x08,
        0x00, 0x00, 0x00, 0x00
    ];

    let arch = Mips::new();

    let mut driver = init_driver_function(
        instruction_bytes,
        vec![("$a0", expr_const(0, 32))],
        memory::Memory::new(Endian::Big),
        &arch
    );

    loop {
        driver = driver.step().unwrap();
        if let Some(address) = driver.location()
                                     .apply(driver.program())
                                     .unwrap()
                                     .address() {
            if address == 0x14 {
                assert_eq!(
                    eval(driver.engine()
                               .get_scalar("$a0")
                               .unwrap()).unwrap()
                                         .value(),
                    2
                );
                break;
            }
        }
    }
}

#[test]
fn bal() {

    /*
    ori $a0, $a0, 0
    bal target
    addi $a0, $a0, 0x1234
    nop
    nop
    target :
    jr $ra
    nop
    */
    let instruction_bytes = &[
        0x34, 0x84, 0x00, 0x00,
        0x04, 0x11, 0x00, 0x03,
        0x20, 0x84, 0x12, 0x34,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x03, 0xe0, 0x00, 0x08,
        0x00, 0x00, 0x00, 0x00
    ];

    let arch = Mips::new();

    let mut driver = init_driver_function(
        instruction_bytes,
        vec![("$a0", expr_const(0, 32))],
        memory::Memory::new(Endian::Big),
        &arch
    );

    loop {
        driver = driver.step().unwrap();
        if let Some(address) = driver.location()
                                     .apply(driver.program())
                                     .unwrap()
                                     .address() {
            if address == 0x14 {
                assert_eq!(
                    eval(driver.engine()
                               .get_scalar("$a0")
                               .unwrap()).unwrap()
                                         .value(),
                    0x1234
                );
                assert_eq!(
                    eval(driver.engine()
                               .get_scalar("$ra")
                               .unwrap()).unwrap()
                                         .value(),
                    0xc
                );
                break;
            }
        }
    }
}

#[test]
fn beq() {

    /*
    addiu $a0, $zero, 0x10
    addiu $a1, $zero, 0x10
    beq $a0, $a1, 0x14
    nop
    addi a0, $a0, 0x1234
    jr $ra
    nop
    */
    let instruction_bytes = &[
        0x24, 0x04, 0x00, 0x10,
        0x24, 0x05, 0x00, 0x10,
        0x10, 0x85, 0x00, 0x02,
        0x00, 0x00, 0x00, 0x00,
        0x20, 0x84, 0x12, 0x34,
        0x03, 0xe0, 0x00, 0x08,
        0x00, 0x00, 0x00, 0x00
    ];

    let arch = Mips::new();

    let mut driver = init_driver_function(
        instruction_bytes,
        vec![("$a0", expr_const(0, 32))],
        memory::Memory::new(Endian::Big),
        &arch
    );

    loop {
        driver = driver.step().unwrap();
        if let Some(address) = driver.location()
                                     .apply(driver.program())
                                     .unwrap()
                                     .address() {
            if address == 0x14 {
                assert_eq!(
                    eval(driver.engine()
                               .get_scalar("$a0")
                               .unwrap()).unwrap()
                                         .value(),
                    0x10
                );
                break;
            }
        }
    }

    /*
    addiu $a0, $zero, 0x10
    addiu $a1, $zero, 0x20
    beq $a0, $a1, 0x14
    nop
    addi a0, $a0, 0x1234
    jr $ra
    nop
    */
    let instruction_bytes = &[
        0x24, 0x04, 0x00, 0x10,
        0x24, 0x05, 0x00, 0x20,
        0x10, 0x85, 0x00, 0x02,
        0x00, 0x00, 0x00, 0x00,
        0x20, 0x84, 0x12, 0x34,
        0x03, 0xe0, 0x00, 0x08,
        0x00, 0x00, 0x00, 0x00
    ];

    let arch = Mips::new();

    let mut driver = init_driver_function(
        instruction_bytes,
        vec![("$a0", expr_const(0, 32))],
        memory::Memory::new(Endian::Big),
        &arch
    );

    loop {
        driver = driver.step().unwrap();
        if let Some(address) = driver.location()
                                     .apply(driver.program())
                                     .unwrap()
                                     .address() {
            if address == 0x14 {
                assert_eq!(
                    eval(driver.engine()
                               .get_scalar("$a0")
                               .unwrap()).unwrap()
                                         .value(),
                    0x1244
                );
                break;
            }
        }
    }
}<commit_msg>cleaning up mips branch tests<commit_after>use executor::*;
use il::*;
use std::rc::Rc;
use translator::mips::*;
use types::Endian;

fn init_driver_block<'d>(
    instruction_bytes: &[u8],
    scalars: Vec<(&str, Expression)>,
    memory: memory::Memory,
    arch: &'d ::translator::Arch
) -> driver::Driver<'d> {
    let mut bytes = vec![0x00, 0x00, 0x00, 0x00];
    bytes.append(&mut instruction_bytes.to_vec());
    bytes.append(&mut vec![0x00, 0x00, 0x00, 0x00]);

    let block_translation_result = Mips::new().translate_block(&bytes, 0).unwrap();
    let control_flow_graph = block_translation_result.control_flow_graph();
    let function = Function::new(0, control_flow_graph.clone());
    let mut program = Program::new();

    program.add_function(function);

    let location = ProgramLocation::new(0, FunctionLocation::EmptyBlock(0));

    let mut engine = engine::Engine::new(memory);
    for scalar in scalars {
        engine.set_scalar(scalar.0, scalar.1);
    }

    driver::Driver::new(Rc::new(program), location, engine, arch)
}

fn init_driver_function<'d>(
    instruction_bytes: &[u8],
    scalars: Vec<(&str, Expression)>,
    mut memory: memory::Memory,
    arch: &'d ::translator::Arch
) -> driver::Driver<'d> {
    for i in 0..instruction_bytes.len() {
        memory.store(i as u64, expr_const(instruction_bytes[i] as u64, 8))
              .unwrap();
    }

    let function = arch.translate_function(&memory, 0).unwrap();
    let mut program = Program::new();

    program.add_function(function);

    let location = ProgramLocation::new(0, FunctionLocation::Instruction(0, 0));

    let mut engine = engine::Engine::new(memory);
    for scalar in scalars {
        engine.set_scalar(scalar.0, scalar.1);
    }

    driver::Driver::new(Rc::new(program), location, engine, arch)
}

fn get_scalar(
    instruction_bytes: &[u8],
    scalars: Vec<(&str, Expression)>,
    memory: memory::Memory,
    result_scalar: &str
) -> Constant {

    let arch = Mips::new();

    let mut driver = init_driver_block(instruction_bytes, scalars, memory, &arch);
    let num_blocks = driver.program()
                           .function(0)
                           .unwrap()
                           .control_flow_graph()
                           .blocks()
                           .len();

    loop {
        driver = driver.step().unwrap();
        if let Some(index) = driver.location().block_index() {
            if index == num_blocks as u64 - 1 {
                break;
            }
        }
    }

    return driver.engine()
                 .symbolize_and_eval(driver.engine().get_scalar(result_scalar).unwrap())
                 .unwrap();
}

fn get_raise(
    instruction_bytes: &[u8],
    scalars: Vec<(&str, Expression)>,
    memory: memory::Memory
) -> Option<Expression> {

    let arch = Mips::new();

    let mut driver = init_driver_block(instruction_bytes, scalars, memory, &arch);
    let num_blocks = driver.program()
                           .function(0)
                           .unwrap()
                           .control_flow_graph()
                           .blocks()
                           .len();

    loop {
        driver = driver.step().unwrap();
        let location = driver.location().apply(driver.program()).unwrap();
        if let Some(instruction) = location.instruction() {
            if let Operation::Raise { ref expr } = *instruction.operation() {
                return Some(expr.clone());
            }
        }
        if let Some(index) = driver.location().block_index() {
            if index == num_blocks as u64 - 1 {
                break;
            }
        }
    }

    None
}

fn step_to<'d>(mut driver: driver::Driver<'d>, target_address: u64)
-> driver::Driver<'d> {

    loop {
        driver = driver.step().unwrap();
        if let Some(address) = driver.location()
                                     .apply(driver.program())
                                     .unwrap()
                                     .address() {
            if address == target_address {
                return driver;
            }
        }
    }
}

#[test]
fn add() {
    // add $a0, $a1, $a2
    let instruction_bytes = &[0x00, 0xa6, 0x20, 0x20];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(1, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 2);

    let result = get_raise(
        instruction_bytes,
        vec![("$a1", expr_const(0x7fffffff, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big)
    ).unwrap();
    if let Expression::Scalar(ref scalar) = result {
        assert_eq!(scalar.name(), "IntegerOverflow");
    }
    else {
        panic!("Did not hit overflow");
    }

    let result = get_raise(
        instruction_bytes,
        vec![("$a1", expr_const(0xffffffff, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big)
    ).unwrap();
    if let Expression::Scalar(ref scalar) = result {
        assert_eq!(scalar.name(), "IntegerOverflow");
    }
    else {
        panic!("Did not hit overflow");
    }
}

#[test]
fn addi() {
    // addi $a0, $a1, 0x1234
    let instruction_bytes = &[0x20, 0xa4, 0x12, 0x34];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x1235);

    let result = get_raise(
        instruction_bytes,
        vec![("$a1", expr_const(0x7fffffff, 32))],
        memory::Memory::new(Endian::Big)
    ).unwrap();
    if let Expression::Scalar(ref scalar) = result {
        assert_eq!(scalar.name(), "IntegerOverflow");
    }
    else {
        panic!("Did not hit overflow");
    }
}

#[test]
fn addiu() {
    // addiu $a0, $a1, 0x1234
    let instruction_bytes = &[0x24, 0xa4, 0x12, 0x34];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x1235);

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0x7fffffff, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x80001233);
}

#[test]
fn addu() {
    // addu $a0, $a1, $a2
    let instruction_bytes = &[0x00, 0xa6, 0x20, 0x21];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(1, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 2);

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0x7fffffff, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x80000000);

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0xffffffff, 32)),
             ("$a2", expr_const(1, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0);
}

#[test]
fn and() {
    // and $a0, $a1, $a2
    let instruction_bytes = &[0x00, 0xa6, 0x20, 0x24];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0x8000ffff, 32)),
             ("$a2", expr_const(0x1234, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x1234);
}

#[test]
fn andi() {
    // andi $a0, $a1, 0x1234
    let instruction_bytes = &[0x30, 0xa4, 0x12, 0x34];

    let result = get_scalar(
        instruction_bytes,
        vec![("$a1", expr_const(0x8000ffff, 32))],
        memory::Memory::new(Endian::Big),
        "$a0"
    );
    assert_eq!(result.value(), 0x1234);
}

#[test]
fn b() {

    /*
    b target
    ori $a0, $a0, 0
    ori $a0, $a0, 1
    ori $a0, $a0, 1
    target :
    ori $a0, $a0, 2
    jr $ra
    nop
    */
    let instruction_bytes = &[
        0x10, 0x00, 0x00, 0x03,
        0x34, 0x84, 0x00, 0x00,
        0x34, 0x84, 0x00, 0x01,
        0x34, 0x84, 0x00, 0x01,
        0x34, 0x84, 0x00, 0x02,
        0x03, 0xe0, 0x00, 0x08,
        0x00, 0x00, 0x00, 0x00
    ];

    let arch = Mips::new();

    let driver = init_driver_function(
        instruction_bytes,
        vec![("$a0", expr_const(0, 32))],
        memory::Memory::new(Endian::Big),
        &arch
    );

    let driver = step_to(driver, 0x14);

    assert_eq!(
        eval(driver.engine().get_scalar("$a0").unwrap()).unwrap().value(),
        0x2
    );
}

#[test]
fn bal() {

    /*
    ori $a0, $a0, 0
    bal target
    addi $a0, $a0, 0x1234
    nop
    nop
    target :
    jr $ra
    nop
    */
    let instruction_bytes = &[
        0x34, 0x84, 0x00, 0x00,
        0x04, 0x11, 0x00, 0x03,
        0x20, 0x84, 0x12, 0x34,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x03, 0xe0, 0x00, 0x08,
        0x00, 0x00, 0x00, 0x00
    ];

    let arch = Mips::new();

    let driver = init_driver_function(
        instruction_bytes,
        vec![("$a0", expr_const(0, 32))],
        memory::Memory::new(Endian::Big),
        &arch
    );

    let driver = step_to(driver, 0x14);

    assert_eq!(
        eval(driver.engine().get_scalar("$a0").unwrap()).unwrap().value(),
        0x1234
    );

    assert_eq!(
        eval(driver.engine().get_scalar("$ra").unwrap()).unwrap().value(),
        0xc
    );
}

#[test]
fn beq() {

    /*
    addiu $a0, $zero, 0x10
    addiu $a1, $zero, 0x10
    beq $a0, $a1, 0x14
    nop
    addi a0, $a0, 0x1234
    jr $ra
    nop
    */
    let instruction_bytes = &[
        0x24, 0x04, 0x00, 0x10,
        0x24, 0x05, 0x00, 0x10,
        0x10, 0x85, 0x00, 0x02,
        0x00, 0x00, 0x00, 0x00,
        0x20, 0x84, 0x12, 0x34,
        0x03, 0xe0, 0x00, 0x08,
        0x00, 0x00, 0x00, 0x00
    ];

    let arch = Mips::new();

    let driver = init_driver_function(
        instruction_bytes,
        vec![("$a0", expr_const(0, 32))],
        memory::Memory::new(Endian::Big),
        &arch
    );

    let driver = step_to(driver, 0x14);

    assert_eq!(
        eval(driver.engine().get_scalar("$a0").unwrap()).unwrap().value(),
        0x10
    );

    /*
    addiu $a0, $zero, 0x10
    addiu $a1, $zero, 0x20
    beq $a0, $a1, 0x14
    nop
    addi a0, $a0, 0x1234
    jr $ra
    nop
    */
    let instruction_bytes = &[
        0x24, 0x04, 0x00, 0x10,
        0x24, 0x05, 0x00, 0x20,
        0x10, 0x85, 0x00, 0x02,
        0x00, 0x00, 0x00, 0x00,
        0x20, 0x84, 0x12, 0x34,
        0x03, 0xe0, 0x00, 0x08,
        0x00, 0x00, 0x00, 0x00
    ];

    let arch = Mips::new();

    let driver = init_driver_function(
        instruction_bytes,
        vec![("$a0", expr_const(0, 32))],
        memory::Memory::new(Endian::Big),
        &arch
    );

    let driver = step_to(driver, 0x14);

    assert_eq!(
        eval(driver.engine().get_scalar("$a0").unwrap()).unwrap().value(),
        0x1244
    );
}<|endoftext|>


<commit_before>#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
struct U128 {
    hi: u64,
    lo: u64,
}

fn modulo(mut a: U128, m: u64) -> u64 {
    if a.hi >= m {
        a.hi -= (a.hi / m) * m;
    }
    let mut x = a.hi;
    let mut y = a.lo;
    for _ in 0..64 {
        let t = (x as i64 >> 63) as u64;
        x = (x << 1) | (y >> 63);
        y <<= 1;
        if (x | t) >= m {
            x = x.wrapping_sub(m);
            y += 1;
        }
    }
    x
}
fn mul128(u: u64, v: u64) -> U128 {
    let u1 = u >> 32;
    let u0 = u & (!0 >> 32);
    let v1 = v >> 32;
    let v0 = v & (!0 >> 32);

    let t = u0 * v0;
    let w0 = t & (!0 >> 32);
    let k = t >> 32;

    let t = u1 * v0 + k;
    let w1 = t & (!0 >> 32);
    let w2 = t >> 32;

    let t = u0 * v1 + w1;
    let k = t >> 32;
    U128 {
        lo: (t << 32) + w0,
        hi: u1*v1 + w2 + k
    }
}
fn mod_mul_(a: u64, b: u64, m: u64) -> u64 {
    modulo(mul128(a, b), m)
}

fn mod_mul(a: u64, b: u64, m: u64) -> u64 {
    match a.checked_mul(b) {
        Some(r) => if r >= m { r % m } else { r },
        None => mod_mul_(a, b, m),
    }
}

fn mod_sqr(a: u64, m: u64) -> u64 {
    if a < (1 << 32) {
        let r = a * a;
        if r >= m {
            r % m
        } else {
            r
        }
    } else {
        mod_mul_(a, a, m)
    }
}

fn mod_exp(mut x: u64, mut d: u64, n: u64) -> u64 {
    let mut ret: u64 = 1;
    while d != 0 {
        if d % 2 == 1 {
            ret = mod_mul(ret, x, n)
        }
        d /= 2;
        x = mod_sqr(x, n);
    }
    ret
}

/// Test if `n` is prime, using the deterministic version of the
/// Miller-Rabin test.
///
/// Doing a lot of primality tests with numbers strictly below some
/// upper bound will be faster using the `is_prime` method of a
/// `Sieve` instance.
///
/// # Examples
///
/// ```rust
/// assert_eq!(primal::is_prime(1), false);
/// assert_eq!(primal::is_prime(2), true);
/// assert_eq!(primal::is_prime(3), true);
/// assert_eq!(primal::is_prime(4), false);
/// assert_eq!(primal::is_prime(5), true);
///
/// assert_eq!(primal::is_prime(22_801_763_487), false);
/// assert_eq!(primal::is_prime(22_801_763_489), true);
/// assert_eq!(primal::is_prime(22_801_763_491), false);
/// ```
pub fn miller_rabin(n: u64) -> bool {
    const HINT: &[u64] = &[2];

    // we have a strict upper bound, so we can just use the witness
    // table of Pomerance, Selfridge & Wagstaff and Jeaschke to be as
    // efficient as possible, without having to fall back to
    // randomness.
    const WITNESSES: &[(u64, &[u64])] =
        &[(2_046, HINT),
          (1_373_652, &[2, 3]),
          (9_080_190, &[31, 73]),
          (25_326_000, &[2, 3, 5]),
          (4_759_123_140, &[2, 7, 61]),
          (1_112_004_669_632, &[2, 13, 23, 1662803]),
          (2_152_302_898_746, &[2, 3, 5, 7, 11]),
          (3_474_749_660_382, &[2, 3, 5, 7, 11, 13]),
          (341_550_071_728_320, &[2, 3, 5, 7, 11, 13, 17]),
          (0xFFFF_FFFF_FFFF_FFFF, &[2, 3, 5, 7, 11, 13, 17, 19, 23])
         ];

    if n % 2 == 0 { return n == 2 }
    if n == 1 { return false }

    let mut d = n - 1;
    let mut s = 0;
    while d % 2 == 0 { d /= 2; s += 1 }

    let witnesses =
        WITNESSES.iter().find(|&&(hi, _)| hi >= n)
            .map(|&(_, wtnss)| wtnss).unwrap();
    'next_witness: for &a in witnesses.iter() {
        let mut power = mod_exp(a, d, n);
        assert!(power < n);
        if power == 1 || power == n - 1 { continue 'next_witness }

        for _r in 0..s {
            power = mod_sqr(power, n);
            assert!(power < n);
            if power == 1 { return false }
            if power == n - 1 {
                continue 'next_witness
            }
        }
        return false
    }

    true
}

#[cfg(test)]
mod tests {
    use primal::Sieve;

    #[test]
    fn modulo() {
        for i in 0..64 {
            let x = 1 << i;
            for j in 0..10 {
                let m = 11 + j * 2;
                assert_eq!(super::modulo(super::U128 { lo: x, hi: 0}, m), x % m);
            }
        }

        let x = 1 << 63;
        assert_eq!(super::modulo(super::U128 { lo: 0, hi: x}, x + 1), 2);
        assert_eq!(super::modulo(super::U128 { lo: 0, hi: x}, x + 3), 18);
        assert_eq!(super::modulo(super::U128 { lo: 0, hi: x}, x + 5), 50);
    }

    #[test]
    fn mul() {
        for i in 1..64 {
            for j in 1..64 {
                let res = super::mul128((1 << i) + 1, (1 << j) + 1);
                let shift = i + j;
                let high_twiddle = i == 63 && j == 63;
                let mut real = if shift >= 64 {
                    super::U128 { lo: 0, hi: (1 << (shift - 64)) + high_twiddle as u64 }
                } else {
                    super::U128 { lo: 1 << shift, hi: 0 }
                };
                real.lo += if high_twiddle { 0 } else { (1 << i) + (1 << j) } + 1;
                assert!(res == real,
                        "(2**{} + 1)*(2**{} + 1): {:?} should be {:?}",
                        i, j, res, real);
            }
        }
    }
    #[test]
    fn mod_mul() {
        assert_eq!(super::mod_mul(1 << 63, 1 << 32, 3), 2);
        assert_eq!(super::mod_mul(1 << 31, 1 << 31, (1 << 32) - 7), 3221225479);
        assert_eq!(super::mod_mul(1 << 32, 1 << 32, (1 << 32) - 7), 49);
        assert_eq!(super::mod_mul(1 << 32, 1 << 32, (1 << 32) + 7), 49);
        assert_eq!(super::mod_mul(1 << 63, 1 << 32, (1 << 32) + 7), 2_147_483_480);
        assert_eq!(super::mod_mul(1 << 63, 1 << 32, (1 << 63) + 7), 9_223_372_006_790_004_743);
        assert_eq!(super::mod_mul(1 << 32, 1 << 32, !0), 1);
    }

    #[test]
    fn miller_rabin() {
        const LIMIT: usize = 1_000_000;
        let sieve = Sieve::new(LIMIT);
        for x in 0..LIMIT {
            let s = sieve.is_prime(x);
            let mr = super::miller_rabin(x as u64);

            assert!(s == mr, "miller_rabin {} mismatches sieve {} for {}",
                    mr, s, x)
        }
    }
    #[test]
    fn miller_rabin_large() {
        let tests = &[
            (4_294_967_311, true),
            (4_294_967_291, true),
            (4_294_967_291 * 4_294_967_291, false),
            (!0, false),
            ];
        for &(n, is_prime) in tests {
            assert!(super::miller_rabin(n) == is_prime,
                    "mismatch for {} (should be {})", n, is_prime);
        }
    }
}
<commit_msg>primal-check: use the primitive u128 type<commit_after>fn mod_mul_(a: u64, b: u64, m: u64) -> u64 {
    (u128::from(a) * u128::from(b) % u128::from(m)) as u64
}

fn mod_mul(a: u64, b: u64, m: u64) -> u64 {
    match a.checked_mul(b) {
        Some(r) => if r >= m { r % m } else { r },
        None => mod_mul_(a, b, m),
    }
}

fn mod_sqr(a: u64, m: u64) -> u64 {
    if a < (1 << 32) {
        let r = a * a;
        if r >= m {
            r % m
        } else {
            r
        }
    } else {
        mod_mul_(a, a, m)
    }
}

fn mod_exp(mut x: u64, mut d: u64, n: u64) -> u64 {
    let mut ret: u64 = 1;
    while d != 0 {
        if d % 2 == 1 {
            ret = mod_mul(ret, x, n)
        }
        d /= 2;
        x = mod_sqr(x, n);
    }
    ret
}

/// Test if `n` is prime, using the deterministic version of the
/// Miller-Rabin test.
///
/// Doing a lot of primality tests with numbers strictly below some
/// upper bound will be faster using the `is_prime` method of a
/// `Sieve` instance.
///
/// # Examples
///
/// ```rust
/// assert_eq!(primal::is_prime(1), false);
/// assert_eq!(primal::is_prime(2), true);
/// assert_eq!(primal::is_prime(3), true);
/// assert_eq!(primal::is_prime(4), false);
/// assert_eq!(primal::is_prime(5), true);
///
/// assert_eq!(primal::is_prime(22_801_763_487), false);
/// assert_eq!(primal::is_prime(22_801_763_489), true);
/// assert_eq!(primal::is_prime(22_801_763_491), false);
/// ```
pub fn miller_rabin(n: u64) -> bool {
    const HINT: &[u64] = &[2];

    // we have a strict upper bound, so we can just use the witness
    // table of Pomerance, Selfridge & Wagstaff and Jeaschke to be as
    // efficient as possible, without having to fall back to
    // randomness.
    const WITNESSES: &[(u64, &[u64])] =
        &[(2_046, HINT),
          (1_373_652, &[2, 3]),
          (9_080_190, &[31, 73]),
          (25_326_000, &[2, 3, 5]),
          (4_759_123_140, &[2, 7, 61]),
          (1_112_004_669_632, &[2, 13, 23, 1662803]),
          (2_152_302_898_746, &[2, 3, 5, 7, 11]),
          (3_474_749_660_382, &[2, 3, 5, 7, 11, 13]),
          (341_550_071_728_320, &[2, 3, 5, 7, 11, 13, 17]),
          (0xFFFF_FFFF_FFFF_FFFF, &[2, 3, 5, 7, 11, 13, 17, 19, 23])
         ];

    if n % 2 == 0 { return n == 2 }
    if n == 1 { return false }

    let mut d = n - 1;
    let mut s = 0;
    while d % 2 == 0 { d /= 2; s += 1 }

    let witnesses =
        WITNESSES.iter().find(|&&(hi, _)| hi >= n)
            .map(|&(_, wtnss)| wtnss).unwrap();
    'next_witness: for &a in witnesses.iter() {
        let mut power = mod_exp(a, d, n);
        assert!(power < n);
        if power == 1 || power == n - 1 { continue 'next_witness }

        for _r in 0..s {
            power = mod_sqr(power, n);
            assert!(power < n);
            if power == 1 { return false }
            if power == n - 1 {
                continue 'next_witness
            }
        }
        return false
    }

    true
}

#[cfg(test)]
mod tests {
    use primal::Sieve;

    #[test]
    fn mod_mul() {
        assert_eq!(super::mod_mul(1 << 63, 1 << 32, 3), 2);
        assert_eq!(super::mod_mul(1 << 31, 1 << 31, (1 << 32) - 7), 3221225479);
        assert_eq!(super::mod_mul(1 << 32, 1 << 32, (1 << 32) - 7), 49);
        assert_eq!(super::mod_mul(1 << 32, 1 << 32, (1 << 32) + 7), 49);
        assert_eq!(super::mod_mul(1 << 63, 1 << 32, (1 << 32) + 7), 2_147_483_480);
        assert_eq!(super::mod_mul(1 << 63, 1 << 32, (1 << 63) + 7), 9_223_372_006_790_004_743);
        assert_eq!(super::mod_mul(1 << 32, 1 << 32, !0), 1);
    }

    #[test]
    fn miller_rabin() {
        const LIMIT: usize = 1_000_000;
        let sieve = Sieve::new(LIMIT);
        for x in 0..LIMIT {
            let s = sieve.is_prime(x);
            let mr = super::miller_rabin(x as u64);

            assert!(s == mr, "miller_rabin {} mismatches sieve {} for {}",
                    mr, s, x)
        }
    }
    #[test]
    fn miller_rabin_large() {
        let tests = &[
            (4_294_967_311, true),
            (4_294_967_291, true),
            (4_294_967_291 * 4_294_967_291, false),
            (!0, false),
            ];
        for &(n, is_prime) in tests {
            assert!(super::miller_rabin(n) == is_prime,
                    "mismatch for {} (should be {})", n, is_prime);
        }
    }
}
<|endoftext|>


<commit_before>pub mod command;
pub mod cmd_helper;
pub mod fs_helper;
<commit_msg>Fix "file not found" error<commit_after>pub mod cmd_helper;
pub mod fs_helper;
<|endoftext|>


<commit_before>use std::iter::FromIterator;
use std::collections::BTreeMap;

use super::parser::{Token, Register};

type AbsoluteIndex = usize;

#[derive(Debug, Copy, Clone)]
enum Instruction {
    Inbox,
    Outbox,
    CopyFrom(Register),
    CopyTo(Register),
    BumpUp(Register),
    BumpDown(Register),
    Add(Register),
    Sub(Register),
    Jump(AbsoluteIndex),
    JumpIfZero(AbsoluteIndex),
    JumpIfNegative(AbsoluteIndex),
    NoOp,
}

#[derive(Debug, Clone)]
pub struct Program(Vec<Instruction>);

impl<'a> FromIterator<Token<'a>> for Program {
    fn from_iter<T>(iterator: T) -> Self
        where T: IntoIterator<Item = Token<'a>>
    {
        // Remove values that don't change the behavior
        let without_junk: Vec<_> = iterator.into_iter().filter(|t| match *t {
            Token::Header |
            Token::Comment(..) |
            Token::CommentDefinition(..) |
            Token::Whitespace(..) => false,
            _ => true,
        }).collect();

        // Find all the indexes of the labels
        let label_mapping = {
            let mut map = BTreeMap::new();

            for (i, t) in without_junk.iter().enumerate() {
                if let Token::LabelDefinition(id) = *t {
                    map.insert(id, i);
                }
            }

            map
        };

        let unmap = |id| *label_mapping.get(id).expect("Label is not defined");

        // Make the instructions, resolving jump locations
        let i = without_junk.into_iter().map(|t| match t {
            Token::Inbox => Instruction::Inbox,
            Token::Outbox => Instruction::Outbox,
            Token::CopyFrom(r) => Instruction::CopyFrom(r),
            Token::CopyTo(r) => Instruction::CopyTo(r),
            Token::BumpUp(r) => Instruction::BumpUp(r),
            Token::BumpDown(r) => Instruction::BumpDown(r),
            Token::Add(r) => Instruction::Add(r),
            Token::Sub(r) => Instruction::Sub(r),
            Token::LabelDefinition(..) => Instruction::NoOp,
            Token::Jump(id) => Instruction::Jump(unmap(id)),
            Token::JumpIfZero(id) => Instruction::JumpIfZero(unmap(id)),
            Token::JumpIfNegative(id) => Instruction::JumpIfNegative(unmap(id)),
            _ => unreachable!(),
        });

        Program(i.collect())
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Tile {
    Number(i8), // what is the actual size here?
    Letter(char),
}

#[derive(Debug, Clone)]
pub enum StepError {
    EndOfProgram,
    Other(String),
}

impl StepError {
    fn e(s: &str) -> StepError {
        StepError::Other(s.into())
    }
}

pub type Input = Vec<Tile>;
pub type Output = Vec<Tile>;
pub type Registers = BTreeMap<u8, Tile>;

pub struct Machine {
    program: Program,
    input: Input,
    output: Output,
    pc: usize,
    accumulator: Option<Tile>,
    registers: Registers,
}

impl Machine {
    pub fn new(program: Program, mut input: Input, registers: Registers) -> Machine {
        // We want to pop off the front, so flip it around for efficiency.
        input.reverse();

        Machine {
            program: program,
            input: input,
            output: Vec::new(),
            pc: 0,
            accumulator: None,
            registers: registers,
        }
    }

    fn deref_target(&self, r: Register) -> Result<u8, StepError> {
        match r {
            Register::Direct(r) => Ok(r),
            Register::Indirect(r) => match self.registers.get(&r) {
                None => Err(StepError::e("indirect through nil!")),
                Some(&Tile::Number(v)) if v < 0 => Err(StepError::e("indirect to negative!")),
                Some(&Tile::Number(v)) => Ok(v as u8),
                Some(&Tile::Letter(..)) => Err(StepError::e("indirect through letter")),
            },
        }
    }

    pub fn into_output(self) -> Output { self.output }

    pub fn step(&mut self) -> Result<(), StepError> {
        use self::Instruction::*;

        // println!("PC: {}", self.pc);
        // println!("Instr: {:?}", self.program.0[self.pc]);
        // println!("Acc: {:?}", self.accumulator);

        match self.program.0[self.pc] {
            Inbox => {
                match self.input.pop() {
                    Some(v) => self.accumulator = Some(v),
                    None => return Err(StepError::EndOfProgram),
                }
            },
            Outbox => {
                match self.accumulator {
                    Some(v) => self.output.push(v),
                    None => return Err(StepError::e("Can't output with nothing!")),
                }
            },
            CopyFrom(r) => {
                let r = try!(self.deref_target(r));
                let v = try!(self.registers.get(&r).ok_or(StepError::e("copy from nil")));
                self.accumulator = Some(*v);
            },
            CopyTo(r) => {
                match self.accumulator {
                    Some(v) => {
                        let r = try!(self.deref_target(r));
                        self.registers.insert(r, v);
                    },
                    None => return Err(StepError::e("nothing to copy to the tile")),
                }
            },
            BumpUp(r) => {
                let r = try!(self.deref_target(r));
                let v = match self.registers.get_mut(&r) {
                    None => return Err(StepError::e("can't bump nil")),
                    Some(&mut Tile::Number(ref mut v)) => {
                        *v = *v + 1;
                        *v
                    },
                    Some(&mut Tile::Letter(..)) => return Err(StepError::e("can't bump a letter"))
                };
                self.accumulator = Some(Tile::Number(v))
            },
            BumpDown(r) => {
                let r = try!(self.deref_target(r));
                let v = match self.registers.get_mut(&r) {
                    None => return Err(StepError::e("can't bump nil")),
                    Some(&mut Tile::Number(ref mut v)) => {
                        *v = *v - 1;
                        *v
                    },
                    Some(&mut Tile::Letter(..)) => return Err(StepError::e("can't bump a letter"))
                };
                self.accumulator = Some(Tile::Number(v))
            },
            Add(r) => {
                let r = try!(self.deref_target(r));
                let v = match (self.accumulator, self.registers.get(&r)) {
                    (None, _) => return Err(StepError::e("Cannot add with nil in hand")),
                    (_, None) => return Err(StepError::e("Cannot add to nil")),
                    (Some(Tile::Number(a)), Some(&Tile::Number(v))) => a + v,
                    _ => return Err(StepError::e("Cannot add with letters")),
                };
                self.accumulator = Some(Tile::Number(v));
            },
            Sub(r) => {
                let r = try!(self.deref_target(r));
                let v = match (self.accumulator, self.registers.get(&r)) {
                    (None, _) => return Err(StepError::e("Cannot sub with nil in hand")),
                    (_, None) => return Err(StepError::e("can't sub to nil")),
                    (Some(Tile::Number(a)), Some(&Tile::Number(v))) => a - v,
                    (Some(Tile::Letter(a)), Some(&Tile::Letter(v))) => a as i8 - v as i8,
                    _ => return Err(StepError::e("Cannot sub a letter and number")),
                };
                self.accumulator = Some(Tile::Number(v))
            },
            Jump(i) => {
                self.pc = i;
                return Ok(());
            },
            JumpIfZero(i) => {
                match self.accumulator {
                    None => return Err(StepError::e("cannot jump zero with nil in hand")),
                    Some(v) => match v {
                        Tile::Number(v) if v == 0 => {
                            self.pc = i;
                            return Ok(());
                        }
                        Tile::Number(..) |
                        Tile::Letter(..) => {}, // noop
                    }
                }
            },
            JumpIfNegative(i) => {
                match self.accumulator {
                    None => return Err(StepError::e("cannot jump neg with nil in hand")),
                    Some(v) => match v {
                        Tile::Number(v) if v < 0 => {
                            self.pc = i;
                            return Ok(());
                        }
                        Tile::Number(..) |
                        Tile::Letter(..) => {}, // noop
                    }
                }
            },
            NoOp => {},
        }

        self.pc += 1;

        if self.pc >= self.program.0.len() {
            Err(StepError::EndOfProgram)
        } else {
            Ok(())
        }
    }

    pub fn run(&mut self) -> Result<(), StepError> {
        loop {
            match self.step() {
                Ok(..) => continue,
                Err(StepError::EndOfProgram) => return Ok(()),
                Err(e) => return Err(e),
            }
        }
    }
}
<commit_msg>Replace string-based runtime errors<commit_after>use std::iter::FromIterator;
use std::collections::BTreeMap;

use super::parser::{Token, Register};

type AbsoluteIndex = usize;

#[derive(Debug, Copy, Clone)]
enum Instruction {
    Inbox,
    Outbox,
    CopyFrom(Register),
    CopyTo(Register),
    BumpUp(Register),
    BumpDown(Register),
    Add(Register),
    Sub(Register),
    Jump(AbsoluteIndex),
    JumpIfZero(AbsoluteIndex),
    JumpIfNegative(AbsoluteIndex),
    NoOp,
}

#[derive(Debug, Clone)]
pub struct Program(Vec<Instruction>);

impl<'a> FromIterator<Token<'a>> for Program {
    fn from_iter<T>(iterator: T) -> Self
        where T: IntoIterator<Item = Token<'a>>
    {
        // Remove values that don't change the behavior
        let without_junk: Vec<_> = iterator.into_iter().filter(|t| match *t {
            Token::Header |
            Token::Comment(..) |
            Token::CommentDefinition(..) |
            Token::Whitespace(..) => false,
            _ => true,
        }).collect();

        // Find all the indexes of the labels
        let label_mapping = {
            let mut map = BTreeMap::new();

            for (i, t) in without_junk.iter().enumerate() {
                if let Token::LabelDefinition(id) = *t {
                    map.insert(id, i);
                }
            }

            map
        };

        let unmap = |id| *label_mapping.get(id).expect("Label is not defined");

        // Make the instructions, resolving jump locations
        let i = without_junk.into_iter().map(|t| match t {
            Token::Inbox => Instruction::Inbox,
            Token::Outbox => Instruction::Outbox,
            Token::CopyFrom(r) => Instruction::CopyFrom(r),
            Token::CopyTo(r) => Instruction::CopyTo(r),
            Token::BumpUp(r) => Instruction::BumpUp(r),
            Token::BumpDown(r) => Instruction::BumpDown(r),
            Token::Add(r) => Instruction::Add(r),
            Token::Sub(r) => Instruction::Sub(r),
            Token::LabelDefinition(..) => Instruction::NoOp,
            Token::Jump(id) => Instruction::Jump(unmap(id)),
            Token::JumpIfZero(id) => Instruction::JumpIfZero(unmap(id)),
            Token::JumpIfNegative(id) => Instruction::JumpIfNegative(unmap(id)),
            _ => unreachable!(),
        });

        Program(i.collect())
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Tile {
    Number(i8), // what is the actual size here?
    Letter(char),
}

#[derive(Debug, Copy, Clone)]
pub enum StepError {
    EndOfProgram,
    IndirectThroughNil,
    IndirectThroughNegative,
    IndirectThroughLetter,
    OutputNil,
    CopyFromNil,
    CopyToNil,
    BumpNil,
    BumpLetter,
    AddWithNil,
    AddToNil,
    AddWithLetter,
    SubFromNil,
    SubWithNil,
    SubCrossTypes,
    JumpZeroNil,
    JumpNegativeNil,
}

pub type Input = Vec<Tile>;
pub type Output = Vec<Tile>;
pub type Registers = BTreeMap<u8, Tile>;

pub struct Machine {
    program: Program,
    input: Input,
    output: Output,
    pc: usize,
    accumulator: Option<Tile>,
    registers: Registers,
}

impl Machine {
    pub fn new(program: Program, mut input: Input, registers: Registers) -> Machine {
        // We want to pop off the front, so flip it around for efficiency.
        input.reverse();

        Machine {
            program: program,
            input: input,
            output: Vec::new(),
            pc: 0,
            accumulator: None,
            registers: registers,
        }
    }

    fn deref_target(&self, r: Register) -> Result<u8, StepError> {
        match r {
            Register::Direct(r) => Ok(r),
            Register::Indirect(r) => match self.registers.get(&r) {
                None => Err(StepError::IndirectThroughNil),
                Some(&Tile::Number(v)) if v < 0 => Err(StepError::IndirectThroughNegative),
                Some(&Tile::Number(v)) => Ok(v as u8),
                Some(&Tile::Letter(..)) => Err(StepError::IndirectThroughLetter),
            },
        }
    }

    pub fn into_output(self) -> Output { self.output }

    pub fn step(&mut self) -> Result<(), StepError> {
        use self::Instruction::*;

        // println!("PC: {}", self.pc);
        // println!("Instr: {:?}", self.program.0[self.pc]);
        // println!("Acc: {:?}", self.accumulator);

        match self.program.0[self.pc] {
            Inbox => {
                match self.input.pop() {
                    Some(v) => self.accumulator = Some(v),
                    None => return Err(StepError::EndOfProgram),
                }
            },
            Outbox => {
                match self.accumulator {
                    Some(v) => self.output.push(v),
                    None => return Err(StepError::OutputNil),
                }
            },
            CopyFrom(r) => {
                let r = try!(self.deref_target(r));
                let v = try!(self.registers.get(&r).ok_or(StepError::CopyFromNil));
                self.accumulator = Some(*v);
            },
            CopyTo(r) => {
                match self.accumulator {
                    Some(v) => {
                        let r = try!(self.deref_target(r));
                        self.registers.insert(r, v);
                    },
                    None => return Err(StepError::CopyToNil),
                }
            },
            BumpUp(r) => {
                let r = try!(self.deref_target(r));
                let v = match self.registers.get_mut(&r) {
                    None => return Err(StepError::BumpNil),
                    Some(&mut Tile::Number(ref mut v)) => {
                        *v = *v + 1;
                        *v
                    },
                    Some(&mut Tile::Letter(..)) => return Err(StepError::BumpLetter)
                };
                self.accumulator = Some(Tile::Number(v))
            },
            BumpDown(r) => {
                let r = try!(self.deref_target(r));
                let v = match self.registers.get_mut(&r) {
                    None => return Err(StepError::BumpNil),
                    Some(&mut Tile::Number(ref mut v)) => {
                        *v = *v - 1;
                        *v
                    },
                    Some(&mut Tile::Letter(..)) => return Err(StepError::BumpLetter)
                };
                self.accumulator = Some(Tile::Number(v))
            },
            Add(r) => {
                let r = try!(self.deref_target(r));
                let v = match (self.accumulator, self.registers.get(&r)) {
                    (None, _) => return Err(StepError::AddToNil),
                    (_, None) => return Err(StepError::AddWithNil),
                    (Some(Tile::Number(a)), Some(&Tile::Number(v))) => a + v,
                    _ => return Err(StepError::AddWithLetter),
                };
                self.accumulator = Some(Tile::Number(v));
            },
            Sub(r) => {
                let r = try!(self.deref_target(r));
                let v = match (self.accumulator, self.registers.get(&r)) {
                    (None, _) => return Err(StepError::SubFromNil),
                    (_, None) => return Err(StepError::SubWithNil),
                    (Some(Tile::Number(a)), Some(&Tile::Number(v))) => a - v,
                    (Some(Tile::Letter(a)), Some(&Tile::Letter(v))) => a as i8 - v as i8,
                    _ => return Err(StepError::SubCrossTypes),
                };
                self.accumulator = Some(Tile::Number(v))
            },
            Jump(i) => {
                self.pc = i;
                return Ok(());
            },
            JumpIfZero(i) => {
                match self.accumulator {
                    None => return Err(StepError::JumpZeroNil),
                    Some(v) => match v {
                        Tile::Number(v) if v == 0 => {
                            self.pc = i;
                            return Ok(());
                        }
                        Tile::Number(..) |
                        Tile::Letter(..) => {}, // noop
                    }
                }
            },
            JumpIfNegative(i) => {
                match self.accumulator {
                    None => return Err(StepError::JumpNegativeNil),
                    Some(v) => match v {
                        Tile::Number(v) if v < 0 => {
                            self.pc = i;
                            return Ok(());
                        }
                        Tile::Number(..) |
                        Tile::Letter(..) => {}, // noop
                    }
                }
            },
            NoOp => {},
        }

        self.pc += 1;

        if self.pc >= self.program.0.len() {
            Err(StepError::EndOfProgram)
        } else {
            Ok(())
        }
    }

    pub fn run(&mut self) -> Result<(), StepError> {
        loop {
            match self.step() {
                Ok(..) => continue,
                Err(StepError::EndOfProgram) => return Ok(()),
                Err(e) => return Err(e),
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Functions for creating and modifying messages to send across the message bus.
use std::ops::DerefMut;

use dbus_serialize::types::{Path,Variant,Value,BasicValue,Signature};

use marshal::{Marshal,pad_to_multiple};
use demarshal::{demarshal,DemarshalError};

#[derive(Debug,Default,PartialEq)]
pub struct MessageType(pub u8);
pub const MESSAGE_TYPE_INVALID : MessageType        = MessageType(0);
pub const MESSAGE_TYPE_METHOD_CALL : MessageType    = MessageType(1);
pub const MESSAGE_TYPE_METHOD_RETURN : MessageType  = MessageType(2);
pub const MESSAGE_TYPE_ERROR : MessageType          = MessageType(3);
pub const MESSAGE_TYPE_SIGNAL : MessageType         = MessageType(4);

pub const HEADER_FIELD_INVALID : u8     = 0;
pub const HEADER_FIELD_PATH: u8         = 1;
pub const HEADER_FIELD_INTERFACE: u8    = 2;
pub const HEADER_FIELD_MEMBER: u8       = 3;
pub const HEADER_FIELD_ERROR_NAME: u8   = 4;
pub const HEADER_FIELD_REPLY_SERIAL: u8 = 5;
pub const HEADER_FIELD_DESTINATION: u8  = 6;
pub const HEADER_FIELD_SENDER: u8       = 7;
pub const HEADER_FIELD_SIGNATURE: u8    = 8;

pub const FLAGS_NO_REPLY_EXPECTED : u8  = 1;

#[derive(Debug)]
pub struct HeaderField (
    pub u8,
    pub Variant
);

impl Marshal for HeaderField {
    fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
        pad_to_multiple(buf, 8);
        let start_len = buf.len();
        let code = self.0 as u8;
        code.dbus_encode(buf);
        self.1.dbus_encode(buf);
        buf.len() - start_len
    }
    fn get_type(&self) -> String {
        "(yv)".to_string()
    }
}

/// Represents a received message from the message bus
#[derive(Debug,Default)]
pub struct Message {
    pub big_endian: bool,
    pub message_type: MessageType,
    pub flags: u8,
    pub version: u8,
    pub serial: u32,
    pub headers: Vec<HeaderField>,
    pub body: Vec<u8>
}

impl Marshal for Message {
    fn dbus_encode (&self, buf: &mut Vec<u8>) -> usize {
        let endian = if self.big_endian { 'B' as u8 } else { 'l' as u8 };
        endian.dbus_encode(buf);
        self.message_type.0.dbus_encode(buf);
        self.flags.dbus_encode(buf);
        self.version.dbus_encode(buf);
        let len : u32 = self.body.len() as u32;
        len.dbus_encode(buf);
        self.serial.dbus_encode(buf);
        self.headers.dbus_encode(buf);
        pad_to_multiple(buf, 8);
        0
    }

    fn get_type (&self) -> String {
        panic!("Don't do that.")
    }
}

/// Create a Message for a D-Bus method call.  Once a Message is created, arguments
/// can be added with Message.add_arg
pub fn create_method_call (dest: &str, path: &str, iface: &str, method: &str) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_METHOD_CALL,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),
    }.add_header(HEADER_FIELD_DESTINATION,
                 Variant::new(Value::from(dest), "s"))
     .add_header(HEADER_FIELD_PATH,
                 Variant::new(Value::BasicValue(BasicValue::ObjectPath(Path(path.to_string()))), "o"))
     .add_header(HEADER_FIELD_INTERFACE,
                 Variant::new(Value::from(iface), "s"))
     .add_header(HEADER_FIELD_MEMBER,
                 Variant::new(Value::from(method), "s"))
}

/// Create a Message for a D-Bus method return.  Once created, return values can be added
/// with Message.add_arg
pub fn create_method_return(reply_serial: u32) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_METHOD_RETURN,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),
    }.add_header(HEADER_FIELD_REPLY_SERIAL,
                 Variant::new(Value::from(reply_serial), "u"))
}

impl Message {
    /// Add the given argument to the Message.  Accepts anything that implements the Marshal
    /// trait, which is most basic types, as well as the general-purpose
    /// dbus_serialize::types::Value enum.
    ///
    /// Note that these calls can be chained together to add multiple arguments, see the example
    ///
    /// # Examples
    /// ```
    /// dbus_bytestream::message::create_method_call("foo", "/bar", "baz", "bloop")
    ///     .add_arg(&1)
    ///     .add_arg(&"string");
    /// ```
    pub fn add_arg(mut self, arg: &Marshal) -> Message {
        match self.get_header(HEADER_FIELD_SIGNATURE) {
            None => {
                let value = Value::BasicValue(BasicValue::Signature(Signature("".to_string())));
                let variant = Variant::new(value, "g");
                self = self.add_header(HEADER_FIELD_SIGNATURE, variant);
            },
            _ => ()
        };
        {
            let b : &mut Box<Value> = &mut self.get_header(HEADER_FIELD_SIGNATURE).unwrap().object;
            let val : &mut Value = b.deref_mut();
            match val {
                &mut Value::BasicValue(BasicValue::Signature(ref mut s)) => s.0.push_str(&arg.get_type()),
                _ => panic!("Garbage in signature field")
            };
        }
        arg.dbus_encode(&mut self.body);
        self
    }

    pub fn get_header(&mut self, name: u8) -> Option<&mut Variant> {
        match self.headers.iter().position(|x| { x.0 == name }) {
            Some(idx) => Some(&mut self.headers[idx].1),
            _ => None
        }
    }

    pub fn add_header(mut self, name: u8, val: Variant) -> Message {
        self.headers.push(HeaderField (name, val));
        self
    }

    /// Get the sequence of Values from out of a Message.  Returns None if the message doesn't have
    /// a body.
    pub fn get_body(&mut self) -> Result<Option<Vec<Value>>,DemarshalError> {
        if self.body.len() == 0 {
            return Ok(None);
        }

        // Get the signature out of the headers
        let v = match self.headers.iter().position(|x| { x.0 == HEADER_FIELD_SIGNATURE }) {
            Some(idx) => &self.headers[idx].1,
            None => return Ok(None)
        };

        let sigval = match *v.object {
            Value::BasicValue(BasicValue::Signature(ref x)) => x,
            _ => return Ok(None)
        };

        let mut sig = "(".to_string() + &sigval.0 + ")";
        let mut offset = 0;
        match try!(demarshal(&mut self.body, &mut offset, &mut sig)) {
            Value::Struct(x) => Ok(Some(x.objects)),
            x => panic!("Didn't get a struct: {:?}", x)
        }
    }
}

#[test]
fn test_msg () {
    create_method_call("foo", "bar", "baz", "floob")
        .add_arg(&1)
        .add_arg(&2);
}
<commit_msg>message.rs: add helpers for create_error and create_signal<commit_after>//! Functions for creating and modifying messages to send across the message bus.
use std::ops::DerefMut;

use dbus_serialize::types::{Path,Variant,Value,BasicValue,Signature};

use marshal::{Marshal,pad_to_multiple};
use demarshal::{demarshal,DemarshalError};

#[derive(Debug,Default,PartialEq)]
pub struct MessageType(pub u8);
pub const MESSAGE_TYPE_INVALID : MessageType        = MessageType(0);
pub const MESSAGE_TYPE_METHOD_CALL : MessageType    = MessageType(1);
pub const MESSAGE_TYPE_METHOD_RETURN : MessageType  = MessageType(2);
pub const MESSAGE_TYPE_ERROR : MessageType          = MessageType(3);
pub const MESSAGE_TYPE_SIGNAL : MessageType         = MessageType(4);

pub const HEADER_FIELD_INVALID : u8     = 0;
pub const HEADER_FIELD_PATH: u8         = 1;
pub const HEADER_FIELD_INTERFACE: u8    = 2;
pub const HEADER_FIELD_MEMBER: u8       = 3;
pub const HEADER_FIELD_ERROR_NAME: u8   = 4;
pub const HEADER_FIELD_REPLY_SERIAL: u8 = 5;
pub const HEADER_FIELD_DESTINATION: u8  = 6;
pub const HEADER_FIELD_SENDER: u8       = 7;
pub const HEADER_FIELD_SIGNATURE: u8    = 8;

pub const FLAGS_NO_REPLY_EXPECTED : u8  = 1;

#[derive(Debug)]
pub struct HeaderField (
    pub u8,
    pub Variant
);

impl Marshal for HeaderField {
    fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
        pad_to_multiple(buf, 8);
        let start_len = buf.len();
        let code = self.0 as u8;
        code.dbus_encode(buf);
        self.1.dbus_encode(buf);
        buf.len() - start_len
    }
    fn get_type(&self) -> String {
        "(yv)".to_string()
    }
}

/// Represents a received message from the message bus
#[derive(Debug,Default)]
pub struct Message {
    pub big_endian: bool,
    pub message_type: MessageType,
    pub flags: u8,
    pub version: u8,
    pub serial: u32,
    pub headers: Vec<HeaderField>,
    pub body: Vec<u8>
}

impl Marshal for Message {
    fn dbus_encode (&self, buf: &mut Vec<u8>) -> usize {
        let endian = if self.big_endian { 'B' as u8 } else { 'l' as u8 };
        endian.dbus_encode(buf);
        self.message_type.0.dbus_encode(buf);
        self.flags.dbus_encode(buf);
        self.version.dbus_encode(buf);
        let len : u32 = self.body.len() as u32;
        len.dbus_encode(buf);
        self.serial.dbus_encode(buf);
        self.headers.dbus_encode(buf);
        pad_to_multiple(buf, 8);
        0
    }

    fn get_type (&self) -> String {
        panic!("Don't do that.")
    }
}

/// Create a Message for a D-Bus method call.  Once a Message is created, arguments
/// can be added with Message.add_arg
pub fn create_method_call (dest: &str, path: &str, iface: &str, method: &str) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_METHOD_CALL,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),
    }.add_header(HEADER_FIELD_DESTINATION,
                 Variant::new(Value::from(dest), "s"))
     .add_header(HEADER_FIELD_PATH,
                 Variant::new(Value::BasicValue(BasicValue::ObjectPath(Path(path.to_string()))), "o"))
     .add_header(HEADER_FIELD_INTERFACE,
                 Variant::new(Value::from(iface), "s"))
     .add_header(HEADER_FIELD_MEMBER,
                 Variant::new(Value::from(method), "s"))
}

/// Create a Message for a D-Bus method return.  Once created, return values can be added
/// with Message.add_arg
pub fn create_method_return(reply_serial: u32) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_METHOD_RETURN,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),
    }.add_header(HEADER_FIELD_REPLY_SERIAL,
                 Variant::new(Value::from(reply_serial), "u"))
}

/// Create a Message for a D-Bus error.  Once created, return values can be added
/// with Message.add_arg
pub fn create_error(error_name: &str, reply_serial: u32) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_ERROR,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),
    }.add_header(HEADER_FIELD_REPLY_SERIAL,
                 Variant::new(Value::from(reply_serial), "u"))
     .add_header(HEADER_FIELD_ERROR_NAME,
                 Variant::new(Value::from(error_name), "s"))
}

/// Create a Message for a D-Bus signal.  Once created, return values can be added
/// with Message.add_arg
pub fn create_signal(path: &str, interface: &str, member: &str) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_SIGNAL,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),
    }.add_header(HEADER_FIELD_PATH,
                 Variant::new(Value::BasicValue(BasicValue::ObjectPath(Path(path.to_string()))), "o"))
     .add_header(HEADER_FIELD_INTERFACE,
                 Variant::new(Value::from(interface), "s"))
     .add_header(HEADER_FIELD_MEMBER,
                 Variant::new(Value::from(member), "s"))
}

impl Message {
    /// Add the given argument to the Message.  Accepts anything that implements the Marshal
    /// trait, which is most basic types, as well as the general-purpose
    /// dbus_serialize::types::Value enum.
    ///
    /// Note that these calls can be chained together to add multiple arguments, see the example
    ///
    /// # Examples
    /// ```
    /// dbus_bytestream::message::create_method_call("foo", "/bar", "baz", "bloop")
    ///     .add_arg(&1)
    ///     .add_arg(&"string");
    /// ```
    pub fn add_arg(mut self, arg: &Marshal) -> Message {
        match self.get_header(HEADER_FIELD_SIGNATURE) {
            None => {
                let value = Value::BasicValue(BasicValue::Signature(Signature("".to_string())));
                let variant = Variant::new(value, "g");
                self = self.add_header(HEADER_FIELD_SIGNATURE, variant);
            },
            _ => ()
        };
        {
            let b : &mut Box<Value> = &mut self.get_header(HEADER_FIELD_SIGNATURE).unwrap().object;
            let val : &mut Value = b.deref_mut();
            match val {
                &mut Value::BasicValue(BasicValue::Signature(ref mut s)) => s.0.push_str(&arg.get_type()),
                _ => panic!("Garbage in signature field")
            };
        }
        arg.dbus_encode(&mut self.body);
        self
    }

    pub fn get_header(&mut self, name: u8) -> Option<&mut Variant> {
        match self.headers.iter().position(|x| { x.0 == name }) {
            Some(idx) => Some(&mut self.headers[idx].1),
            _ => None
        }
    }

    pub fn add_header(mut self, name: u8, val: Variant) -> Message {
        self.headers.push(HeaderField (name, val));
        self
    }

    /// Get the sequence of Values from out of a Message.  Returns None if the message doesn't have
    /// a body.
    pub fn get_body(&mut self) -> Result<Option<Vec<Value>>,DemarshalError> {
        if self.body.len() == 0 {
            return Ok(None);
        }

        // Get the signature out of the headers
        let v = match self.headers.iter().position(|x| { x.0 == HEADER_FIELD_SIGNATURE }) {
            Some(idx) => &self.headers[idx].1,
            None => return Ok(None)
        };

        let sigval = match *v.object {
            Value::BasicValue(BasicValue::Signature(ref x)) => x,
            _ => return Ok(None)
        };

        let mut sig = "(".to_string() + &sigval.0 + ")";
        let mut offset = 0;
        match try!(demarshal(&mut self.body, &mut offset, &mut sig)) {
            Value::Struct(x) => Ok(Some(x.objects)),
            x => panic!("Didn't get a struct: {:?}", x)
        }
    }
}

#[test]
fn test_msg () {
    create_method_call("foo", "bar", "baz", "floob")
        .add_arg(&1)
        .add_arg(&2);
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::mem;

use runtime::{Class, Object, Sel, Super, self};

/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

#[cfg(target_arch = "x86")]
fn msg_send_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    let size = mem::size_of::<R>();
    if type_id == TypeId::of::<f32>() || type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSend_fpret) }
    } else if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "x86")]
fn msg_send_super_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    let size = mem::size_of::<R>();
    if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(target_arch = "arm")]
fn msg_send_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    if mem::size_of::<R>() <= 4 ||
            type_id == TypeId::of::<i64>() ||
            type_id == TypeId::of::<u64>() ||
            type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "arm")]
fn msg_send_super_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    if mem::size_of::<R>() <= 4 ||
            type_id == TypeId::of::<i64>() ||
            type_id == TypeId::of::<u64>() ||
            type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(target_arch = "aarch64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    unsafe { mem::transmute(runtime::objc_msgSend) }
}

#[cfg(target_arch = "aarch64")]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    unsafe { mem::transmute(runtime::objc_msgSendSuper) }
}

/// Types that may be used as the arguments of an Objective-C message.
pub trait MessageArguments {
    /// Sends a message to the given obj with the given selector and self as
    /// the arguments.
    ///
    /// The correct version of `objc_msgSend` will be chosen based on the
    /// return type. For more information, see Apple's documenation:
    /// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
    ///
    /// It is recommended to use the `msg_send!` macro rather than calling this
    /// method directly.
    unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
            where T: Message, R: Any;

    /// Sends a message to the superclass of an instance of a class with self
    /// as the arguments.
    unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
            where T: Message, R: Any;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
                    where T: Message, R: Any {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let ($($a,)*) = self;
                objc_try!({
                    msg_send_fn(obj as *mut Object, sel $(, $a)*)
                })
            }

            unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
                    where T: Message, R: Any {
                let msg_send_fn = msg_send_super_fn::<R>();
                let msg_send_fn: unsafe extern fn(*const Super, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let sup = Super { receiver: obj as *mut Object, superclass: superclass };
                let ($($a,)*) = self;
                objc_try!({
                    msg_send_fn(&sup, sel $(, $a)*)
                })
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[cfg(test)]
mod tests {
    use std::ptr;
    use runtime::Object;
    use test_utils;

    #[test]
    fn test_send_message() {
        let obj = test_utils::sample_object();
        let result: *const Object = unsafe {
            msg_send![obj, self]
        };
        assert!(result == &*obj);
    }

    #[test]
    fn test_send_message_stret() {
        let obj = test_utils::custom_object();
        let result: test_utils::CustomStruct = unsafe {
            msg_send![obj, customStruct]
        };
        let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
        assert!(result == expected);
    }

    #[test]
    fn test_send_message_nil() {
        let nil: *mut Object = ptr::null_mut();
        let result: usize = unsafe {
            msg_send![nil, hash]
        };
        assert!(result == 0);

        let result: *mut Object = unsafe {
            msg_send![nil, description]
        };
        assert!(result.is_null());

        let result: f64 = unsafe {
            msg_send![nil, doubleValue]
        };
        assert!(result == 0.0);
    }

    #[test]
    fn test_send_message_super() {
        let obj = test_utils::custom_subclass_object();
        let superclass = test_utils::custom_class();
        unsafe {
            let _: () = msg_send![obj, setFoo:4u32];
            let foo: u32 = msg_send![super(obj, superclass), foo];
            assert!(foo == 4);

            // The subclass is overriden to return foo + 2
            let foo: u32 = msg_send![obj, foo];
            assert!(foo == 6);
        }
    }
}
<commit_msg>Documented all the calling conventions before I forget.<commit_after>use std::any::Any;
use std::mem;

use runtime::{Class, Object, Sel, Super, self};

/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

#[cfg(target_arch = "x86")]
fn msg_send_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // Structures 1 or 2 bytes in size are placed in EAX.
    // Structures 4 or 8 bytes in size are placed in: EAX and EDX.
    // Structures of other sizes are placed at the address supplied by the caller.
    // https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html

    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    let size = mem::size_of::<R>();
    if type_id == TypeId::of::<f32>() || type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSend_fpret) }
    } else if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "x86")]
fn msg_send_super_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    let size = mem::size_of::<R>();
    if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // If the size of an object is larger than two eightbytes, it has class MEMORY.
    // If the type has class MEMORY, then the caller provides space for the return
    // value and passes the address of this storage.
    // http://people.freebsd.org/~obrien/amd64-elf-abi.pdf

    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(target_arch = "arm")]
fn msg_send_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // Double-word sized fundamental data types don't use stret,
    // but any composite type larger than 4 bytes does.
    // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf

    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    if mem::size_of::<R>() <= 4 ||
            type_id == TypeId::of::<i64>() ||
            type_id == TypeId::of::<u64>() ||
            type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "arm")]
fn msg_send_super_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    if mem::size_of::<R>() <= 4 ||
            type_id == TypeId::of::<i64>() ||
            type_id == TypeId::of::<u64>() ||
            type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(target_arch = "aarch64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // stret is not even available in arm64.
    // https://twitter.com/gparker/status/378079715824660480

    unsafe { mem::transmute(runtime::objc_msgSend) }
}

#[cfg(target_arch = "aarch64")]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    unsafe { mem::transmute(runtime::objc_msgSendSuper) }
}

/// Types that may be used as the arguments of an Objective-C message.
pub trait MessageArguments {
    /// Sends a message to the given obj with the given selector and self as
    /// the arguments.
    ///
    /// The correct version of `objc_msgSend` will be chosen based on the
    /// return type. For more information, see Apple's documenation:
    /// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
    ///
    /// It is recommended to use the `msg_send!` macro rather than calling this
    /// method directly.
    unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
            where T: Message, R: Any;

    /// Sends a message to the superclass of an instance of a class with self
    /// as the arguments.
    unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
            where T: Message, R: Any;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
                    where T: Message, R: Any {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let ($($a,)*) = self;
                objc_try!({
                    msg_send_fn(obj as *mut Object, sel $(, $a)*)
                })
            }

            unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
                    where T: Message, R: Any {
                let msg_send_fn = msg_send_super_fn::<R>();
                let msg_send_fn: unsafe extern fn(*const Super, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let sup = Super { receiver: obj as *mut Object, superclass: superclass };
                let ($($a,)*) = self;
                objc_try!({
                    msg_send_fn(&sup, sel $(, $a)*)
                })
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[cfg(test)]
mod tests {
    use std::ptr;
    use runtime::Object;
    use test_utils;

    #[test]
    fn test_send_message() {
        let obj = test_utils::sample_object();
        let result: *const Object = unsafe {
            msg_send![obj, self]
        };
        assert!(result == &*obj);
    }

    #[test]
    fn test_send_message_stret() {
        let obj = test_utils::custom_object();
        let result: test_utils::CustomStruct = unsafe {
            msg_send![obj, customStruct]
        };
        let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
        assert!(result == expected);
    }

    #[test]
    fn test_send_message_nil() {
        let nil: *mut Object = ptr::null_mut();
        let result: usize = unsafe {
            msg_send![nil, hash]
        };
        assert!(result == 0);

        let result: *mut Object = unsafe {
            msg_send![nil, description]
        };
        assert!(result.is_null());

        let result: f64 = unsafe {
            msg_send![nil, doubleValue]
        };
        assert!(result == 0.0);
    }

    #[test]
    fn test_send_message_super() {
        let obj = test_utils::custom_subclass_object();
        let superclass = test_utils::custom_class();
        unsafe {
            let _: () = msg_send![obj, setFoo:4u32];
            let foo: u32 = msg_send![super(obj, superclass), foo];
            assert!(foo == 4);

            // The subclass is overriden to return foo + 2
            let foo: u32 = msg_send![obj, foo];
            assert!(foo == 6);
        }
    }
}
<|endoftext|>