<commit_before>use address::{LENGTH, Address, Addressable};
use num::bigint::{BigUint, ToBigUint};
use std::collections::HashMap;
use std::collections::hash_map::Values;
use num;

#[derive(Debug)]
pub struct NodeBucket<A: Addressable> {
    k: usize,
    min: BigUint,
    max: BigUint,
    addresses: Vec<Address>,
    nodes: HashMap<Address, A>
}

impl<A: Addressable> NodeBucket<A> {
    pub fn new(k: usize) -> NodeBucket<A> {
        let min = 0.to_biguint().unwrap();
        let max = num::pow(2.to_biguint().unwrap(), LENGTH);
        NodeBucket {
            k: k,
            min: min,
            max: max,
            addresses: Vec::with_capacity(k),
            nodes: HashMap::with_capacity(k)
        }
    }

    pub fn contains(&self, address: &Address) -> bool {
        self.addresses.contains(address)
    }

    pub fn covers(&self, address: &Address) -> bool {
        let numeric = address.as_numeric();
        self.min <= numeric && numeric < self.max
    }

    pub fn get_nodes(&mut self) -> Vec<&mut A> {
        self.nodes.iter_mut().map(|(_, node)| node).collect()
    }

    pub fn insert(&mut self, node: A) {
        let address = node.get_address();
        if let Some(pos) = self.addresses.iter().position(|&a| a == address) {
            self.addresses.remove(pos);
            self.addresses.insert(0, address);
            self.nodes.insert(address, node);
        } else if !self.is_full() {
            self.addresses.insert(0, address);
            self.nodes.insert(address, node);
        }
    }

    pub fn is_full(&self) -> bool {
        self.addresses.len() >= self.k
    }

    pub fn split(&mut self) -> (Self, Self) {
        let partition = self.max.clone() / 2.to_biguint().unwrap();
        let addresses = self.addresses.clone();
        let (a_addresses, b_addresses): (Vec<Address>, Vec<Address>) = addresses
            .into_iter()
            .partition(|&a| a.as_numeric() < partition);
        let mut a_nodes = HashMap::new();
        let mut b_nodes = HashMap::new();
        for (address, node) in self.nodes.drain() {
            if address.as_numeric() < partition {
                a_nodes.insert(address, node);
            } else {
                b_nodes.insert(address, node);
            }
        }

        let a = NodeBucket {
            k: self.k,
            min: self.min.clone(),
            max: partition.clone(),
            addresses: a_addresses,
            nodes: a_nodes
        };
        let b = NodeBucket {
            k: self.k,
            min: partition.clone(),
            max: self.max.clone(),
            addresses: b_addresses,
            nodes: b_nodes
        };
        (a, b)
    }
}

#[cfg(test)]
mod tests {
    use address::{Address, Addressable};
    use super::NodeBucket;

    #[derive(Clone,Copy,Debug,PartialEq,Eq)]
    struct Node {
        pub address: Address
    }

    impl Node {
        fn new(address: Address) -> Node {
            Node { address: address }
        }
    }

    impl Addressable for Node {
        fn get_address(&self) -> Address {
            self.address
        }
    }

    #[test]
    fn test_insert() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(8);
        let node = Node::new(Address::for_content("some string"));
        bucket.insert(node);
        assert_eq!(bucket.addresses.len(), 1);
    }

    #[test]
    fn test_insert_duplicate() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(8);
        let a = Node::new(Address::for_content("node 1"));
        let b = Node::new(Address::for_content("node 2"));
        let c = Node::new(Address::for_content("node 1"));

        bucket.insert(a.clone());
        bucket.insert(b);
        bucket.insert(c);

        assert_eq!(bucket.addresses.len(), 2);
        assert_eq!(bucket.nodes[&Address::for_content("node 1")], a);
    }

    #[test]
    fn test_insert_full() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(2);
        bucket.insert(Node::new(Address::for_content("node 1")));
        bucket.insert(Node::new(Address::for_content("node 2")));
        bucket.insert(Node::new(Address::for_content("node 3")));
        assert_eq!(bucket.addresses.len(), 2);
        assert_eq!(bucket.nodes.get(&Address::for_content("node 3")), None);
    }

    #[test]
    fn test_is_full() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(2);
        assert!(!bucket.is_full());

        bucket.insert(Node::new(Address::for_content("node 1")));
        bucket.insert(Node::new(Address::for_content("node 2")));
        assert!(bucket.is_full());
    }

    #[test]
    fn test_contains() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(8);
        bucket.insert(Node::new(Address::for_content("node 1")));
        assert!(bucket.contains(&Address::for_content("node 1")));
    }

    #[test]
    fn test_covers() {
        let bucket: NodeBucket<Node> = NodeBucket::new(8);
        let address_1 = Address::from_str("0000000000000000000000000000000000000000");
        let address_2 = Address::from_str("ffffffffffffffffffffffffffffffffffffffff");
        assert!(bucket.covers(&address_1));
        assert!(bucket.covers(&address_2));
    }

    #[test]
    fn test_split() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(4);
        let node_1 = Node::new(Address::from_str("0000000000000000000000000000000000000000"));
        let node_2 = Node::new(Address::from_str("7fffffffffffffffffffffffffffffffffffffff"));
        let node_3 = Node::new(Address::from_str("8000000000000000000000000000000000000000"));
        let node_4 = Node::new(Address::from_str("ffffffffffffffffffffffffffffffffffffffff"));

        bucket.insert(node_1);
        bucket.insert(node_2);
        bucket.insert(node_3);
        bucket.insert(node_4);

        let (a, b) = bucket.split();

        // Splits up known address
        assert_eq!(a.addresses.len(), 2);
        assert_eq!(b.addresses.len(), 2);

        // Splits up known nodes
        assert_eq!(a.nodes[&Address::from_str("0000000000000000000000000000000000000000")], node_1);
        assert_eq!(a.nodes[&Address::from_str("7fffffffffffffffffffffffffffffffffffffff")], node_2);
        assert_eq!(b.nodes[&Address::from_str("8000000000000000000000000000000000000000")], node_3);
        assert_eq!(b.nodes[&Address::from_str("ffffffffffffffffffffffffffffffffffffffff")], node_4);

        // Equitably covers address space
        assert!(a.covers(&Address::from_str("0000000000000000000000000000000000000000")));
        assert!(!b.covers(&Address::from_str("0000000000000000000000000000000000000000")));
        assert!(a.covers(&Address::from_str("7fffffffffffffffffffffffffffffffffffffff")));
        assert!(!b.covers(&Address::from_str("7fffffffffffffffffffffffffffffffffffffff")));
        assert!(!a.covers(&Address::from_str("8000000000000000000000000000000000000000")));
        assert!(b.covers(&Address::from_str("8000000000000000000000000000000000000000")));
        assert!(!a.covers(&Address::from_str("ffffffffffffffffffffffffffffffffffffffff")));
        assert!(b.covers(&Address::from_str("ffffffffffffffffffffffffffffffffffffffff")));
    }
}
<commit_msg>Remove unused import<commit_after>use address::{LENGTH, Address, Addressable};
use num::bigint::{BigUint, ToBigUint};
use std::collections::HashMap;
use num;

#[derive(Debug)]
pub struct NodeBucket<A: Addressable> {
    k: usize,
    min: BigUint,
    max: BigUint,
    addresses: Vec<Address>,
    nodes: HashMap<Address, A>
}

impl<A: Addressable> NodeBucket<A> {
    pub fn new(k: usize) -> NodeBucket<A> {
        let min = 0.to_biguint().unwrap();
        let max = num::pow(2.to_biguint().unwrap(), LENGTH);
        NodeBucket {
            k: k,
            min: min,
            max: max,
            addresses: Vec::with_capacity(k),
            nodes: HashMap::with_capacity(k)
        }
    }

    pub fn contains(&self, address: &Address) -> bool {
        self.addresses.contains(address)
    }

    pub fn covers(&self, address: &Address) -> bool {
        let numeric = address.as_numeric();
        self.min <= numeric && numeric < self.max
    }

    pub fn get_nodes(&mut self) -> Vec<&mut A> {
        self.nodes.iter_mut().map(|(_, node)| node).collect()
    }

    pub fn insert(&mut self, node: A) {
        let address = node.get_address();
        if let Some(pos) = self.addresses.iter().position(|&a| a == address) {
            self.addresses.remove(pos);
            self.addresses.insert(0, address);
            self.nodes.insert(address, node);
        } else if !self.is_full() {
            self.addresses.insert(0, address);
            self.nodes.insert(address, node);
        }
    }

    pub fn is_full(&self) -> bool {
        self.addresses.len() >= self.k
    }

    pub fn split(&mut self) -> (Self, Self) {
        let partition = self.max.clone() / 2.to_biguint().unwrap();
        let addresses = self.addresses.clone();
        let (a_addresses, b_addresses): (Vec<Address>, Vec<Address>) = addresses
            .into_iter()
            .partition(|&a| a.as_numeric() < partition);
        let mut a_nodes = HashMap::new();
        let mut b_nodes = HashMap::new();
        for (address, node) in self.nodes.drain() {
            if address.as_numeric() < partition {
                a_nodes.insert(address, node);
            } else {
                b_nodes.insert(address, node);
            }
        }

        let a = NodeBucket {
            k: self.k,
            min: self.min.clone(),
            max: partition.clone(),
            addresses: a_addresses,
            nodes: a_nodes
        };
        let b = NodeBucket {
            k: self.k,
            min: partition.clone(),
            max: self.max.clone(),
            addresses: b_addresses,
            nodes: b_nodes
        };
        (a, b)
    }
}

#[cfg(test)]
mod tests {
    use address::{Address, Addressable};
    use super::NodeBucket;

    #[derive(Clone,Copy,Debug,PartialEq,Eq)]
    struct Node {
        pub address: Address
    }

    impl Node {
        fn new(address: Address) -> Node {
            Node { address: address }
        }
    }

    impl Addressable for Node {
        fn get_address(&self) -> Address {
            self.address
        }
    }

    #[test]
    fn test_insert() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(8);
        let node = Node::new(Address::for_content("some string"));
        bucket.insert(node);
        assert_eq!(bucket.addresses.len(), 1);
    }

    #[test]
    fn test_insert_duplicate() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(8);
        let a = Node::new(Address::for_content("node 1"));
        let b = Node::new(Address::for_content("node 2"));
        let c = Node::new(Address::for_content("node 1"));

        bucket.insert(a.clone());
        bucket.insert(b);
        bucket.insert(c);

        assert_eq!(bucket.addresses.len(), 2);
        assert_eq!(bucket.nodes[&Address::for_content("node 1")], a);
    }

    #[test]
    fn test_insert_full() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(2);
        bucket.insert(Node::new(Address::for_content("node 1")));
        bucket.insert(Node::new(Address::for_content("node 2")));
        bucket.insert(Node::new(Address::for_content("node 3")));
        assert_eq!(bucket.addresses.len(), 2);
        assert_eq!(bucket.nodes.get(&Address::for_content("node 3")), None);
    }

    #[test]
    fn test_is_full() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(2);
        assert!(!bucket.is_full());

        bucket.insert(Node::new(Address::for_content("node 1")));
        bucket.insert(Node::new(Address::for_content("node 2")));
        assert!(bucket.is_full());
    }

    #[test]
    fn test_contains() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(8);
        bucket.insert(Node::new(Address::for_content("node 1")));
        assert!(bucket.contains(&Address::for_content("node 1")));
    }

    #[test]
    fn test_covers() {
        let bucket: NodeBucket<Node> = NodeBucket::new(8);
        let address_1 = Address::from_str("0000000000000000000000000000000000000000");
        let address_2 = Address::from_str("ffffffffffffffffffffffffffffffffffffffff");
        assert!(bucket.covers(&address_1));
        assert!(bucket.covers(&address_2));
    }

    #[test]
    fn test_split() {
        let mut bucket: NodeBucket<Node> = NodeBucket::new(4);
        let node_1 = Node::new(Address::from_str("0000000000000000000000000000000000000000"));
        let node_2 = Node::new(Address::from_str("7fffffffffffffffffffffffffffffffffffffff"));
        let node_3 = Node::new(Address::from_str("8000000000000000000000000000000000000000"));
        let node_4 = Node::new(Address::from_str("ffffffffffffffffffffffffffffffffffffffff"));

        bucket.insert(node_1);
        bucket.insert(node_2);
        bucket.insert(node_3);
        bucket.insert(node_4);

        let (a, b) = bucket.split();

        // Splits up known address
        assert_eq!(a.addresses.len(), 2);
        assert_eq!(b.addresses.len(), 2);

        // Splits up known nodes
        assert_eq!(a.nodes[&Address::from_str("0000000000000000000000000000000000000000")], node_1);
        assert_eq!(a.nodes[&Address::from_str("7fffffffffffffffffffffffffffffffffffffff")], node_2);
        assert_eq!(b.nodes[&Address::from_str("8000000000000000000000000000000000000000")], node_3);
        assert_eq!(b.nodes[&Address::from_str("ffffffffffffffffffffffffffffffffffffffff")], node_4);

        // Equitably covers address space
        assert!(a.covers(&Address::from_str("0000000000000000000000000000000000000000")));
        assert!(!b.covers(&Address::from_str("0000000000000000000000000000000000000000")));
        assert!(a.covers(&Address::from_str("7fffffffffffffffffffffffffffffffffffffff")));
        assert!(!b.covers(&Address::from_str("7fffffffffffffffffffffffffffffffffffffff")));
        assert!(!a.covers(&Address::from_str("8000000000000000000000000000000000000000")));
        assert!(b.covers(&Address::from_str("8000000000000000000000000000000000000000")));
        assert!(!a.covers(&Address::from_str("ffffffffffffffffffffffffffffffffffffffff")));
        assert!(b.covers(&Address::from_str("ffffffffffffffffffffffffffffffffffffffff")));
    }
}
<|endoftext|>


<commit_before>/*wrap_fn*/#![feature(plugin)]
#![plugin(parse_generics_poc)]

use std::fmt::Display;

macro_rules! wrap_fn {
    (
        as $wrap_name:ident,
        fn $fn_name:ident $($tail:tt)*
    ) => {
        parse_generics! {
            then wrap_fn!(@expand $wrap_name, $fn_name,),
            $($tail)*
        }
    };

    (@as_item $i:item) => { $i };

    (
        @expand
        $wrap_name:ident,
        $fn_name:ident,
        {
            constr: [$($constr:tt)*],
            ltimes: $ltimes:tt,
            params: [$($params:tt)*]
        },
        (
            $($arg_pats:ident: $arg_tys:ty),* $(,)*
        )
        $(-> $ret_ty:ty)* ;
        pre { $($pre:tt)* }
        post($res:ident) { $($post:tt)* }
    ) => {
        wrap_fn! {
            @as_item
            fn $wrap_name<$($constr)*>($($arg_pats: $arg_tys),*) $(-> $ret_ty)* {
                $($pre)*
                let $res = $fn_name::<$($params)*>($($arg_pats),*);
                $($post)*
            }
        }
    };
}

wrap_fn! {
    as wrap_to_string,
    fn to_string<T: Display>(v: T) -> String;
    pre {
        let prefix = String::from("wrap:");
    }
    post(result) {
        format!("{}{}", prefix, result)
    }
}

fn to_string<T: Display>(v: T) -> String {
    format!("{}", v)
}

#[test]
fn test_wrap_fn() {
    assert_eq!(&*wrap_to_string(42i32), "wrap:42");
}
<commit_msg>Another wrap_fn test.<commit_after>/*wrap_fn*/#![feature(plugin)]
#![plugin(parse_generics_poc)]

use std::fmt::Display;

macro_rules! wrap_fn {
    (
        as $wrap_name:ident,
        fn $fn_name:ident $($tail:tt)*
    ) => {
        parse_generics! {
            then wrap_fn!(@expand $wrap_name, $fn_name,),
            $($tail)*
        }
    };

    (@as_item $i:item) => { $i };

    (
        @expand
        $wrap_name:ident,
        $fn_name:ident,
        {
            constr: [$($constr:tt)*],
            ltimes: $ltimes:tt,
            params: [$($params:tt)*]
        },
        (
            $($arg_pats:ident: $arg_tys:ty),* $(,)*
        )
        $(-> $ret_ty:ty)* ;
        pre { $($pre:tt)* }
        post($res:ident) { $($post:tt)* }
    ) => {
        wrap_fn! {
            @as_item
            fn $wrap_name<$($constr)*>($($arg_pats: $arg_tys),*) $(-> $ret_ty)* {
                $($pre)*
                let $res = $fn_name::<$($params)*>($($arg_pats),*);
                $($post)*
            }
        }
    };
}

wrap_fn! {
    as wrap_to_string,
    fn to_string<T: Display>(v: T) -> String;
    pre {
        let prefix = String::from("wrap:");
    }
    post(result) {
        format!("{}{}", prefix, result)
    }
}

fn to_string<T: Display>(v: T) -> String {
    format!("{}", v)
}

#[test]
fn test_wrap_fn() {
    assert_eq!(&*wrap_to_string(42i32), "wrap:42");
}

trait Dummy<'a, T: ?Sized>: Sized {
    fn id(self) -> Self { self }
}

impl<'a> Dummy<'a, str> for &'a str {}

fn id<'a, T: ?Sized, U: ::Dummy<'a, T>>(v: U) -> U { v.id() }

wrap_fn! {
    as wrap_id,
    fn id<'a, T: ?Sized, U: ::Dummy<'a, T>>(v: U) -> U;
    pre {}
    post(result) { result }
}

#[test]
fn test_wrap_fn_id() {
    assert_eq!(wrap_id("hi!"), "hi!");
}
<|endoftext|>


<commit_before>#![recursion_limit = "150"]
use std::result;
mod operand;
use operand::Operand;
extern crate r68k_common;
use r68k_common::constants::*;
mod constants;
use constants::*;
#[macro_use]
extern crate pest;

pub mod memory;
pub mod assembler;
pub mod disassembler;
pub mod srecords;

use memory::Memory;

// type alias for exception handling
pub type Result<T> = result::Result<T, Exception>;
type OperandDecoder = fn(u16, Size, u32, &Memory) -> Vec<Operand>;
type InstructionEncoder = fn(&OpcodeInstance, u16, u32, &mut Memory) -> u32;
type InstructionSelector = fn(&OpcodeInstance) -> bool;

#[derive(Debug)]
pub enum Exception {
     IllegalInstruction(u16, u32), // ir, pc
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Size {
	Unsized, Byte, Word, Long
}

impl fmt::Display for Size {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Size::Unsized => write!(f, ""),
            Size::Byte => write!(f, ".B"),
            Size::Word => write!(f, ".W"),
            Size::Long => write!(f, ".L"),
        }
    }
}

// #[derive(Clone, Copy)]
pub struct OpcodeInfo<'a> {
    mask: u32,
    matching: u32,
    ea_mask: u16,
    size: Size,
    decoder: OperandDecoder,
    mnemonic: &'a str,
    encoder: InstructionEncoder,
    selector: InstructionSelector,
}
#[derive(Debug, PartialEq)]
pub struct OpcodeInstance<'a> {
    mnemonic: &'a str,
    size: Size,
	operands: Vec<Operand>,
}

use std::fmt;
impl<'a> fmt::Debug for OpcodeInfo<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            _ => write!(f, "[some fn]"),
        }
    }
}
impl<'a> fmt::Display for OpcodeInstance<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.operands.len() {
            0 => write!(f, "{}{}", self.mnemonic, self.size),
            1 => write!(f, "{}{}\t{}", self.mnemonic, self.size, self.operands[0]),
            2 => write!(f, "{}{}\t{},{}", self.mnemonic, self.size, self.operands[0], self.operands[1]),
            _ => panic!("more than two operands {:?}", self)
        }
    }
}
impl<'a> OpcodeInstance<'a> {
    pub fn length(&self) -> u32 {
        1 + self.operands.iter().map(|op| op.extension_words()).fold(0, |i,j|i+j)
    }
}
macro_rules! instruction {
    ($mask:expr, $matching:expr, $ea_mask:expr, $size:expr, $mnemonic:expr, $decoder:ident) => (OpcodeInfo { mask: $mask, matching: $matching, size: $size, mnemonic: $mnemonic, decoder: disassembler::$decoder, encoder: assembler::nop_encoder, selector: assembler::nop_selector, ea_mask: $ea_mask});
    ($mask:expr, $matching:expr, $ea_mask:expr, $size:expr, $mnemonic:expr, $decoder:ident, $selector:ident, $encoder:ident) => (OpcodeInfo { mask: $mask, matching: $matching, size: $size, mnemonic: $mnemonic, decoder: disassembler::$decoder, encoder: assembler::$encoder, selector: assembler::$selector, ea_mask: $ea_mask})
}
fn generate<'a>() -> Vec<OpcodeInfo<'a>> {
    vec![
        instruction!(MASK_OUT_X_EA, OP_ADD | BYTE_SIZED | DEST_EA, EA_MEMORY_ALTERABLE, Size::Byte, "ADD", decode_dx_ea, is_dx_ea, encode_dx_ea),
        instruction!(MASK_OUT_X_EA, OP_ADD | BYTE_SIZED | DEST_DX, EA_ALL_EXCEPT_AN, Size::Byte, "ADD", decode_ea_dx, is_ea_dx, encode_ea_dx),
        instruction!(MASK_OUT_X_EA, OP_ADD | WORD_SIZED | DEST_EA, EA_MEMORY_ALTERABLE, Size::Word, "ADD", decode_dx_ea, is_dx_ea, encode_dx_ea),
        instruction!(MASK_OUT_X_EA, OP_ADD | WORD_SIZED | DEST_DX, EA_ALL, Size::Word, "ADD", decode_ea_dx, is_ea_dx, encode_ea_dx),
        instruction!(MASK_OUT_X_EA, OP_ADD | LONG_SIZED | DEST_EA, EA_MEMORY_ALTERABLE, Size::Long, "ADD", decode_dx_ea, is_dx_ea, encode_dx_ea),
        instruction!(MASK_OUT_X_EA, OP_ADD | LONG_SIZED | DEST_DX, EA_ALL, Size::Long, "ADD", decode_ea_dx, is_ea_dx, encode_ea_dx),
        instruction!(MASK_OUT_X_EA, OP_ADD | DEST_AX_WORD, EA_ALL, Size::Word, "ADDA", decode_ea_ax, is_ea_ax, encode_ea_ax),
        instruction!(MASK_OUT_X_EA, OP_ADD | DEST_AX_LONG, EA_ALL, Size::Long, "ADDA", decode_ea_ax, is_ea_ax, encode_ea_ax),
        instruction!(MASK_OUT_EA, OP_ADDI | BYTE_SIZED, EA_DATA_ALTERABLE, Size::Byte, "ADDI", decode_imm_ea, is_imm_ea, encode_imm_ea),
        instruction!(MASK_OUT_EA, OP_ADDI | WORD_SIZED, EA_DATA_ALTERABLE, Size::Word, "ADDI", decode_imm_ea, is_imm_ea, encode_imm_ea),
        instruction!(MASK_OUT_EA, OP_ADDI | LONG_SIZED, EA_DATA_ALTERABLE, Size::Long, "ADDI", decode_imm_ea, is_imm_ea, encode_imm_ea),
    ]
}

#[cfg(test)]
mod tests {
    use memory::{MemoryVec, Memory};
    use assembler::{Assembler, encode_instruction};
    use disassembler::{disassemble, disassemble_first};
    use super::Exception;

    #[test]
    fn roundtrips_from_opcode() {
        let opcode = 0xd511;
        let mut mem = &mut MemoryVec::new16(0, vec![opcode]);
        let asm = {
            let inst = disassemble_first(mem);
            format!(" {}", inst)
        };
        let pc = 0;
        let a = Assembler::new();
        let inst = a.parse_assembler(asm.as_str());
        let new_pc = encode_instruction(asm.as_str(), &inst, pc, mem);
        assert_eq!(2, new_pc);
        assert_eq!(opcode, mem.read_word(pc));
    }
    #[test]
    fn roundtrips_from_asm() {
        let mut mem = &mut MemoryVec::new();
        let pc = 0;
        let asm = " ADD.B\tD2,(A1)";
        let a = Assembler::new();
        let inst = a.parse_assembler(asm);
        encode_instruction(asm, &inst, pc, mem);
        let inst = disassemble_first(mem);

        assert_eq!(asm, format!(" {}", inst));
    }

    #[test]
    #[ignore]
    fn roundtrips() {
        let a = Assembler::new();
        for opcode in 0x0000..0xffff {
            let pc = 0;
            let extension_word_mask = 0b1111_1000_1111_1111;
            // bits 8-10 should always be zero in the ea extension word
            // as we don't know which word will be seen as the ea extension word
            // (as opposed to immediate operand values) just make sure these aren't set.
            let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x001f, 0x00a4, 0x1234 & extension_word_mask, 0x5678 & extension_word_mask]);
            match disassemble(pc, dasm_mem) {
                Err(Exception::IllegalInstruction(opcode, _)) => println!("{:04x}:\t\tinvalid", opcode),
                Ok(inst) => {
                    let asm = format!("{}", inst);
                    let inst = a.parse_assembler(asm.as_str());
                    let mut asm_mem = &mut MemoryVec::new();
                    let new_pc = encode_instruction(asm.as_str(), &inst, pc, asm_mem);
                    assert_eq!(inst.length()*2, new_pc);
                    let new_opcode = asm_mem.read_word(pc);
                    if opcode != new_opcode {
                        panic!("{:04x} | {:04x}: {}", opcode, new_opcode, asm);
                    } else {
                        println!("{:04x}: {}", opcode, asm);
                    }
                    if inst.length() > 1 {
                        let old_ex1 = dasm_mem.read_word(pc+2);
                        let new_ex1 = asm_mem.read_word(pc+2);
                        if old_ex1 != new_ex1 {println!("ew1")};
                        assert_eq!(old_ex1, new_ex1);
                    };
                    if inst.length() > 2 {
                        let old_ex2 = dasm_mem.read_word(pc+4);
                        let new_ex2 = asm_mem.read_word(pc+4);
                        if old_ex2 != new_ex2 {println!("ew2")};
                        assert_eq!(old_ex2, new_ex2);
                    };
                    if inst.length() > 3 {
                        let old_ex3 = dasm_mem.read_word(pc+6);
                        let new_ex3 = asm_mem.read_word(pc+6);
                        if old_ex3 != new_ex3 {println!("ew3")};
                        assert_eq!(old_ex3, new_ex3);
                    };
                }
            }
        }
    }
}<commit_msg>Increase recursion_limit for impl_rdp! to 160<commit_after>#![recursion_limit = "160"] // 150 was too low in rust 1.15
use std::result;
mod operand;
use operand::Operand;
extern crate r68k_common;
use r68k_common::constants::*;
mod constants;
use constants::*;
#[macro_use]
extern crate pest;

pub mod memory;
pub mod assembler;
pub mod disassembler;
pub mod srecords;

use memory::Memory;

// type alias for exception handling
pub type Result<T> = result::Result<T, Exception>;
type OperandDecoder = fn(u16, Size, u32, &Memory) -> Vec<Operand>;
type InstructionEncoder = fn(&OpcodeInstance, u16, u32, &mut Memory) -> u32;
type InstructionSelector = fn(&OpcodeInstance) -> bool;

#[derive(Debug)]
pub enum Exception {
     IllegalInstruction(u16, u32), // ir, pc
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Size {
	Unsized, Byte, Word, Long
}

impl fmt::Display for Size {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Size::Unsized => write!(f, ""),
            Size::Byte => write!(f, ".B"),
            Size::Word => write!(f, ".W"),
            Size::Long => write!(f, ".L"),
        }
    }
}

// #[derive(Clone, Copy)]
pub struct OpcodeInfo<'a> {
    mask: u32,
    matching: u32,
    ea_mask: u16,
    size: Size,
    decoder: OperandDecoder,
    mnemonic: &'a str,
    encoder: InstructionEncoder,
    selector: InstructionSelector,
}
#[derive(Debug, PartialEq)]
pub struct OpcodeInstance<'a> {
    mnemonic: &'a str,
    size: Size,
	operands: Vec<Operand>,
}

use std::fmt;
impl<'a> fmt::Debug for OpcodeInfo<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            _ => write!(f, "[some fn]"),
        }
    }
}
impl<'a> fmt::Display for OpcodeInstance<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.operands.len() {
            0 => write!(f, "{}{}", self.mnemonic, self.size),
            1 => write!(f, "{}{}\t{}", self.mnemonic, self.size, self.operands[0]),
            2 => write!(f, "{}{}\t{},{}", self.mnemonic, self.size, self.operands[0], self.operands[1]),
            _ => panic!("more than two operands {:?}", self)
        }
    }
}
impl<'a> OpcodeInstance<'a> {
    pub fn length(&self) -> u32 {
        1 + self.operands.iter().map(|op| op.extension_words()).fold(0, |i,j|i+j)
    }
}
macro_rules! instruction {
    ($mask:expr, $matching:expr, $ea_mask:expr, $size:expr, $mnemonic:expr, $decoder:ident) => (OpcodeInfo { mask: $mask, matching: $matching, size: $size, mnemonic: $mnemonic, decoder: disassembler::$decoder, encoder: assembler::nop_encoder, selector: assembler::nop_selector, ea_mask: $ea_mask});
    ($mask:expr, $matching:expr, $ea_mask:expr, $size:expr, $mnemonic:expr, $decoder:ident, $selector:ident, $encoder:ident) => (OpcodeInfo { mask: $mask, matching: $matching, size: $size, mnemonic: $mnemonic, decoder: disassembler::$decoder, encoder: assembler::$encoder, selector: assembler::$selector, ea_mask: $ea_mask})
}
fn generate<'a>() -> Vec<OpcodeInfo<'a>> {
    vec![
        instruction!(MASK_OUT_X_EA, OP_ADD | BYTE_SIZED | DEST_EA, EA_MEMORY_ALTERABLE, Size::Byte, "ADD", decode_dx_ea, is_dx_ea, encode_dx_ea),
        instruction!(MASK_OUT_X_EA, OP_ADD | BYTE_SIZED | DEST_DX, EA_ALL_EXCEPT_AN, Size::Byte, "ADD", decode_ea_dx, is_ea_dx, encode_ea_dx),
        instruction!(MASK_OUT_X_EA, OP_ADD | WORD_SIZED | DEST_EA, EA_MEMORY_ALTERABLE, Size::Word, "ADD", decode_dx_ea, is_dx_ea, encode_dx_ea),
        instruction!(MASK_OUT_X_EA, OP_ADD | WORD_SIZED | DEST_DX, EA_ALL, Size::Word, "ADD", decode_ea_dx, is_ea_dx, encode_ea_dx),
        instruction!(MASK_OUT_X_EA, OP_ADD | LONG_SIZED | DEST_EA, EA_MEMORY_ALTERABLE, Size::Long, "ADD", decode_dx_ea, is_dx_ea, encode_dx_ea),
        instruction!(MASK_OUT_X_EA, OP_ADD | LONG_SIZED | DEST_DX, EA_ALL, Size::Long, "ADD", decode_ea_dx, is_ea_dx, encode_ea_dx),
        instruction!(MASK_OUT_X_EA, OP_ADD | DEST_AX_WORD, EA_ALL, Size::Word, "ADDA", decode_ea_ax, is_ea_ax, encode_ea_ax),
        instruction!(MASK_OUT_X_EA, OP_ADD | DEST_AX_LONG, EA_ALL, Size::Long, "ADDA", decode_ea_ax, is_ea_ax, encode_ea_ax),
        instruction!(MASK_OUT_EA, OP_ADDI | BYTE_SIZED, EA_DATA_ALTERABLE, Size::Byte, "ADDI", decode_imm_ea, is_imm_ea, encode_imm_ea),
        instruction!(MASK_OUT_EA, OP_ADDI | WORD_SIZED, EA_DATA_ALTERABLE, Size::Word, "ADDI", decode_imm_ea, is_imm_ea, encode_imm_ea),
        instruction!(MASK_OUT_EA, OP_ADDI | LONG_SIZED, EA_DATA_ALTERABLE, Size::Long, "ADDI", decode_imm_ea, is_imm_ea, encode_imm_ea),
    ]
}

#[cfg(test)]
mod tests {
    use memory::{MemoryVec, Memory};
    use assembler::{Assembler, encode_instruction};
    use disassembler::{disassemble, disassemble_first};
    use super::Exception;

    #[test]
    fn roundtrips_from_opcode() {
        let opcode = 0xd511;
        let mut mem = &mut MemoryVec::new16(0, vec![opcode]);
        let asm = {
            let inst = disassemble_first(mem);
            format!(" {}", inst)
        };
        let pc = 0;
        let a = Assembler::new();
        let inst = a.parse_assembler(asm.as_str());
        let new_pc = encode_instruction(asm.as_str(), &inst, pc, mem);
        assert_eq!(2, new_pc);
        assert_eq!(opcode, mem.read_word(pc));
    }
    #[test]
    fn roundtrips_from_asm() {
        let mut mem = &mut MemoryVec::new();
        let pc = 0;
        let asm = " ADD.B\tD2,(A1)";
        let a = Assembler::new();
        let inst = a.parse_assembler(asm);
        encode_instruction(asm, &inst, pc, mem);
        let inst = disassemble_first(mem);

        assert_eq!(asm, format!(" {}", inst));
    }

    #[test]
    #[ignore]
    fn roundtrips() {
        let a = Assembler::new();
        for opcode in 0x0000..0xffff {
            let pc = 0;
            let extension_word_mask = 0b1111_1000_1111_1111;
            // bits 8-10 should always be zero in the ea extension word
            // as we don't know which word will be seen as the ea extension word
            // (as opposed to immediate operand values) just make sure these aren't set.
            let dasm_mem = &mut MemoryVec::new16(0, vec![opcode, 0x001f, 0x00a4, 0x1234 & extension_word_mask, 0x5678 & extension_word_mask]);
            match disassemble(pc, dasm_mem) {
                Err(Exception::IllegalInstruction(opcode, _)) => println!("{:04x}:\t\tinvalid", opcode),
                Ok(inst) => {
                    let asm = format!("{}", inst);
                    let inst = a.parse_assembler(asm.as_str());
                    let mut asm_mem = &mut MemoryVec::new();
                    let new_pc = encode_instruction(asm.as_str(), &inst, pc, asm_mem);
                    assert_eq!(inst.length()*2, new_pc);
                    let new_opcode = asm_mem.read_word(pc);
                    if opcode != new_opcode {
                        panic!("{:04x} | {:04x}: {}", opcode, new_opcode, asm);
                    } else {
                        println!("{:04x}: {}", opcode, asm);
                    }
                    if inst.length() > 1 {
                        let old_ex1 = dasm_mem.read_word(pc+2);
                        let new_ex1 = asm_mem.read_word(pc+2);
                        if old_ex1 != new_ex1 {println!("ew1")};
                        assert_eq!(old_ex1, new_ex1);
                    };
                    if inst.length() > 2 {
                        let old_ex2 = dasm_mem.read_word(pc+4);
                        let new_ex2 = asm_mem.read_word(pc+4);
                        if old_ex2 != new_ex2 {println!("ew2")};
                        assert_eq!(old_ex2, new_ex2);
                    };
                    if inst.length() > 3 {
                        let old_ex3 = dasm_mem.read_word(pc+6);
                        let new_ex3 = asm_mem.read_word(pc+6);
                        if old_ex3 != new_ex3 {println!("ew3")};
                        assert_eq!(old_ex3, new_ex3);
                    };
                }
            }
        }
    }
}<|endoftext|>


<commit_before>//! Set up resource content for game.

use brush::{Brush, Builder, Geom};
use cache;
use calx::Rgba;
use calx::color::*;
use euclid::vec2;
use std::collections::HashMap;
use std::rc::Rc;
use std::str::FromStr;
use vec_map::VecMap;
use vitral;

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn terrain_brushes() -> VecMap<Rc<Brush>> {
    use world::Terrain::*;
    let mut ret = VecMap::new();

    ret.insert(Empty as usize, Builder::new("assets/floors.png").tile(0, 0).finish());
    ret.insert(Gate as usize, Builder::new("assets/portals.png")
        .color(LIGHTCYAN)
        .tile(0, 0).merge()
        .tile(32, 0).merge()
        .tile(64, 0).merge()
        .tile(96, 0).merge()
        .tile(128, 0).merge()
        .tile(160, 0).merge()
        .tile(192, 0).merge()
        .tile(224, 0).merge()
        .tile(256, 0).merge()
        .tile(288, 0).merge()
        .tile(320, 0).merge()
        .tile(352, 0).merge()
        .tile(384, 0).finish());
    ret.insert(Ground as usize, Builder::new("assets/floors.png").color(SLATEGRAY).tile(32, 0).finish());
    ret.insert(Grass as usize, Builder::new("assets/floors.png").color(DARKGREEN).tile(32, 0).finish());
    ret.insert(Snow as usize, Builder::new("assets/floors.png").color(WHITE).tile(32, 0).finish());
    ret.insert(Sand as usize, Builder::new("assets/floors.png").color(YELLOW).tile(32, 0).finish());
    ret.insert(Water as usize, Builder::new("assets/floors.png").colors(MIDNIGHTBLUE, ROYALBLUE).tile(96, 0).finish());
    ret.insert(Shallows as usize, Builder::new("assets/floors.png").colors(STEELBLUE, ROYALBLUE).tile(96, 0).finish());
    ret.insert(Magma as usize, Builder::new("assets/floors.png").colors(YELLOW, DARKRED).tile(96, 0).finish());
    ret.insert(Tree as usize, Builder::new("assets/props.png")
        .color(SADDLEBROWN).tile(160, 64)
        .color(GREEN).tile(192, 64).finish());
    ret.insert(Wall as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 32, 0).finish());
    ret.insert(Rock as usize, Builder::new("assets/blobs.png").color(DARKGOLDENROD).blob(0, 0, 0, 32, 0, 160).finish());
    ret.insert(Door as usize, Builder::new("assets/walls.png")
               .color(SADDLEBROWN).wall(128, 0, 160, 0)
               .color(LIGHTSLATEGRAY).wall(0, 0, 96, 0).finish());
    ret.insert(OpenDoor as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 96, 0).finish());
    ret.insert(Window as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 64, 0).finish());
    ret.insert(Grass2 as usize, Builder::new("assets/floors.png").color(DARKGREEN).tile(64, 0).finish());

    ret
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn entity_brushes() -> VecMap<Rc<Brush>> {
    use world::Icon::*;
    let mut ret = VecMap::new();

    ret.insert(Player as usize, Builder::new("assets/mobs.png").color(AZURE).mob(0, 0).finish());
    ret.insert(Snake as usize, Builder::new("assets/mobs.png").color(GREEN).mob(1*32, 0).finish());
    ret.insert(Dreg as usize, Builder::new("assets/mobs.png").color(OLIVE).mob(2*32, 0).finish());
    ret.insert(Ogre as usize, Builder::new("assets/mobs.png").color(DARKCYAN).mob(3*32, 0).finish());
    ret.insert(Wraith as usize, Builder::new("assets/mobs.png").color(GRAY).mob(4*32, 0).finish());
    ret.insert(Octopus as usize, Builder::new("assets/mobs.png").color(WHEAT).mob(5*32, 0).finish());
    ret.insert(Bug as usize, Builder::new("assets/mobs.png").color(0xFF00FFFF).mob(6*32, 0).finish());
    ret.insert(Ooze as usize, Builder::new("assets/mobs.png").color(LIGHTSKYBLUE).mob(7*32, 0).finish());
    ret.insert(Efreet as usize, Builder::new("assets/mobs.png").color(ORANGE).mob(0, 1*32).finish());

    // The serpent has a special sprite structure where it's split to the head and mound parts,
    // and the mound part doesn't move during the idle animation.
    ret.insert(Serpent as usize, Builder::new("assets/mobs.png").color(CORAL)
               .splat(Some(Geom::new(16, 14, 1*32, 32, 32, 32))).tile(2*32, 32).merge()
               .tile(1*32, 32).tile(2*32, 32).merge()
               .finish());

    ret.insert(Sword as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(4*32, 1*32).finish());
    ret.insert(Helmet as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(5*32, 1*32).finish());
    ret.insert(Armor as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(2*32, 2*32).finish());

    ret.insert(Scroll1 as usize, Builder::new("assets/props.png").color(LIGHTYELLOW).tile(7*32, 2*32).finish());
    ret.insert(Wand1 as usize, Builder::new("assets/props.png").color(RED).tile(7*32, 1*32).finish());
    ret.insert(Wand2 as usize, Builder::new("assets/props.png").color(CYAN).tile(7*32, 1*32).finish());
    ret
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn misc_brushes() -> VecMap<Rc<Brush>> {
    use Icon::*;
    let mut ret = VecMap::new();

    ret.insert(SolidBlob as usize, Builder::new("assets/blobs.png").colors(BLACK, BLACK).blob(0, 64, 0, 96, 0, 128).finish());
    ret.insert(CursorTop as usize, Builder::new("assets/props.png").color(RED).tile(32, 0).finish());
    ret.insert(CursorBottom as usize, Builder::new("assets/props.png").color(RED).tile(0, 0).finish());
    ret.insert(Portal as usize, Builder::new("assets/props.png").color(Rgba::from_str("#fa08").unwrap()).tile(0, 0).finish());
    ret.insert(HealthPip as usize, Builder::new("assets/gui.png").color(LIMEGREEN).rect(0, 8, 4, 4).finish());
    ret.insert(DarkHealthPip as usize, Builder::new("assets/gui.png").color(DARKSLATEGRAY).rect(0, 8, 4, 4).finish());
    ret.insert(BlockedOffSectorCell as usize, Builder::new("assets/floors.png").color(LIGHTGRAY).tile(0, 32).finish());

    ret
}

pub fn font<I: Iterator<Item = char>>(
    name: String,
    data: &[u8],
    span: I,
) -> vitral::FontData<usize> {
    let glyphs = cache::ATLAS.with(|a| a.borrow_mut().load_tilesheet(name, data).unwrap());

    let mut glyphs = glyphs
        .into_iter()
        .map(|i| vitral::CharData {
            image: cache::get(&i),
            draw_offset: vec2(0.0, 0.0),
            advance: i.bounds.size.width as f32,
        })
        .collect::<Vec<_>>();

    assert!(!glyphs.is_empty());
    let font_height = glyphs[0].image.size.height as f32;

    glyphs.reverse();

    let mut chars = HashMap::new();
    for c in span {
        chars.insert(
            c,
            glyphs
                .pop()
                .expect("Not enough glyphs in font sheet for all chars"),
        );
    }

    vitral::FontData {
        chars: chars,
        height: font_height,
    }
}
<commit_msg>Consistent indenting<commit_after>//! Set up resource content for game.

use brush::{Brush, Builder, Geom};
use cache;
use calx::Rgba;
use calx::color::*;
use euclid::vec2;
use std::collections::HashMap;
use std::rc::Rc;
use std::str::FromStr;
use vec_map::VecMap;
use vitral;

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn terrain_brushes() -> VecMap<Rc<Brush>> {
    use world::Terrain::*;
    let mut ret = VecMap::new();

    ret.insert(Empty as usize, Builder::new("assets/floors.png").tile(0, 0).finish());
    ret.insert(Gate as usize, Builder::new("assets/portals.png")
        .color(LIGHTCYAN)
        .tile(0, 0).merge()
        .tile(32, 0).merge()
        .tile(64, 0).merge()
        .tile(96, 0).merge()
        .tile(128, 0).merge()
        .tile(160, 0).merge()
        .tile(192, 0).merge()
        .tile(224, 0).merge()
        .tile(256, 0).merge()
        .tile(288, 0).merge()
        .tile(320, 0).merge()
        .tile(352, 0).merge()
        .tile(384, 0).finish());
    ret.insert(Ground as usize, Builder::new("assets/floors.png").color(SLATEGRAY).tile(32, 0).finish());
    ret.insert(Grass as usize, Builder::new("assets/floors.png").color(DARKGREEN).tile(32, 0).finish());
    ret.insert(Snow as usize, Builder::new("assets/floors.png").color(WHITE).tile(32, 0).finish());
    ret.insert(Sand as usize, Builder::new("assets/floors.png").color(YELLOW).tile(32, 0).finish());
    ret.insert(Water as usize, Builder::new("assets/floors.png").colors(MIDNIGHTBLUE, ROYALBLUE).tile(96, 0).finish());
    ret.insert(Shallows as usize, Builder::new("assets/floors.png").colors(STEELBLUE, ROYALBLUE).tile(96, 0).finish());
    ret.insert(Magma as usize, Builder::new("assets/floors.png").colors(YELLOW, DARKRED).tile(96, 0).finish());
    ret.insert(Tree as usize, Builder::new("assets/props.png")
        .color(SADDLEBROWN).tile(160, 64)
        .color(GREEN).tile(192, 64).finish());
    ret.insert(Wall as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 32, 0).finish());
    ret.insert(Rock as usize, Builder::new("assets/blobs.png").color(DARKGOLDENROD).blob(0, 0, 0, 32, 0, 160).finish());
    ret.insert(Door as usize, Builder::new("assets/walls.png")
        .color(SADDLEBROWN).wall(128, 0, 160, 0)
        .color(LIGHTSLATEGRAY).wall(0, 0, 96, 0).finish());
    ret.insert(OpenDoor as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 96, 0).finish());
    ret.insert(Window as usize, Builder::new("assets/walls.png").color(LIGHTSLATEGRAY).wall(0, 0, 64, 0).finish());
    ret.insert(Grass2 as usize, Builder::new("assets/floors.png").color(DARKGREEN).tile(64, 0).finish());

    ret
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn entity_brushes() -> VecMap<Rc<Brush>> {
    use world::Icon::*;
    let mut ret = VecMap::new();

    ret.insert(Player as usize, Builder::new("assets/mobs.png").color(AZURE).mob(0, 0).finish());
    ret.insert(Snake as usize, Builder::new("assets/mobs.png").color(GREEN).mob(1*32, 0).finish());
    ret.insert(Dreg as usize, Builder::new("assets/mobs.png").color(OLIVE).mob(2*32, 0).finish());
    ret.insert(Ogre as usize, Builder::new("assets/mobs.png").color(DARKCYAN).mob(3*32, 0).finish());
    ret.insert(Wraith as usize, Builder::new("assets/mobs.png").color(GRAY).mob(4*32, 0).finish());
    ret.insert(Octopus as usize, Builder::new("assets/mobs.png").color(WHEAT).mob(5*32, 0).finish());
    ret.insert(Bug as usize, Builder::new("assets/mobs.png").color(0xFF00FFFF).mob(6*32, 0).finish());
    ret.insert(Ooze as usize, Builder::new("assets/mobs.png").color(LIGHTSKYBLUE).mob(7*32, 0).finish());
    ret.insert(Efreet as usize, Builder::new("assets/mobs.png").color(ORANGE).mob(0, 1*32).finish());

    // The serpent has a special sprite structure where it's split to the head and mound parts,
    // and the mound part doesn't move during the idle animation.
    ret.insert(Serpent as usize, Builder::new("assets/mobs.png").color(CORAL)
        .splat(Some(Geom::new(16, 14, 1*32, 32, 32, 32))).tile(2*32, 32).merge()
        .tile(1*32, 32).tile(2*32, 32).merge()
        .finish());

    ret.insert(Sword as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(4*32, 1*32).finish());
    ret.insert(Helmet as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(5*32, 1*32).finish());
    ret.insert(Armor as usize, Builder::new("assets/props.png").color(LIGHTGRAY).tile(2*32, 2*32).finish());

    ret.insert(Scroll1 as usize, Builder::new("assets/props.png").color(LIGHTYELLOW).tile(7*32, 2*32).finish());
    ret.insert(Wand1 as usize, Builder::new("assets/props.png").color(RED).tile(7*32, 1*32).finish());
    ret.insert(Wand2 as usize, Builder::new("assets/props.png").color(CYAN).tile(7*32, 1*32).finish());
    ret
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn misc_brushes() -> VecMap<Rc<Brush>> {
    use Icon::*;
    let mut ret = VecMap::new();

    ret.insert(SolidBlob as usize, Builder::new("assets/blobs.png").colors(BLACK, BLACK).blob(0, 64, 0, 96, 0, 128).finish());
    ret.insert(CursorTop as usize, Builder::new("assets/props.png").color(RED).tile(32, 0).finish());
    ret.insert(CursorBottom as usize, Builder::new("assets/props.png").color(RED).tile(0, 0).finish());
    ret.insert(Portal as usize, Builder::new("assets/props.png").color(Rgba::from_str("#fa08").unwrap()).tile(0, 0).finish());
    ret.insert(HealthPip as usize, Builder::new("assets/gui.png").color(LIMEGREEN).rect(0, 8, 4, 4).finish());
    ret.insert(DarkHealthPip as usize, Builder::new("assets/gui.png").color(DARKSLATEGRAY).rect(0, 8, 4, 4).finish());
    ret.insert(BlockedOffSectorCell as usize, Builder::new("assets/floors.png").color(LIGHTGRAY).tile(0, 32).finish());

    ret
}

pub fn font<I: Iterator<Item = char>>(
    name: String,
    data: &[u8],
    span: I,
) -> vitral::FontData<usize> {
    let glyphs = cache::ATLAS.with(|a| a.borrow_mut().load_tilesheet(name, data).unwrap());

    let mut glyphs = glyphs
        .into_iter()
        .map(|i| vitral::CharData {
            image: cache::get(&i),
            draw_offset: vec2(0.0, 0.0),
            advance: i.bounds.size.width as f32,
        })
        .collect::<Vec<_>>();

    assert!(!glyphs.is_empty());
    let font_height = glyphs[0].image.size.height as f32;

    glyphs.reverse();

    let mut chars = HashMap::new();
    for c in span {
        chars.insert(
            c,
            glyphs
                .pop()
                .expect("Not enough glyphs in font sheet for all chars"),
        );
    }

    vitral::FontData {
        chars: chars,
        height: font_height,
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{self, Read};
use std::iter::Iterator;
use std::path::PathBuf;
use std::sync::mpsc::{self, Receiver};
use std::time::{Duration, Instant};

use notify::{self, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};

use super::*;

pub struct ShaderDirectoryWatcher {
    directory: PathBuf,
    _watcher: RecommendedWatcher,
    watcher_rx: Receiver<DebouncedEvent>,

    last_modification: Instant,
}
impl ShaderDirectoryWatcher {
    pub fn new<P>(directory: P) -> Result<Self, notify::Error>
    where
        PathBuf: From<P>,
    {
        let directory = PathBuf::from(directory);
        let (tx, watcher_rx) = mpsc::channel();
        let mut watcher = notify::watcher(tx, Duration::from_millis(50))?;
        watcher.watch(&directory, RecursiveMode::Recursive)?;

        Ok(Self {
            directory,
            _watcher: watcher,
            watcher_rx,
            last_modification: Instant::now(),
        })
    }

    fn detect_changes(&mut self) {
        while let Ok(event) = self.watcher_rx.try_recv() {
            if let DebouncedEvent::Write(_) = event {
                self.last_modification = Instant::now();
            }
        }
    }
}

fn concat_file_contents<'a, I: Iterator<Item = &'a PathBuf>>(filenames: I) -> io::Result<String> {
    let mut contents = String::new();
    for filename in filenames {
        File::open(filename)?.read_to_string(&mut contents)?;
    }
    Ok(contents)
}

pub struct ShaderSet {
    vertex: Option<Vec<u8>>,
    fragment: Option<Vec<u8>>,
    compute: Option<Vec<u8>>,

    vertex_filenames: Option<Vec<PathBuf>>,
    fragment_filenames: Option<Vec<PathBuf>>,
    compute_filenames: Option<Vec<PathBuf>>,
    last_update: Instant,
}
impl ShaderSet {
    pub fn simple(
        watcher: &mut ShaderDirectoryWatcher,
        vertex_source: ShaderSource,
        fragment_source: ShaderSource,
    ) -> Result<Self, failure::Error> {
        let vertex_filenames = vertex_source
            .filenames
            .unwrap()
            .into_iter()
            .map(|f| watcher.directory.join(f))
            .collect::<Vec<_>>();
        let fragment_filenames = fragment_source
            .filenames
            .unwrap()
            .into_iter()
            .map(|f| watcher.directory.join(f))
            .collect::<Vec<_>>();
        let vertex = create_vertex_shader(&concat_file_contents(vertex_filenames.iter())?)?;
        let fragment = create_fragment_shader(&concat_file_contents(fragment_filenames.iter())?)?;

        Ok(Self {
            vertex: Some(vertex),
            fragment: Some(fragment),
            compute: None,
            last_update: Instant::now(),
            vertex_filenames: Some(vertex_filenames),
            fragment_filenames: Some(fragment_filenames),
            compute_filenames: None,
        })
    }

    pub fn compute_only(
        watcher: &mut ShaderDirectoryWatcher,
        compute_source: ShaderSource,
    ) -> Result<Self, failure::Error> {
        let compute_filenames = compute_source
            .filenames
            .unwrap()
            .into_iter()
            .map(|f| watcher.directory.join(f))
            .collect::<Vec<_>>();
        let compute = create_compute_shader(&concat_file_contents(compute_filenames.iter())?)?;

        Ok(Self {
            vertex: None,
            fragment: None,
            compute: Some(compute),
            last_update: Instant::now(),
            vertex_filenames: None,
            fragment_filenames: None,
            compute_filenames: Some(compute_filenames),
        })
    }

    /// Refreshes the shader if necessary. Returns whether a refresh happened.
    pub fn refresh(&mut self, directory_watcher: &mut ShaderDirectoryWatcher) -> bool {
        directory_watcher.detect_changes();
        if directory_watcher.last_modification > self.last_update {
            self.last_update = Instant::now();

            let new_shaders  = || -> Result<_, failure::Error> {
                let (mut vs, mut fs, mut cs) = (None, None, None);
                if let Some(ref s) = self.vertex_filenames {
                    vs = Some(create_vertex_shader(&concat_file_contents(s.iter())?)?);
                }
                if let Some(ref s) = self.fragment_filenames {
                    fs = Some(create_fragment_shader(&concat_file_contents(s.iter())?)?);
                }
                if let Some(ref s) = self.compute_filenames {
                    cs = Some(create_compute_shader(&concat_file_contents(s.iter())?)?);
                }
                Ok((vs, fs, cs))
            } ();

            if let Ok((vs, fs, cs)) = new_shaders {
                self.vertex = vs;
                self.fragment = fs;
                self.compute = cs;
                return true;
            }
        }
        false
    }

    pub fn vertex(&self) -> &[u8] {
        self.vertex.as_ref().unwrap()
    }
    pub fn fragment(&self) -> &[u8] {
        self.fragment.as_ref().unwrap()
    }
    pub fn compute(&self) -> &[u8] {
        self.compute.as_ref().unwrap()
    }
}
<commit_msg>Only refresh shaders that have changed<commit_after>use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{self, Read};
use std::iter::Iterator;
use std::path::PathBuf;
use std::sync::mpsc::{self, Receiver};
use std::time::{Duration, Instant};

use notify::{self, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};

use super::*;

pub struct ShaderDirectoryWatcher {
    directory: PathBuf,
    _watcher: RecommendedWatcher,
    watcher_rx: Receiver<DebouncedEvent>,

    last_modifications: HashMap<PathBuf, Instant>,
}
impl ShaderDirectoryWatcher {
    pub fn new<P>(directory: P) -> Result<Self, notify::Error>
    where
        PathBuf: From<P>,
    {
        let directory = PathBuf::from(directory);
        let (tx, watcher_rx) = mpsc::channel();
        let mut watcher = notify::watcher(tx, Duration::from_millis(50))?;
        watcher.watch(&directory, RecursiveMode::Recursive)?;

        Ok(Self { directory, _watcher: watcher, watcher_rx, last_modifications: HashMap::new() })
    }

    fn detect_changes(&mut self) {
        while let Ok(event) = self.watcher_rx.try_recv() {
            if let DebouncedEvent::Write(p) = event {
                self.last_modifications.insert(p, Instant::now());
            }
        }
    }
}

fn concat_file_contents<'a, I: Iterator<Item = &'a PathBuf>>(filenames: I) -> io::Result<String> {
    let mut contents = String::new();
    for filename in filenames {
        File::open(filename)?.read_to_string(&mut contents)?;
    }
    Ok(contents)
}

pub struct ShaderSet {
    vertex: Option<Vec<u8>>,
    fragment: Option<Vec<u8>>,
    compute: Option<Vec<u8>>,

    vertex_filenames: Vec<PathBuf>,
    fragment_filenames: Vec<PathBuf>,
    compute_filenames: Vec<PathBuf>,
    last_update: Instant,
}
impl ShaderSet {
    pub fn simple(
        watcher: &mut ShaderDirectoryWatcher,
        vertex_source: ShaderSource,
        fragment_source: ShaderSource,
    ) -> Result<Self, failure::Error> {
        let vertex_filenames = vertex_source
            .filenames
            .unwrap()
            .into_iter()
            .map(|f| fs::canonicalize(watcher.directory.join(f)).unwrap())
            .collect::<Vec<_>>();
        let fragment_filenames = fragment_source
            .filenames
            .unwrap()
            .into_iter()
            .map(|f| fs::canonicalize(watcher.directory.join(f)).unwrap())
            .collect::<Vec<_>>();
        let vertex = create_vertex_shader(&concat_file_contents(vertex_filenames.iter())?)?;
        let fragment = create_fragment_shader(&concat_file_contents(fragment_filenames.iter())?)?;

        Ok(Self {
            vertex: Some(vertex),
            fragment: Some(fragment),
            compute: None,
            last_update: Instant::now(),
            vertex_filenames: vertex_filenames,
            fragment_filenames: fragment_filenames,
            compute_filenames: Vec::new(),
        })
    }

    pub fn compute_only(
        watcher: &mut ShaderDirectoryWatcher,
        compute_source: ShaderSource,
    ) -> Result<Self, failure::Error> {
        let compute_filenames = compute_source
            .filenames
            .unwrap()
            .into_iter()
            .map(|f| fs::canonicalize(watcher.directory.join(f)).unwrap())
            .collect::<Vec<_>>();
        let compute = create_compute_shader(&concat_file_contents(compute_filenames.iter())?)?;

        Ok(Self {
            vertex: None,
            fragment: None,
            compute: Some(compute),
            last_update: Instant::now(),
            vertex_filenames: Vec::new(),
            fragment_filenames: Vec::new(),
            compute_filenames: compute_filenames,
        })
    }

    /// Refreshes the shader if necessary. Returns whether a refresh happened.
    pub fn refresh(&mut self, directory_watcher: &mut ShaderDirectoryWatcher) -> bool {
        directory_watcher.detect_changes();

        let needs_update = self
            .vertex_filenames
            .iter()
            .chain(self.fragment_filenames.iter())
            .chain(self.compute_filenames.iter())
            .filter_map(|n| directory_watcher.last_modifications.get(n))
            .any(|&t| t > self.last_update);

        if needs_update {
            self.last_update = Instant::now();

            let new_shaders = || -> Result<_, failure::Error> {
                let (mut vs, mut fs, mut cs) = (None, None, None);
                if !self.vertex_filenames.is_empty() {
                    vs = Some(create_vertex_shader(&concat_file_contents(
                        self.vertex_filenames.iter(),
                    )?)?);
                }
                if !self.fragment_filenames.is_empty() {
                    fs = Some(create_fragment_shader(&concat_file_contents(
                        self.fragment_filenames.iter(),
                    )?)?);
                }
                if !self.compute_filenames.is_empty() {
                    cs = Some(create_compute_shader(&concat_file_contents(
                        self.compute_filenames.iter(),
                    )?)?);
                }
                Ok((vs, fs, cs))
            }();

            if let Ok((vs, fs, cs)) = new_shaders {
                self.vertex = vs;
                self.fragment = fs;
                self.compute = cs;
                return true;
            }
        }
        false
    }

    pub fn vertex(&self) -> &[u8] {
        self.vertex.as_ref().unwrap()
    }
    pub fn fragment(&self) -> &[u8] {
        self.fragment.as_ref().unwrap()
    }
    pub fn compute(&self) -> &[u8] {
        self.compute.as_ref().unwrap()
    }
}
<|endoftext|>


<commit_before>use pnet::packet::ipv4::{Ipv4Packet, Ipv4Flags};
use serde_json::{Value, Map, Number};

pub struct Ipv4Header {
	version: Number,
	ihl: Number,
	dscp: Number,
	ecn: Number,
	total_length: Number,
	identification: Number,
	flags: Value,
	fragment_offset: Number,
	ttl: Number,
	next_level_protocol: String,
	checksum: Number,
	source: String,
	destination: String,
}

impl Ipv4Header {
	pub fn new(p: &Ipv4Packet) -> Ipv4Header {
		let flags_number = p.get_flags();
		let mut flags: Vec<&str> = Vec::new();

		if (flags_number & Ipv4Flags::DontFragment) == Ipv4Flags::DontFragment {
			flags.push("DF");
		}
		if (flags_number & Ipv4Flags::MoreFragments) == Ipv4Flags::MoreFragments {
			flags.push("MF");
		}

		Ipv4Header {
			version: Number::from(p.get_version()),
			ihl: Number::from(p.get_header_length()),
			dscp: Number::from(p.get_dscp()),
			ecn: Number::from(p.get_ecn()),
			total_length: Number::from(p.get_total_length()),
			identification: Number::from(p.get_identification()),
			flags: Value::from(flags),
			//flags: Number::from(p.get_flags()),
			fragment_offset: Number::from(p.get_fragment_offset()),
			ttl: Number::from(p.get_ttl()),
			next_level_protocol: p.get_next_level_protocol().to_string().to_lowercase(),
			checksum: Number::from(p.get_checksum()),
			source: p.get_source().to_string(),
			destination: p.get_destination().to_string(),
		}
	}

	pub fn to_json_map(&self) -> Map<String, Value> {
		let mut header = Map::new();

    	header.insert("version".to_string(), Value::Number(self.version.clone()));
    	header.insert("ihl".to_string(), Value::Number(self.ihl.clone()));
    	header.insert("dscp".to_string(), Value::Number(self.dscp.clone()));
    	header.insert("ecn".to_string(), Value::Number(self.ecn.clone()));
    	header.insert("total_length".to_string(), Value::Number(self.total_length.clone()));
    	header.insert("identification".to_string(), Value::Number(self.identification.clone()));
		header.insert("flags".to_string(), self.flags.clone());
    	//header.insert("flags.".to_string(), Value::Number(self.flags.clone()));
    	header.insert("fragment_offset".to_string(), Value::Number(self.fragment_offset.clone()));
    	header.insert("ttl".to_string(), Value::Number(self.ttl.clone()));
    	header.insert("protocol".to_string(), Value::String(self.next_level_protocol.clone()));
    	header.insert("checksum".to_string(), Value::Number(self.checksum.clone()));
    	header.insert("source_address".to_string(), Value::String(self.source.clone()));
    	header.insert("destination_address".to_string(), Value::String(self.destination.clone()));

		header
	}
}<commit_msg>Remove comments<commit_after>use pnet::packet::ipv4::{Ipv4Packet, Ipv4Flags};
use serde_json::{Value, Map, Number};

pub struct Ipv4Header {
	version: Number,
	ihl: Number,
	dscp: Number,
	ecn: Number,
	total_length: Number,
	identification: Number,
	flags: Value,
	fragment_offset: Number,
	ttl: Number,
	next_level_protocol: String,
	checksum: Number,
	source: String,
	destination: String,
}

impl Ipv4Header {
	pub fn new(p: &Ipv4Packet) -> Ipv4Header {
		let flags_number = p.get_flags();
		let mut flags: Vec<&str> = Vec::new();

		if (flags_number & Ipv4Flags::DontFragment) == Ipv4Flags::DontFragment {
			flags.push("DF");
		}
		if (flags_number & Ipv4Flags::MoreFragments) == Ipv4Flags::MoreFragments {
			flags.push("MF");
		}

		Ipv4Header {
			version: Number::from(p.get_version()),
			ihl: Number::from(p.get_header_length()),
			dscp: Number::from(p.get_dscp()),
			ecn: Number::from(p.get_ecn()),
			total_length: Number::from(p.get_total_length()),
			identification: Number::from(p.get_identification()),
			flags: Value::from(flags),
			fragment_offset: Number::from(p.get_fragment_offset()),
			ttl: Number::from(p.get_ttl()),
			next_level_protocol: p.get_next_level_protocol().to_string().to_lowercase(),
			checksum: Number::from(p.get_checksum()),
			source: p.get_source().to_string(),
			destination: p.get_destination().to_string(),
		}
	}

	pub fn to_json_map(&self) -> Map<String, Value> {
		let mut header = Map::new();

    	header.insert("version".to_string(), Value::Number(self.version.clone()));
    	header.insert("ihl".to_string(), Value::Number(self.ihl.clone()));
    	header.insert("dscp".to_string(), Value::Number(self.dscp.clone()));
    	header.insert("ecn".to_string(), Value::Number(self.ecn.clone()));
    	header.insert("total_length".to_string(), Value::Number(self.total_length.clone()));
    	header.insert("identification".to_string(), Value::Number(self.identification.clone()));
		header.insert("flags".to_string(), self.flags.clone());
    	header.insert("fragment_offset".to_string(), Value::Number(self.fragment_offset.clone()));
    	header.insert("ttl".to_string(), Value::Number(self.ttl.clone()));
    	header.insert("protocol".to_string(), Value::String(self.next_level_protocol.clone()));
    	header.insert("checksum".to_string(), Value::Number(self.checksum.clone()));
    	header.insert("source_address".to_string(), Value::String(self.source.clone()));
    	header.insert("destination_address".to_string(), Value::String(self.destination.clone()));

		header
	}
}<|endoftext|>


<commit_before>//! # Unfinished features
//!
//! - **3.7**: Nonblocking mode:
//!   - Completion, `MPI_Waitany()`, `MPI_Waitall()`, `MPI_Waitsome()`,
//!   `MPI_Testany()`, `MPI_Testall()`, `MPI_Testsome()`, `MPI_Request_get_status()`
//! - **3.8**:
//!   - Cancellation, `MPI_Cancel()`, `MPI_Test_cancelled()`

use std::mem;
use std::marker::PhantomData;

use libc::c_int;

use ffi;
use ffi::{MPI_Request, MPI_Status};

use datatype::traits::*;
use point_to_point::{Status};
use raw::traits::*;

pub mod traits;

/// A request for a non-blocking operation
pub trait Request: AsRaw<Raw = MPI_Request> + AsRawMut {
    /// Returns true for a null request handle.
    fn is_null(&self) -> bool {
        unsafe {
            self.as_raw() == ffi::RSMPI_REQUEST_NULL
        }
    }

    /// Wait for an operation to finish.
    ///
    /// Will block execution of the calling thread until the associated operation has finished.
    ///
    /// # Examples
    ///
    /// See `examples/immediate.rs`
    ///
    /// # Standard section(s)
    ///
    /// 3.7.3
    fn wait(mut self) -> Status where Self: Sized {
        let mut status: MPI_Status = unsafe { mem::uninitialized() };
        unsafe {
            ffi::MPI_Wait(self.as_raw_mut(), &mut status);
        }
        assert!(self.is_null());
        mem::forget(self);
        Status::from_raw(status)
    }

    /// Test whether an operation has finished.
    ///
    /// If the operation has finished returns the `Status` otherwise returns the unfinished
    /// `Request`.
    /// # Examples
    ///
    /// See `examples/immediate.rs`
    ///
    /// # Standard section(s)
    ///
    /// 3.7.3
    fn test(mut self) -> Result<Status, Self> where Self: Sized {
        let mut status: MPI_Status = unsafe { mem::uninitialized() };
        let mut flag: c_int = 0;
        unsafe {
            ffi::MPI_Test(self.as_raw_mut(), &mut flag, &mut status);
        }
        assert!(flag == 0 || self.is_null());
        if flag != 0 {
            mem::forget(self);
            Result::Ok(Status::from_raw(status))
        } else {
            Result::Err(self)
        }
    }

    /// Cancel an operation.
    ///
    /// # Examples
    ///
    /// See `examples/immediate.rs`
    ///
    /// # Standard section(s)
    ///
    /// 3.8.4
    fn cancel(mut self) where Self: Sized {
        unsafe {
            ffi::MPI_Cancel(self.as_raw_mut());
            ffi::MPI_Request_free(self.as_raw_mut());
        }
        assert!(self.is_null());
        mem::forget(self);
    }
}

/// A request object for an non-blocking operation that holds no references
///
/// # Examples
///
/// See `examples/immediate_barrier.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct PlainRequest(MPI_Request);

impl PlainRequest {
    /// Construct a request object from the raw MPI type
    pub fn from_raw(request: MPI_Request) -> PlainRequest {
        PlainRequest(request)
    }
}

impl AsRaw for PlainRequest {
    type Raw = MPI_Request;
    unsafe fn as_raw(&self) -> Self::Raw { self.0 }
}

impl AsRawMut for PlainRequest {
    unsafe fn as_raw_mut(&mut self) -> *mut <Self as AsRaw>::Raw { &mut (self.0) }
}

impl Request for PlainRequest { }

impl Drop for PlainRequest {
    fn drop(&mut self) {
        assert!(self.is_null(), "request dropped without ascertaining completion.");
    }
}

/// A request object for a non-blocking operation that holds a reference to an immutable buffer
///
/// # Examples
///
/// See `examples/immediate.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct ReadRequest<'b, Buf: 'b + Buffer + ?Sized>(MPI_Request, PhantomData<&'b Buf>);

impl<'b, Buf: 'b + Buffer + ?Sized> ReadRequest<'b, Buf> {
    /// Construct a request object from the raw MPI type
    pub fn from_raw(request: MPI_Request, _: &'b Buf) -> ReadRequest<'b, Buf> {
        ReadRequest(request, PhantomData)
    }
}

impl<'b, Buf: 'b + Buffer + ?Sized> AsRaw for ReadRequest<'b, Buf> {
    type Raw = MPI_Request;
    unsafe fn as_raw(&self) -> Self::Raw { self.0 }
}

impl<'b, Buf: 'b + Buffer + ?Sized> AsRawMut for ReadRequest<'b, Buf> {
    unsafe fn as_raw_mut(&mut self) -> *mut <Self as AsRaw>::Raw { &mut (self.0) }
}

impl<'b, Buf: 'b + Buffer + ?Sized> Request for ReadRequest<'b, Buf> { }

impl<'b, Buf: 'b + Buffer + ?Sized> Drop for ReadRequest<'b, Buf> {
    fn drop(&mut self) {
        assert!(self.is_null(), "read request dropped without ascertaining completion.");
    }
}

/// A request object for a non-blocking operation that holds a reference to a mutable buffer
///
/// # Examples
///
/// See `examples/immediate.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct WriteRequest<'b, Buf: 'b + BufferMut + ?Sized>(MPI_Request, PhantomData<&'b mut Buf>);

impl<'b, Buf: 'b + BufferMut + ?Sized> WriteRequest<'b, Buf> {
    /// Construct a request object from the raw MPI type
    pub fn from_raw(request: MPI_Request, _: &'b Buf) -> WriteRequest<'b, Buf> {
        WriteRequest(request, PhantomData)
    }
}

impl<'b, Buf: 'b + BufferMut + ?Sized> AsRaw for WriteRequest<'b, Buf> {
    type Raw = MPI_Request;
    unsafe fn as_raw(&self) -> Self::Raw { self.0 }
}

impl<'b, Buf: 'b + BufferMut + ?Sized> AsRawMut for WriteRequest<'b, Buf> {
    unsafe fn as_raw_mut(&mut self) -> *mut <Self as AsRaw>::Raw { &mut (self.0) }
}

impl<'b, Buf: 'b + BufferMut + ?Sized> Request for WriteRequest<'b, Buf> { }

impl<'b, Buf: 'b + BufferMut + ?Sized> Drop for WriteRequest<'b, Buf> {
    fn drop(&mut self) {
        assert!(self.is_null(), "write request dropped without ascertaining completion.");
    }
}

/// A request object for a non-blocking operation that holds a reference to a mutable and an
/// immutable buffer
///
/// # Examples
///
/// See `examples/immediate_gather.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct ReadWriteRequest<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized>(MPI_Request, PhantomData<&'s S>, PhantomData<&'r mut R>);

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> ReadWriteRequest<'s, 'r, S, R> {
    /// Construct a request object from the raw MPI type
    pub fn from_raw(request: MPI_Request, _: &'s S, _: &'r R) -> ReadWriteRequest<'s, 'r, S, R> {
        ReadWriteRequest(request, PhantomData, PhantomData)
    }
}

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> AsRaw for ReadWriteRequest<'s, 'r, S, R> {
    type Raw = MPI_Request;
    unsafe fn as_raw(&self) -> Self::Raw { self.0 }
}

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> AsRawMut for ReadWriteRequest<'s, 'r, S, R> {
    unsafe fn as_raw_mut(&mut self) -> *mut <Self as AsRaw>::Raw { &mut (self.0) }
}

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> Request for ReadWriteRequest<'s, 'r, S, R> { }

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> Drop for ReadWriteRequest<'s, 'r, S, R> {
    fn drop(&mut self) {
        assert!(self.is_null(), "read-write request dropped without ascertaining completion.");
    }
}

/// Guard object that waits for the completion of an operation when it is dropped
///
/// # Examples
///
/// See `examples/immediate.rs`
pub struct WaitGuard<Req: Request>(Option<Req>);

impl<Req: Request> Drop for WaitGuard<Req> {
    fn drop(&mut self) {
        self.0.take().map(|mut req| {
            unsafe {
                ffi::MPI_Wait(req.as_raw_mut(), ffi::RSMPI_STATUS_IGNORE);
            }
            assert!(req.is_null());
            mem::forget(req);
        });
    }
}

impl<Req: Request> From<Req> for WaitGuard<Req> {
    fn from(req: Req) -> WaitGuard<Req> {
        WaitGuard(Some(req))
    }
}

/// Guard object that cancels an operation when it is dropped
///
/// # Examples
///
/// See `examples/immediate.rs`
pub struct CancelGuard<Req: Request>(Option<Req>);

impl<Req: Request> Drop for CancelGuard<Req> {
    fn drop(&mut self) {
        self.0.take().map(|mut req| {
            unsafe {
                ffi::MPI_Cancel(req.as_raw_mut());
                ffi::MPI_Request_free(req.as_raw_mut());
            }
            assert!(req.is_null());
            mem::forget(req);
        });
    }
}

impl<Req: Request> From<Req> for CancelGuard<Req> {
    fn from(req: Req) -> CancelGuard<Req> {
        CancelGuard(Some(req))
    }
}
<commit_msg>Document request object module.<commit_after>//! Request objects for non-blocking operations
//!
//! Non-blocking operations such as `immediate_send()` return request objects that borrow any
//! buffers involved in the operation so as to ensure proper access restrictions. In order to
//! release the borrowed buffers from the request objects, a completion operation such as `wait()`
//! or `test()` must be used on the request object. To enforce this rule, the request objects
//! implement a `Drop` bomb which will `panic!()` when a request object is dropped.
//!
//! To handle request completion in a RAII style, requests can be wrapped in either `WaitGuard` or
//! `CancelGuard` which will follow the respective policy for completing the operation upon being
//! dropped instead of `panic!()`ing.
//!
//! # Unfinished features
//!
//! - **3.7**: Nonblocking mode:
//!   - Completion, `MPI_Waitany()`, `MPI_Waitall()`, `MPI_Waitsome()`,
//!   `MPI_Testany()`, `MPI_Testall()`, `MPI_Testsome()`, `MPI_Request_get_status()`
//! - **3.8**:
//!   - Cancellation, `MPI_Cancel()`, `MPI_Test_cancelled()`

use std::mem;
use std::marker::PhantomData;

use libc::c_int;

use ffi;
use ffi::{MPI_Request, MPI_Status};

use datatype::traits::*;
use point_to_point::{Status};
use raw::traits::*;

pub mod traits;

/// A request for a non-blocking operation
pub trait Request: AsRaw<Raw = MPI_Request> + AsRawMut {
    /// Returns true for a null request handle.
    fn is_null(&self) -> bool {
        unsafe {
            self.as_raw() == ffi::RSMPI_REQUEST_NULL
        }
    }

    /// Wait for an operation to finish.
    ///
    /// Will block execution of the calling thread until the associated operation has finished.
    ///
    /// # Examples
    ///
    /// See `examples/immediate.rs`
    ///
    /// # Standard section(s)
    ///
    /// 3.7.3
    fn wait(mut self) -> Status where Self: Sized {
        let mut status: MPI_Status = unsafe { mem::uninitialized() };
        unsafe {
            ffi::MPI_Wait(self.as_raw_mut(), &mut status);
        }
        assert!(self.is_null());
        mem::forget(self);
        Status::from_raw(status)
    }

    /// Test whether an operation has finished.
    ///
    /// If the operation has finished returns the `Status` otherwise returns the unfinished
    /// `Request`.
    /// # Examples
    ///
    /// See `examples/immediate.rs`
    ///
    /// # Standard section(s)
    ///
    /// 3.7.3
    fn test(mut self) -> Result<Status, Self> where Self: Sized {
        let mut status: MPI_Status = unsafe { mem::uninitialized() };
        let mut flag: c_int = 0;
        unsafe {
            ffi::MPI_Test(self.as_raw_mut(), &mut flag, &mut status);
        }
        assert!(flag == 0 || self.is_null());
        if flag != 0 {
            mem::forget(self);
            Result::Ok(Status::from_raw(status))
        } else {
            Result::Err(self)
        }
    }

    /// Cancel an operation.
    ///
    /// # Examples
    ///
    /// See `examples/immediate.rs`
    ///
    /// # Standard section(s)
    ///
    /// 3.8.4
    fn cancel(mut self) where Self: Sized {
        unsafe {
            ffi::MPI_Cancel(self.as_raw_mut());
            ffi::MPI_Request_free(self.as_raw_mut());
        }
        assert!(self.is_null());
        mem::forget(self);
    }
}

/// A request object for an non-blocking operation that holds no references
///
/// # Examples
///
/// See `examples/immediate_barrier.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct PlainRequest(MPI_Request);

impl PlainRequest {
    /// Construct a request object from the raw MPI type
    pub fn from_raw(request: MPI_Request) -> PlainRequest {
        PlainRequest(request)
    }
}

impl AsRaw for PlainRequest {
    type Raw = MPI_Request;
    unsafe fn as_raw(&self) -> Self::Raw { self.0 }
}

impl AsRawMut for PlainRequest {
    unsafe fn as_raw_mut(&mut self) -> *mut <Self as AsRaw>::Raw { &mut (self.0) }
}

impl Request for PlainRequest { }

impl Drop for PlainRequest {
    fn drop(&mut self) {
        assert!(self.is_null(), "request dropped without ascertaining completion.");
    }
}

/// A request object for a non-blocking operation that holds a reference to an immutable buffer
///
/// # Examples
///
/// See `examples/immediate.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct ReadRequest<'b, Buf: 'b + Buffer + ?Sized>(MPI_Request, PhantomData<&'b Buf>);

impl<'b, Buf: 'b + Buffer + ?Sized> ReadRequest<'b, Buf> {
    /// Construct a request object from the raw MPI type
    pub fn from_raw(request: MPI_Request, _: &'b Buf) -> ReadRequest<'b, Buf> {
        ReadRequest(request, PhantomData)
    }
}

impl<'b, Buf: 'b + Buffer + ?Sized> AsRaw for ReadRequest<'b, Buf> {
    type Raw = MPI_Request;
    unsafe fn as_raw(&self) -> Self::Raw { self.0 }
}

impl<'b, Buf: 'b + Buffer + ?Sized> AsRawMut for ReadRequest<'b, Buf> {
    unsafe fn as_raw_mut(&mut self) -> *mut <Self as AsRaw>::Raw { &mut (self.0) }
}

impl<'b, Buf: 'b + Buffer + ?Sized> Request for ReadRequest<'b, Buf> { }

impl<'b, Buf: 'b + Buffer + ?Sized> Drop for ReadRequest<'b, Buf> {
    fn drop(&mut self) {
        assert!(self.is_null(), "read request dropped without ascertaining completion.");
    }
}

/// A request object for a non-blocking operation that holds a reference to a mutable buffer
///
/// # Examples
///
/// See `examples/immediate.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct WriteRequest<'b, Buf: 'b + BufferMut + ?Sized>(MPI_Request, PhantomData<&'b mut Buf>);

impl<'b, Buf: 'b + BufferMut + ?Sized> WriteRequest<'b, Buf> {
    /// Construct a request object from the raw MPI type
    pub fn from_raw(request: MPI_Request, _: &'b Buf) -> WriteRequest<'b, Buf> {
        WriteRequest(request, PhantomData)
    }
}

impl<'b, Buf: 'b + BufferMut + ?Sized> AsRaw for WriteRequest<'b, Buf> {
    type Raw = MPI_Request;
    unsafe fn as_raw(&self) -> Self::Raw { self.0 }
}

impl<'b, Buf: 'b + BufferMut + ?Sized> AsRawMut for WriteRequest<'b, Buf> {
    unsafe fn as_raw_mut(&mut self) -> *mut <Self as AsRaw>::Raw { &mut (self.0) }
}

impl<'b, Buf: 'b + BufferMut + ?Sized> Request for WriteRequest<'b, Buf> { }

impl<'b, Buf: 'b + BufferMut + ?Sized> Drop for WriteRequest<'b, Buf> {
    fn drop(&mut self) {
        assert!(self.is_null(), "write request dropped without ascertaining completion.");
    }
}

/// A request object for a non-blocking operation that holds a reference to a mutable and an
/// immutable buffer
///
/// # Examples
///
/// See `examples/immediate_gather.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct ReadWriteRequest<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized>(MPI_Request, PhantomData<&'s S>, PhantomData<&'r mut R>);

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> ReadWriteRequest<'s, 'r, S, R> {
    /// Construct a request object from the raw MPI type
    pub fn from_raw(request: MPI_Request, _: &'s S, _: &'r R) -> ReadWriteRequest<'s, 'r, S, R> {
        ReadWriteRequest(request, PhantomData, PhantomData)
    }
}

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> AsRaw for ReadWriteRequest<'s, 'r, S, R> {
    type Raw = MPI_Request;
    unsafe fn as_raw(&self) -> Self::Raw { self.0 }
}

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> AsRawMut for ReadWriteRequest<'s, 'r, S, R> {
    unsafe fn as_raw_mut(&mut self) -> *mut <Self as AsRaw>::Raw { &mut (self.0) }
}

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> Request for ReadWriteRequest<'s, 'r, S, R> { }

impl<'s, 'r, S: 's + Buffer + ?Sized, R: 'r + BufferMut + ?Sized> Drop for ReadWriteRequest<'s, 'r, S, R> {
    fn drop(&mut self) {
        assert!(self.is_null(), "read-write request dropped without ascertaining completion.");
    }
}

/// Guard object that waits for the completion of an operation when it is dropped
///
/// # Examples
///
/// See `examples/immediate.rs`
pub struct WaitGuard<Req: Request>(Option<Req>);

impl<Req: Request> Drop for WaitGuard<Req> {
    fn drop(&mut self) {
        self.0.take().map(|mut req| {
            unsafe {
                ffi::MPI_Wait(req.as_raw_mut(), ffi::RSMPI_STATUS_IGNORE);
            }
            assert!(req.is_null());
            mem::forget(req);
        });
    }
}

impl<Req: Request> From<Req> for WaitGuard<Req> {
    fn from(req: Req) -> WaitGuard<Req> {
        WaitGuard(Some(req))
    }
}

/// Guard object that cancels an operation when it is dropped
///
/// # Examples
///
/// See `examples/immediate.rs`
pub struct CancelGuard<Req: Request>(Option<Req>);

impl<Req: Request> Drop for CancelGuard<Req> {
    fn drop(&mut self) {
        self.0.take().map(|mut req| {
            unsafe {
                ffi::MPI_Cancel(req.as_raw_mut());
                ffi::MPI_Request_free(req.as_raw_mut());
            }
            assert!(req.is_null());
            mem::forget(req);
        });
    }
}

impl<Req: Request> From<Req> for CancelGuard<Req> {
    fn from(req: Req) -> CancelGuard<Req> {
        CancelGuard(Some(req))
    }
}
<|endoftext|>