<commit_before>
use hyper;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
}

impl GitLab {

    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        let gl = GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port:   port,
            private_token: private_token.to_string(),
            client: hyper::Client::new()
        };

        gl
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    pub fn build_url(&self, command: &str) -> String {
        format!("{}://{}:{}/api/v{}/{}?private_token={}",
                                self.scheme,
                                self.domain,
                                self.port,
                                API_VERSION,
                                command,
                                self.private_token)
    }

    pub fn get(&self, command: &str) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url(&command);
        self.client.get(&url).send()
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        self.get("version")
    }

    // pub fn projects(&self) -> ProjectManager {
    //     ProjectManager()
    // }
}
<commit_msg>Cleanup<commit_after>
use hyper;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
}

impl GitLab {

    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port:   port,
            private_token: private_token.to_string(),
            client: hyper::Client::new()
        };
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    pub fn build_url(&self, command: &str) -> String {
        format!("{}://{}:{}/api/v{}/{}?private_token={}",
                                self.scheme,
                                self.domain,
                                self.port,
                                API_VERSION,
                                command,
                                self.private_token)
    }

    pub fn get(&self, command: &str) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url(&command);
        self.client.get(&url).send()
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        self.get("version")
    }

    // pub fn projects(&self) -> ProjectManager {
    //     ProjectManager()
    // }
}
<|endoftext|>


<commit_before>/// MPI-based method for summing many arrays

// Argument parsing
// logging
#[macro_use] extern crate log;
#[macro_use] extern crate clap;
extern crate ndarray;
extern crate env_logger;
// lastly, this library
extern crate cabarrus;
use cabarrus::errors::*;

pub fn main() {
    // Main can't return a Result, and the ? operator needs the enclosing function to return Result
    inner_main().expect("Could not recover. Exiting.");
}
pub fn inner_main() -> Result<()> {
    env_logger::init().unwrap();
    let args = app_from_crate!()
        .arg_from_usage("<size> 'how many workers there are'")
        .arg_from_usage("<rank> 'which worker am I, starting from 0'")
        .arg_from_usage("<addends>.. 'files containing matrices to add'")
        .arg_from_usage("<output> 'file in which to store the resulting matrix'")
        .get_matches();
    let outname = args.value_of("output").unwrap();
    let mut mats : Vec<&str> = args.values_of("addends").unwrap().collect();
    mats.sort();

    let size = value_t!(args, "size", usize).unwrap_or_else(|e| e.exit());
    let rank = value_t!(args, "rank", usize).unwrap_or_else(|e| e.exit());
    let chunksize = (mats.len() + size - 1) / size;
    mats = mats.into_iter().skip(rank*chunksize).take(chunksize).collect();
    info!("{} files, {} workers (I'm #{}), chunks of {} (I get {}), output goes to {}",
        mats.len(), size, rank, chunksize, mats.len(), outname);

    if ! mats.is_empty() {
        {
            let matname = mats[0];
            let ref matfile = cabarrus::numpy::open_matrix_mmap(matname)
                .expect(&format!("Failed to open first matrix, {}", matname));
            let ref mat = cabarrus::numpy::read_matrix_mmap(matfile)
                .unwrap();
            cabarrus::numpy::write_matrix(outname, mat)
                .expect("Failed to create accumulator matrix file");
        };
        let ref accumfile = cabarrus::numpy::open_matrix_mmap(outname)
            .expect("Failed to reopen accumulator matrix");
        let mut accum = cabarrus::numpy::read_matrix_mmap(accumfile)?;

        for matname in mats {
            let ref matfile = cabarrus::numpy::open_matrix_mmap(matname)
                .expect(&format!("Failed to open matrix {}", matname));
            let ref mat = cabarrus::numpy::read_matrix_mmap(matfile)?;

            info!("Reading {} ({} GB) ..", matname, mat.len() >> 27);
            accum += mat;
        }
    } else {
            info!("No matrices processed so nothing saved.");
        }
    Ok(())
}
<commit_msg>Improve IO characteristics with batching<commit_after>/// MPI-based method for summing many arrays

// Argument parsing
// logging
#[macro_use] extern crate log;
#[macro_use] extern crate clap;
extern crate ndarray;
extern crate env_logger;
// lastly, this library
extern crate cabarrus;
use cabarrus::errors::*;
use ndarray::prelude::*;

pub fn main() {
    // Main can't return a Result, and the ? operator needs the enclosing function to return Result
    inner_main().expect("Could not recover. Exiting.");
}
pub fn inner_main() -> Result<()> {
    env_logger::init().unwrap();
    let args = app_from_crate!()
        .arg_from_usage("<size> 'how many workers there are'")
        .arg_from_usage("<rank> 'which worker am I, starting from 0'")
        .arg_from_usage("<addends>.. 'files containing matrices to add'")
        .arg_from_usage("<output> 'file in which to store the resulting matrix'")
        .get_matches();
    let outname = args.value_of("output").unwrap();
    let mut mats : Vec<&str> = args.values_of("addends").unwrap().collect();
    mats.sort();

    let size = value_t!(args, "size", usize).unwrap_or_else(|e| e.exit());
    let rank = value_t!(args, "rank", usize).unwrap_or_else(|e| e.exit());
    let chunksize = (mats.len() + size - 1) / size;
    mats = mats.into_iter().skip(rank*chunksize).take(chunksize).collect();
    info!("{} files, {} workers (I'm #{}), chunks of {} (I get {}), output goes to {}",
        mats.len(), size, rank, chunksize, mats.len(), outname);

    if ! mats.is_empty() {
        {
            let matname = mats[0];
            let ref matfile = cabarrus::numpy::open_matrix_mmap(matname)
                .expect(&format!("Failed to open first matrix, {}", matname));
            let ref mat = cabarrus::numpy::read_matrix_mmap(matfile)
                .unwrap();
            cabarrus::numpy::write_matrix(outname, mat)
                .expect("Failed to create accumulator matrix file");
        };
        let ref accumfile = cabarrus::numpy::open_matrix_mmap(outname)
            .expect("Failed to reopen accumulator matrix");
        let mut accum = cabarrus::numpy::read_matrix_mmap(accumfile)?;

        // This is awkward because the matrices are too large for memory..
        // But if accum is an mmap, you waste a *ton* of IO.
        let mut bufline = Array1::zeros([accum.shape()[1]]);
        for matnames in mats[1..].chunks(16) {
            let matfiles : Vec<cabarrus::numpy::MatFile> =
                matnames.iter()
                .map(|name| cabarrus::numpy::open_matrix_mmap(name)
                    .expect(&format!("Failed to open matrix {}", name)))
                .collect();
            let mats : Vec<ArrayViewMut2<f64>> = matfiles.iter()
                .map(|matfile| cabarrus::numpy::read_matrix_mmap(matfile)
                    .expect("Failed to read matrix"))
                .collect();

            // The overhead just doesn't matter when the IO is the limit
            for (row_i, mut accum_row) in accum.outer_iter_mut().enumerate() {
                bufline *= 0.0;
                for mat in mats.iter() {
                    bufline += &mat.row(row_i);
                }
                accum_row.assign(&bufline);
            }
            //info!("Reading {} ({} GB) ..", matname, mat.len() >> 27);
        }
    } else {
            info!("No matrices processed so nothing saved.");
        }
    Ok(())
}
<|endoftext|>


<commit_before>use std::path::Path;

use ops::{self, ExecEngine, CompileFilter};
use util::{self, CargoResult, human, process, ProcessError};
use core::source::Source;
use sources::PathSource;

pub fn run(manifest_path: &Path,
           options: &ops::CompileOptions,
           args: &[String]) -> CargoResult<Option<ProcessError>> {
    let config = options.config;
    let mut src = try!(PathSource::for_path(&manifest_path.parent().unwrap(),
                                            config));
    try!(src.update());
    let root = try!(src.root_package());

    let mut bins = root.manifest().targets().iter().filter(|a| {
        !a.is_lib() && !a.is_custom_build() && match options.filter {
            CompileFilter::Everything => a.is_bin(),
            CompileFilter::Only { .. } => options.filter.matches(a),
        }
    });
    if bins.next().is_none() {
        match options.filter {
            CompileFilter::Everything => {
                return Err(human("a bin target must be available for \
                                  `cargo run`"))
            }
            CompileFilter::Only { .. } => {
                // this will be verified in cargo_compile
            }
        }
    }
    if bins.next().is_some() {
        match options.filter {
            CompileFilter::Everything => {
                return Err(human("`cargo run` requires that a project only have \
                                  one executable; use the `--bin` option to \
                                  specify which one to run"))
            }
            CompileFilter::Only { .. } => {
                return Err(human("`cargo run` can run at most one executable, \
                                  but multiple were specified"))
            }
        }
    }

    let compile = try!(ops::compile(manifest_path, options));
    let exe = &compile.binaries[0];
    let exe = match util::without_prefix(&exe, config.cwd()) {
        Some(path) => if path.as_os_str() == path.file_name().unwrap() { &**exe }
                      else { path }, // workaround for being able to use
                                     // `cargo run` from the executable path itself
        None => &**exe,
    };
    let mut process = try!(compile.target_process(exe, &root))
                                  .into_process_builder();
    process.args(args).cwd(config.cwd());

    try!(config.shell().status("Running", process.to_string()));
    Ok(process.exec().err())
}
<commit_msg>Improved fix for the issue #1942<commit_after>use std::path::Path;

use ops::{self, ExecEngine, CompileFilter};
use util::{self, CargoResult, human, process, ProcessError};
use core::source::Source;
use sources::PathSource;

pub fn run(manifest_path: &Path,
           options: &ops::CompileOptions,
           args: &[String]) -> CargoResult<Option<ProcessError>> {
    let config = options.config;
    let mut src = try!(PathSource::for_path(&manifest_path.parent().unwrap(),
                                            config));
    try!(src.update());
    let root = try!(src.root_package());

    let mut bins = root.manifest().targets().iter().filter(|a| {
        !a.is_lib() && !a.is_custom_build() && match options.filter {
            CompileFilter::Everything => a.is_bin(),
            CompileFilter::Only { .. } => options.filter.matches(a),
        }
    });
    if bins.next().is_none() {
        match options.filter {
            CompileFilter::Everything => {
                return Err(human("a bin target must be available for \
                                  `cargo run`"))
            }
            CompileFilter::Only { .. } => {
                // this will be verified in cargo_compile
            }
        }
    }
    if bins.next().is_some() {
        match options.filter {
            CompileFilter::Everything => {
                return Err(human("`cargo run` requires that a project only have \
                                  one executable; use the `--bin` option to \
                                  specify which one to run"))
            }
            CompileFilter::Only { .. } => {
                return Err(human("`cargo run` can run at most one executable, \
                                  but multiple were specified"))
            }
        }
    }

    let compile = try!(ops::compile(manifest_path, options));
    let exe = &compile.binaries[0];
    let exe = match util::without_prefix(&exe, config.cwd()) {
        Some(path) if path.file_name() == Some(path.as_os_str())
                   => Path::new(".").join(path).to_path_buf(),
        Some(path) => path.to_path_buf(),
        None => exe.to_path_buf(),
    };
    let mut process = try!(compile.target_process(exe, &root))
                                  .into_process_builder();
    process.args(args).cwd(config.cwd());

    try!(config.shell().status("Running", process.to_string()));
    Ok(process.exec().err())
}
<|endoftext|>


<commit_before>
#[macro_export]
macro_rules! interrupt_handler {
    ($name: ident, $nvic: expr $(, $body: expr)*) => {
        #[no_mangle]
        #[allow(non_snake_case)]
        #[allow(unused_imports)]
        pub unsafe extern fn $name() {
            $({
                $body
            })*

            ::cortexm3::nvic::disable($nvic);
        }
    }
}

<commit_msg>Helper macro for defining interrupt handlers<commit_after>
#[macro_export]
macro_rules! interrupt_handler {
    ($name: ident, $nvic: expr $(, $body: expr)*) => {
        #[no_mangle]
        #[allow(non_snake_case)]
        #[allow(unused_imports)]
        pub unsafe extern fn $name() {
            $({
                $body
            })*

            ::cortexm3::nvic::Nvic::new($nvic).disable();
        }
    }
}

<|endoftext|>


<commit_before>use std::fmt;
use std::iter::{once, repeat, FromIterator};
use std::ops::Index;

use memory::{MemoryLayout, MemoryBlock, CellIndex, MemSize};
use operations::{Operation, Operations};

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

impl Instructions {
    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn last(&self) -> Option<&Instruction> {
        self.0.last()
    }

    pub fn iter(&self) -> ::std::slice::Iter<Instruction> {
        self.0.iter()
    }

    pub fn remove(&mut self, index: usize) -> Instruction {
        self.0.remove(index)
    }

    pub fn pop(&mut self) -> Option<Instruction> {
        self.0.pop()
    }

    pub fn truncate(&mut self, len: usize) {
        self.0.truncate(len)
    }

    pub fn clear(&mut self) {
        self.0.clear()
    }

}

impl Index<usize> for Instructions {
    type Output = Instruction;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }
}

impl IntoIterator for Instructions {
    type Item = Instruction;
    type IntoIter = ::std::vec::IntoIter<Instruction>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromIterator<Instruction> for Instructions {
    fn from_iter<I: IntoIterator<Item=Instruction>>(iter: I) -> Self {
        Instructions(iter.into_iter().collect())
    }
}

impl FromIterator<Instruction> for String {
    fn from_iter<I: IntoIterator<Item=Instruction>>(iter: I) -> Self {
        iter.into_iter().map(|instr| instr.to_string()).collect()
    }
}

impl From<Instructions> for String {
    fn from(instrs: Instructions) -> String {
        instrs.into_iter().collect()
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Instruction {
    // ">" - increment the pointer (move it to the "right")
    Right,
    // "<" - decrement the pointer (move it to the "left")
    Left,
    // "+" - increment the byte at the pointer
    Increment,
    // "-" - decrement the byte at the pointer
    Decrement,
    // "." - output the byte at the pointer
    Write,
    // "," - input a byte and store it in the byte at the pointer
    Read,
    // "[" - jump forward past the matching ] if the byte at the pointer is zero
    JumpForwardIfZero,
    // "]" - jump backward to the matching [ unless the byte at the pointer is zero
    JumpBackwardUnlessZero,
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Instruction::*;
        f.write_str(match *self {
            Right => ">",
            Left => "<",
            Increment => "+",
            Decrement => "-",
            Write => ".",
            Read => ",",
            JumpForwardIfZero => "[",
            JumpBackwardUnlessZero => "]",
        })
    }
}

impl From<Operations> for Instructions {
    fn from(ops: Operations) -> Instructions {
        let mut current_cell = 0;
        let mut layout = MemoryLayout::new();

        into_instructions_index(ops, &mut layout, &mut current_cell)
    }
}

fn into_instructions_index(
    ops: Operations,
    layout: &mut MemoryLayout,
    current_cell: &mut CellIndex,
) -> Instructions {
    use self::Operation::*;
    ops.into_iter().flat_map(|op| match op {
        Block {body} => into_instructions_index(body, layout, current_cell),
        TempAllocate {temp, body, should_zero} => {
            let instrs = into_instructions_index(body, layout, current_cell);
            layout.remove(&temp);
            if should_zero {
                instrs.into_iter().chain(zero(current_cell, layout, temp)).collect()
            }
            else {
                instrs
            }
        },
        Increment {target, amount} => {
            move_to(current_cell, layout.position(&target)).into_iter()
                .chain(repeat(Instruction::Increment).take(amount as usize)).collect()
        },
        Decrement {target, amount} => {
            move_to(current_cell, layout.position(&target)).into_iter()
                .chain(repeat(Instruction::Decrement).take(amount as usize)).collect()
        },
        Read {target} => {
            move_to(current_cell, layout.position(&target.position())).into_iter()
                .chain(consecutive(vec![Instruction::Read], current_cell, target.size())).collect()
        },
        Write {target} => {
            move_to(current_cell, layout.position(&target.position())).into_iter()
                .chain(consecutive(vec![Instruction::Write], current_cell, target.size())).collect()
        },
        Zero {target} => zero(current_cell, layout, target),
        Branch {cond, if_body, else_body} => {
            // Algorithm from: https://esolangs.org/wiki/Brainfuck_algorithms#if_.28x.29_.7B_code1_.7D_else_.7B_code2_.7D
            //
            // temp0 and temp1 are consecutive in memory following cond
            // temp0[-]+
            // temp1[-]
            // cond[
            //  if_block
            //  cond>-]>
            // [<
            //  else_block
            //  cond>->]
            //
            // Three consecutive temporary cells:
            // 1. cond - the boolean result of the condition expression
            // 2. temp0 - used to go into the else block when necessary
            // 3. temp1 - used *not* to go into the else block when necessary
            //
            // The basic idea of the algorithm is that you can control which of two adjacent loops run
            // by "sending" them either temp0 or temp1 based on the condition result
            layout.consecutive(&cond, 2, |layout, cond, temp| {
                move_to(current_cell, temp.position()).into_iter()
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(into_instructions_index(if_body, layout, current_cell))
                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::Right))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    .chain(once(Instruction::Right))

                    .chain(once(Instruction::JumpForwardIfZero))
                    .chain(once(Instruction::Left))

                    .chain(into_instructions_index(else_body, layout, current_cell))
                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::Right))
                    .chain(once(Instruction::Decrement))
                    .chain(once(Instruction::Right))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    .collect()
            })
        },
        Loop {cond, body} => {
            move_to(current_cell, layout.position(&cond)).into_iter()
                .chain(once(Instruction::JumpForwardIfZero))
                .chain(into_instructions_index(body, layout, current_cell))
                .chain(move_to(current_cell, layout.position(&cond)))
                .chain(once(Instruction::JumpBackwardUnlessZero))
                .collect()
        },
        Copy {source, target, size} => {
            debug_assert!(source.associated_memory().size() - source.offset() == size);
            debug_assert!(target.associated_memory().size() - target.offset() == size);

            // Algorithm for copying cells:
            // 1. In a loop, decrement the source cell and increment both the target cell and a
            //    temporary cell until the source cell is zero
            // 2. In a loop, decrement the temporary cell and increment the source cell until the
            //    temporary cell is zero
            // 3. Repeat these steps for each cell to be copied

            let source = layout.position(&source);
            let target = layout.position(&target);
            layout.temporary(1, |temp| (0..size).flat_map(|i| {
                move_to(current_cell, source + i).into_iter()
                    // Fill the target and the temporary with the value of the source cell
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, target + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    // Refill the source cell with the temporary
                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    // Need to zero the temporary cell so that it doesn't interfere with later code
                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::JumpForwardIfZero))
                    .chain(once(Instruction::Decrement))
                    .chain(once(Instruction::JumpBackwardUnlessZero))
            }).collect())
        },
        Relocate {source, target} => {
            debug_assert!(source.size() == target.size());
            let size = source.size();

            let source = layout.position(&source.position());
            let target = layout.position(&target.position());

            (0..size).flat_map(|i| {
                move_to(current_cell, source + i).into_iter()
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, target + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
            }).collect()
        },
    }).collect()
}

fn zero(current_cell: &mut CellIndex, layout: &mut MemoryLayout, target: MemoryBlock) -> Instructions {
    move_to(current_cell, layout.position(&target.position())).into_iter()
        .chain(consecutive(vec![
            Instruction::JumpForwardIfZero,
            Instruction::Decrement,
            Instruction::JumpBackwardUnlessZero,
        ], current_cell, target.size())).collect()
}

fn move_to(current_cell: &mut CellIndex, target: CellIndex) -> Vec<Instruction> {
    let current = *current_cell;
    *current_cell = target;

    if current > target {
        repeat(Instruction::Left).take(current - target).collect()
    }
    else if target > current {
        repeat(Instruction::Right).take(target - current).collect()
    }
    else {
        Vec::new()
    }
}

fn consecutive(instrs: Vec<Instruction>, current_cell: &mut CellIndex, size: MemSize) -> Vec<Instruction> {
    *current_cell += size;
    (0..size).flat_map(|_| instrs.clone().into_iter().chain(once(Instruction::Right))).collect()
}
<commit_msg>Fixed a bug that was breaking some invariants about current_cell and removed some useless instructions that were accidentally added previously<commit_after>use std::fmt;
use std::iter::{once, repeat, FromIterator};
use std::ops::Index;

use memory::{MemoryLayout, MemoryBlock, CellIndex, MemSize};
use operations::{Operation, Operations};

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

impl Instructions {
    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn last(&self) -> Option<&Instruction> {
        self.0.last()
    }

    pub fn iter(&self) -> ::std::slice::Iter<Instruction> {
        self.0.iter()
    }

    pub fn remove(&mut self, index: usize) -> Instruction {
        self.0.remove(index)
    }

    pub fn pop(&mut self) -> Option<Instruction> {
        self.0.pop()
    }

    pub fn truncate(&mut self, len: usize) {
        self.0.truncate(len)
    }

    pub fn clear(&mut self) {
        self.0.clear()
    }

}

impl Index<usize> for Instructions {
    type Output = Instruction;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }
}

impl IntoIterator for Instructions {
    type Item = Instruction;
    type IntoIter = ::std::vec::IntoIter<Instruction>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromIterator<Instruction> for Instructions {
    fn from_iter<I: IntoIterator<Item=Instruction>>(iter: I) -> Self {
        Instructions(iter.into_iter().collect())
    }
}

impl FromIterator<Instruction> for String {
    fn from_iter<I: IntoIterator<Item=Instruction>>(iter: I) -> Self {
        iter.into_iter().map(|instr| instr.to_string()).collect()
    }
}

impl From<Instructions> for String {
    fn from(instrs: Instructions) -> String {
        instrs.into_iter().collect()
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Instruction {
    // ">" - increment the pointer (move it to the "right")
    Right,
    // "<" - decrement the pointer (move it to the "left")
    Left,
    // "+" - increment the byte at the pointer
    Increment,
    // "-" - decrement the byte at the pointer
    Decrement,
    // "." - output the byte at the pointer
    Write,
    // "," - input a byte and store it in the byte at the pointer
    Read,
    // "[" - jump forward past the matching ] if the byte at the pointer is zero
    JumpForwardIfZero,
    // "]" - jump backward to the matching [ unless the byte at the pointer is zero
    JumpBackwardUnlessZero,
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Instruction::*;
        f.write_str(match *self {
            Right => ">",
            Left => "<",
            Increment => "+",
            Decrement => "-",
            Write => ".",
            Read => ",",
            JumpForwardIfZero => "[",
            JumpBackwardUnlessZero => "]",
        })
    }
}

impl From<Operations> for Instructions {
    fn from(ops: Operations) -> Instructions {
        let mut current_cell = 0;
        let mut layout = MemoryLayout::new();

        into_instructions_index(ops, &mut layout, &mut current_cell)
    }
}

fn into_instructions_index(
    ops: Operations,
    layout: &mut MemoryLayout,
    current_cell: &mut CellIndex,
) -> Instructions {
    use self::Operation::*;
    ops.into_iter().flat_map(|op| match op {
        Block {body} => into_instructions_index(body, layout, current_cell),
        TempAllocate {temp, body, should_zero} => {
            let instrs = into_instructions_index(body, layout, current_cell);
            layout.remove(&temp);
            if should_zero {
                instrs.into_iter().chain(zero(current_cell, layout, temp)).collect()
            }
            else {
                instrs
            }
        },
        Increment {target, amount} => {
            move_to(current_cell, layout.position(&target)).into_iter()
                .chain(repeat(Instruction::Increment).take(amount as usize)).collect()
        },
        Decrement {target, amount} => {
            move_to(current_cell, layout.position(&target)).into_iter()
                .chain(repeat(Instruction::Decrement).take(amount as usize)).collect()
        },
        Read {target} => {
            move_to(current_cell, layout.position(&target.position())).into_iter()
                .chain(consecutive(vec![Instruction::Read], current_cell, target.size())).collect()
        },
        Write {target} => {
            move_to(current_cell, layout.position(&target.position())).into_iter()
                .chain(consecutive(vec![Instruction::Write], current_cell, target.size())).collect()
        },
        Zero {target} => zero(current_cell, layout, target),
        Branch {cond, if_body, else_body} => {
            // Algorithm from: https://esolangs.org/wiki/Brainfuck_algorithms#if_.28x.29_.7B_code1_.7D_else_.7B_code2_.7D
            //
            // temp0 and temp1 are consecutive in memory following cond
            // temp0[-]+
            // temp1[-]
            // cond[
            //  if_block
            //  cond>-]>
            // [<
            //  else_block
            //  cond>->]
            //
            // Three consecutive temporary cells:
            // 1. cond - the boolean result of the condition expression
            // 2. temp0 - used to go into the else block when necessary
            // 3. temp1 - used *not* to go into the else block when necessary
            //
            // The basic idea of the algorithm is that you can control which of two adjacent loops run
            // by "sending" them either temp0 or temp1 based on the condition result
            layout.consecutive(&cond, 2, |layout, cond, temp| {
                move_to(current_cell, temp.position()).into_iter()
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(into_instructions_index(if_body, layout, current_cell))
                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::Right))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    .chain(once(Instruction::Right))

                    .chain(once(Instruction::JumpForwardIfZero))
                    .chain(once(Instruction::Left))

                    .chain(into_instructions_index(else_body, layout, current_cell))
                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::Right))
                    .chain(once(Instruction::Decrement))
                    .chain(once(Instruction::Right))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
                    .chain(once(Instruction::Left))
                    .chain(once(Instruction::Left))

                    .collect()
            })
        },
        Loop {cond, body} => {
            move_to(current_cell, layout.position(&cond)).into_iter()
                .chain(once(Instruction::JumpForwardIfZero))
                .chain(into_instructions_index(body, layout, current_cell))
                .chain(move_to(current_cell, layout.position(&cond)))
                .chain(once(Instruction::JumpBackwardUnlessZero))
                .collect()
        },
        Copy {source, target, size} => {
            debug_assert!(source.associated_memory().size() - source.offset() == size);
            debug_assert!(target.associated_memory().size() - target.offset() == size);

            // Algorithm for copying cells:
            // 1. In a loop, decrement the source cell and increment both the target cell and a
            //    temporary cell until the source cell is zero
            // 2. In a loop, decrement the temporary cell and increment the source cell until the
            //    temporary cell is zero
            // 3. Repeat these steps for each cell to be copied

            let source = layout.position(&source);
            let target = layout.position(&target);
            layout.temporary(1, |temp| (0..size).flat_map(|i| {
                move_to(current_cell, source + i).into_iter()
                    // Fill the target and the temporary with the value of the source cell
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, target + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    // Refill the source cell with the temporary
                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
            }).collect())
        },
        Relocate {source, target} => {
            debug_assert!(source.size() == target.size());
            let size = source.size();

            let source = layout.position(&source.position());
            let target = layout.position(&target.position());

            (0..size).flat_map(|i| {
                move_to(current_cell, source + i).into_iter()
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, target + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
            }).collect()
        },
    }).collect()
}

fn zero(current_cell: &mut CellIndex, layout: &mut MemoryLayout, target: MemoryBlock) -> Instructions {
    move_to(current_cell, layout.position(&target.position())).into_iter()
        .chain(consecutive(vec![
            Instruction::JumpForwardIfZero,
            Instruction::Decrement,
            Instruction::JumpBackwardUnlessZero,
        ], current_cell, target.size())).collect()
}

fn move_to(current_cell: &mut CellIndex, target: CellIndex) -> Vec<Instruction> {
    let current = *current_cell;
    *current_cell = target;

    if current > target {
        repeat(Instruction::Left).take(current - target).collect()
    }
    else if target > current {
        repeat(Instruction::Right).take(target - current).collect()
    }
    else {
        Vec::new()
    }
}

fn consecutive(instrs: Vec<Instruction>, current_cell: &mut CellIndex, size: MemSize) -> Vec<Instruction> {
    *current_cell += size;
    (0..size).flat_map(|_| instrs.clone().into_iter().chain(once(Instruction::Right))).collect()
}
<|endoftext|>


<commit_before>//!Bindings and rewrites of include/linux/time.h and include/linux/time64.h

extern crate linux_api;

use linux_api::*;

///Checks to see if two timespecs are equal
pub fn timespec_equal(a: &timespec, b: &timespec) -> c_int {
    return ((a.tv_sec == b.tv_sec) && (a.tv_nsec == b.tv_nsec)) as c_int;
}

///Compares two timespecs
///
///If lhs < rhs, return < 0
///If lhs == rhs, return 0
///If lhs > rhs, return > 0
pub fn timespec_compare(lhs: &timespec, rhs: &timespec) -> c_int {
    if lhs.tv_sec < rhs.tv_sec { return -1; }
    if lhs.tv_sec > rhs.tv_sec { return 1; }
    return (lhs.tv_nsec - rhs.tv_nsec) as c_int;
}

///Compares two timevals
///
///If lhs < rhs, return < 0
///If lhs == rhs, return 0
///If lhs > rhs, return > 0
pub fn timeval_compare(lhs: &timeval, rhs: &timeval) -> c_int {
    if lhs.tv_sec < rhs.tv_sec { return -1; }
    if lhs.tv_sec > rhs.tv_sec { return 1; }
    return (lhs.tv_usec - rhs.tv_usec) as c_int;
}

//TODO: mktime64
//TODO: mktime

///Sets the data contained in the borrowed `timespec` ts to normalized values
pub fn set_normalized_timespec(ts: &mut timespec, sec: time_t, nsec: i64) {
    let mut realsec = sec;
    let mut realnsec = nsec;

    while realnsec >= NSEC_PER_SEC {
        //TODO: Check to see if this gets optimized and, if so, force it not to as per kernel definition
        realnsec -= NSEC_PER_SEC;
        realsec += 1;
    }

    while realnsec < 0 {
        //Ditto
        realnsec += NSEC_PER_SEC;
        realsec -= 1;
    }

    ts.tv_sec = realsec;
    ts.tv_nsec = realnsec;
}

//TODO: timespec_add_safe, timespec_add, timespec_sub

pub fn timespec_valid(ts: &timespec) -> bool {
    //Dates before 1970 are bogus
    if ts.tv_sec < 0 {
        return false;
    }

    //Can't have more nanoseconds than a second
    if ts.tv_nsec >= NSEC_PER_SEC {
        return false;
    }

    //Okay, all looks good
    return true;
}

pub fn timespec_valid_strict(ts: &timespec) -> bool {
    if !timespec_valid(ts) {
        return false;
    }

    //Okay, we've validated it quickly
    //Disallow values that could overflow ktime_t
    if ts.tv_sec >= KTIME_SEC_MAX {
        return false;
    }

    return true;
}

pub fn timeval_valid(tv: &timeval) -> bool {
    //Dates before 1970 are bogus
    if tv.tv_sec < 0 {
        return false;
    }

    //Can't have more microseconds than a second
    if tv.tv_usec >= USEC_PER_SEC {
        return false;
    }

    //Okay, all looks good
    return true;
}

#[cfg(test)]
mod test {
    use super::*;
    use linux_api::*;

    #[test]
    fn test_timespec_valid() {
        let atime: timespec = timespec { tv_sec: 0, tv_nsec: 4262 };

        assert!(timespec_valid(&atime));
    }

    #[test]
    fn test_timespec_too_many_seconds_valid() {
        let atime: timespec = timespec { tv_sec: KTIME_SEC_MAX + 365, tv_nsec: 4262 };

        assert!(!timespec_valid_strict(&atime));
    }

    #[test]
    fn test_timespec_before_1970_invalid() {
        let atime: timespec = timespec { tv_sec: -63, tv_nsec: 4262 };

        assert!(!timespec_valid(&atime));
    }

    #[test]
    fn test_timespec_too_many_nanoseconds_invalid() {
        let atime: timespec = timespec { tv_sec: 0, tv_nsec: NSEC_PER_SEC + 2 };

        assert!(!timespec_valid(&atime));
    }

    #[test]
    fn test_timeval_valid() {
        let atime: timeval = timeval { tv_sec: 0, tv_usec: 4262 };

        assert!(timeval_valid(&atime));
    }

    #[test]
    fn test_timeval_before_1970_invalid() {
        let atime: timeval = timeval { tv_sec: -63, tv_usec: 4262 };

        assert!(!timeval_valid(&atime));
    }

    #[test]
    fn test_timeval_too_many_nanoseconds_invalid() {
        let atime: timeval = timeval { tv_sec: 0, tv_usec: USEC_PER_SEC + 2 };

        assert!(!timeval_valid(&atime));
    }

    #[test]
    fn test_timespec_equal_when_equal() {
        let one: timespec = timespec { tv_sec: 77, tv_nsec: 77 };
        let two: timespec = timespec { tv_sec: 77, tv_nsec: 77 };

        assert_eq!(1, timespec_equal(&one, &two));
    }

    #[test]
    fn test_timespec_equal_when_inequal() {
        let one: timespec = timespec { tv_sec: 0, tv_nsec: 266 };
        let two: timespec = timespec { tv_sec: 4, tv_nsec: 0 };

        assert_eq!(0, timespec_equal(&one, &two));
    }

    #[test]
    fn test_timespec_compare_same() {
        let one = timespec { tv_sec: 10, tv_nsec: 0 };
        let two = timespec { tv_sec: 10, tv_nsec: 0 };

        assert_eq!(0, timespec_compare(&one, &two));
    }

    #[test]
    fn test_timespec_compare_larger() {
        let one = timespec { tv_sec: 11, tv_nsec: 0 };
        let two = timespec { tv_sec: 10, tv_nsec: 0 };

        assert_eq!(1, timespec_compare(&one, &two));
    }

    #[test]
    fn test_timespec_compare_smaller() {
        let one = timespec { tv_sec: 9, tv_nsec: 0 };
        let two = timespec { tv_sec: 10, tv_nsec: 0 };

        assert_eq!(-1, timespec_compare(&one, &two));
    }

    #[test]
    fn test_timeval_compare_same() {
        let one = timeval { tv_sec: 10, tv_usec: 0 };
        let two = timeval { tv_sec: 10, tv_usec: 0 };

        assert_eq!(0, timeval_compare(&one, &two));
    }

    #[test]
    fn test_timeval_compare_larger() {
        let one = timeval { tv_sec: 11, tv_usec: 0 };
        let two = timeval { tv_sec: 10, tv_usec: 0 };

        assert_eq!(1, timeval_compare(&one, &two));
    }

    #[test]
    fn test_timeval_compare_smaller() {
        let one = timeval { tv_sec: 9, tv_usec: 0 };
        let two = timeval { tv_sec: 10, tv_usec: 0 };

        assert_eq!(-1, timeval_compare(&one, &two));
    }

    #[test]
    fn test_normalized_timespec_many_nanos() {
        let mut spec: timespec = timespec { tv_sec: 0, tv_nsec: 0 };

        set_normalized_timespec(&mut spec, 10, NSEC_PER_SEC * 20);

        assert_eq!(30, spec.tv_sec);
        assert_eq!(0, spec.tv_nsec);
    }

    #[test]
    fn test_normalized_timespec_negative_nanos() {
        let mut spec: timespec = timespec { tv_sec: 0, tv_nsec: 0 };

        set_normalized_timespec(&mut spec, 5, -800);

        assert_eq!(4, spec.tv_sec);
        assert_eq!(NSEC_PER_SEC - 800, spec.tv_nsec);
    }

}<commit_msg>Add and test timespec_add and timespec_sub<commit_after>//!Bindings and rewrites of include/linux/time.h and include/linux/time64.h

extern crate linux_api;

use linux_api::*;

///Checks to see if two timespecs are equal
pub fn timespec_equal(a: &timespec, b: &timespec) -> c_int {
    return ((a.tv_sec == b.tv_sec) && (a.tv_nsec == b.tv_nsec)) as c_int;
}

///Compares two timespecs
///
///If lhs < rhs, return < 0
///If lhs == rhs, return 0
///If lhs > rhs, return > 0
pub fn timespec_compare(lhs: &timespec, rhs: &timespec) -> c_int {
    if lhs.tv_sec < rhs.tv_sec { return -1; }
    if lhs.tv_sec > rhs.tv_sec { return 1; }
    return (lhs.tv_nsec - rhs.tv_nsec) as c_int;
}

///Compares two timevals
///
///If lhs < rhs, return < 0
///If lhs == rhs, return 0
///If lhs > rhs, return > 0
pub fn timeval_compare(lhs: &timeval, rhs: &timeval) -> c_int {
    if lhs.tv_sec < rhs.tv_sec { return -1; }
    if lhs.tv_sec > rhs.tv_sec { return 1; }
    return (lhs.tv_usec - rhs.tv_usec) as c_int;
}

//TODO: mktime64
//TODO: mktime

///Sets the data contained in the borrowed `timespec` ts to normalized values
pub fn set_normalized_timespec(ts: &mut timespec, sec: time_t, nsec: i64) {
    let mut realsec = sec;
    let mut realnsec = nsec;

    while realnsec >= NSEC_PER_SEC {
        //TODO: Check to see if this gets optimized and, if so, force it not to as per kernel definition
        realnsec -= NSEC_PER_SEC;
        realsec += 1;
    }

    while realnsec < 0 {
        //Ditto
        realnsec += NSEC_PER_SEC;
        realsec -= 1;
    }

    ts.tv_sec = realsec;
    ts.tv_nsec = realnsec;
}

//TODO: timespec_add_safe, timespec_sub

///Adds two timespecs together, returning the result as a new timespec
pub fn timespec_add(lhs: &timespec, rhs: &timespec) -> timespec {
    let mut ts_delta: timespec = timespec { tv_sec:0, tv_nsec: 0 };
    set_normalized_timespec(&mut ts_delta, lhs.tv_sec + rhs.tv_sec, lhs.tv_nsec + rhs.tv_nsec);
    ts_delta
}

///Subtracts rhs from lhs, returning the difference as a new timespec
pub fn timespec_sub(lhs: &timespec, rhs: &timespec) -> timespec {
    let mut ts_delta: timespec = timespec { tv_sec: 0, tv_nsec: 0 };
    set_normalized_timespec(&mut ts_delta, lhs.tv_sec - rhs.tv_sec, lhs.tv_nsec - rhs.tv_nsec);
    ts_delta
}

///Checks to see if a timespec is valid
pub fn timespec_valid(ts: &timespec) -> bool {
    //Dates before 1970 are bogus
    if ts.tv_sec < 0 {
        return false;
    }

    //Can't have more nanoseconds than a second
    if ts.tv_nsec >= NSEC_PER_SEC {
        return false;
    }

    //Okay, all looks good
    return true;
}

///Checks to see if a timespec is valid according to stricter rules
pub fn timespec_valid_strict(ts: &timespec) -> bool {
    if !timespec_valid(ts) {
        return false;
    }

    //Okay, we've validated it quickly
    //Disallow values that could overflow ktime_t
    if ts.tv_sec >= KTIME_SEC_MAX {
        return false;
    }

    return true;
}

///Checks to see if a timeval is valid
pub fn timeval_valid(tv: &timeval) -> bool {
    //Dates before 1970 are bogus
    if tv.tv_sec < 0 {
        return false;
    }

    //Can't have more microseconds than a second
    if tv.tv_usec >= USEC_PER_SEC {
        return false;
    }

    //Okay, all looks good
    return true;
}

#[cfg(test)]
mod test {
    use super::*;
    use linux_api::*;

    #[test]
    fn test_timespec_valid() {
        let atime: timespec = timespec { tv_sec: 0, tv_nsec: 4262 };

        assert!(timespec_valid(&atime));
    }

    #[test]
    fn test_timespec_too_many_seconds_valid() {
        let atime: timespec = timespec { tv_sec: KTIME_SEC_MAX + 365, tv_nsec: 4262 };

        assert!(!timespec_valid_strict(&atime));
    }

    #[test]
    fn test_timespec_before_1970_invalid() {
        let atime: timespec = timespec { tv_sec: -63, tv_nsec: 4262 };

        assert!(!timespec_valid(&atime));
    }

    #[test]
    fn test_timespec_too_many_nanoseconds_invalid() {
        let atime: timespec = timespec { tv_sec: 0, tv_nsec: NSEC_PER_SEC + 2 };

        assert!(!timespec_valid(&atime));
    }

    #[test]
    fn test_timeval_valid() {
        let atime: timeval = timeval { tv_sec: 0, tv_usec: 4262 };

        assert!(timeval_valid(&atime));
    }

    #[test]
    fn test_timeval_before_1970_invalid() {
        let atime: timeval = timeval { tv_sec: -63, tv_usec: 4262 };

        assert!(!timeval_valid(&atime));
    }

    #[test]
    fn test_timeval_too_many_nanoseconds_invalid() {
        let atime: timeval = timeval { tv_sec: 0, tv_usec: USEC_PER_SEC + 2 };

        assert!(!timeval_valid(&atime));
    }

    #[test]
    fn test_timespec_equal_when_equal() {
        let one: timespec = timespec { tv_sec: 77, tv_nsec: 77 };
        let two: timespec = timespec { tv_sec: 77, tv_nsec: 77 };

        assert_eq!(1, timespec_equal(&one, &two));
    }

    #[test]
    fn test_timespec_equal_when_inequal() {
        let one: timespec = timespec { tv_sec: 0, tv_nsec: 266 };
        let two: timespec = timespec { tv_sec: 4, tv_nsec: 0 };

        assert_eq!(0, timespec_equal(&one, &two));
    }

    #[test]
    fn test_timespec_compare_same() {
        let one = timespec { tv_sec: 10, tv_nsec: 0 };
        let two = timespec { tv_sec: 10, tv_nsec: 0 };

        assert_eq!(0, timespec_compare(&one, &two));
    }

    #[test]
    fn test_timespec_compare_larger() {
        let one = timespec { tv_sec: 11, tv_nsec: 0 };
        let two = timespec { tv_sec: 10, tv_nsec: 0 };

        assert_eq!(1, timespec_compare(&one, &two));
    }

    #[test]
    fn test_timespec_compare_smaller() {
        let one = timespec { tv_sec: 9, tv_nsec: 0 };
        let two = timespec { tv_sec: 10, tv_nsec: 0 };

        assert_eq!(-1, timespec_compare(&one, &two));
    }

    #[test]
    fn test_timeval_compare_same() {
        let one = timeval { tv_sec: 10, tv_usec: 0 };
        let two = timeval { tv_sec: 10, tv_usec: 0 };

        assert_eq!(0, timeval_compare(&one, &two));
    }

    #[test]
    fn test_timeval_compare_larger() {
        let one = timeval { tv_sec: 11, tv_usec: 0 };
        let two = timeval { tv_sec: 10, tv_usec: 0 };

        assert_eq!(1, timeval_compare(&one, &two));
    }

    #[test]
    fn test_timeval_compare_smaller() {
        let one = timeval { tv_sec: 9, tv_usec: 0 };
        let two = timeval { tv_sec: 10, tv_usec: 0 };

        assert_eq!(-1, timeval_compare(&one, &two));
    }

    #[test]
    fn test_normalized_timespec_many_nanos() {
        let mut spec: timespec = timespec { tv_sec: 0, tv_nsec: 0 };

        set_normalized_timespec(&mut spec, 10, NSEC_PER_SEC * 20);

        assert_eq!(30, spec.tv_sec);
        assert_eq!(0, spec.tv_nsec);
    }

    #[test]
    fn test_normalized_timespec_negative_nanos() {
        let mut spec: timespec = timespec { tv_sec: 0, tv_nsec: 0 };

        set_normalized_timespec(&mut spec, 5, -800);

        assert_eq!(4, spec.tv_sec);
        assert_eq!(NSEC_PER_SEC - 800, spec.tv_nsec);
    }

    #[test]
    fn test_timespec_add_simple() {
        let lhs = timespec { tv_sec: 80, tv_nsec: 500 };
        let rhs = timespec { tv_sec: 30, tv_nsec: 580 };

        let delta = timespec_add(&lhs, &rhs);

        assert_eq!(110, delta.tv_sec);
        assert_eq!(1080, delta.tv_nsec);
    }

    #[test]
    fn test_timespec_add_manynanos() {
        let lhs = timespec { tv_sec: 80, tv_nsec: NSEC_PER_SEC / 2 };
        let rhs = timespec { tv_sec: 30, tv_nsec: (NSEC_PER_SEC / 2) + 400 };

        let delta = timespec_add(&lhs, &rhs);

        assert_eq!(111, delta.tv_sec);
        assert_eq!(400, delta.tv_nsec);
    }

    #[test]
    fn test_timespec_sub_simple() {
        let lhs = timespec { tv_sec: 80, tv_nsec: 500 };
        let rhs = timespec { tv_sec: 30, tv_nsec: 580 };

        let delta = timespec_sub(&lhs, &rhs);

        assert_eq!(49, delta.tv_sec);
        assert_eq!(NSEC_PER_SEC - 80, delta.tv_nsec);
    }

    #[test]
    fn test_timespec_sub_bad() {
        let lhs = timespec { tv_sec: 80, tv_nsec: 500 };
        let rhs = timespec { tv_sec: 1030, tv_nsec: 580 };

        let delta = timespec_sub(&lhs, &rhs);

        assert_eq!(-951, delta.tv_sec);
        assert_eq!(NSEC_PER_SEC - 80, delta.tv_nsec);
    }

}<|endoftext|>


<commit_before>// Copyright (c) 2016 Tibor Benke <ihrwein@gmail.com>
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::collections::HashMap;

use config::ContextConfig;
use context::Context;

pub struct ContextMap {
    map: HashMap<String, Vec<usize>>,
    contexts: Vec<Context>,
}

impl ContextMap {
    pub fn new() -> ContextMap {
        ContextMap {
            map: HashMap::new(),
            contexts: Vec::new(),
        }
    }

    pub fn from_configs(configs: Vec<ContextConfig>) -> ContextMap {
        let mut context_map = ContextMap::new();
        for i in configs {
            context_map.insert(i.into());
        }
        context_map
    }

    pub fn insert(&mut self, context: Context) {
        self.contexts.push(context);
        let last_context = self.contexts
                               .last()
                               .expect("Failed to remove the last Context from a non empty vector");
        let index_of_last_context = self.contexts.len() - 1;
        let patterns = last_context.patterns();
        ContextMap::update_indices(&mut self.map, index_of_last_context, patterns);
    }

    fn update_indices(map: &mut HashMap<String, Vec<usize>>,
                      new_index: usize,
                      patterns: &[String]) {
        if patterns.is_empty() {
            ContextMap::add_index_to_every_index_vectors(map, new_index);
        } else {
            ContextMap::add_index_to_looked_up_index_vectors(map, new_index, patterns);
        }
    }

    fn add_index_to_every_index_vectors(map: &mut HashMap<String, Vec<usize>>, new_index: usize) {
        for (_, v) in map.iter_mut() {
            v.push(new_index);
        }
    }

    fn add_index_to_looked_up_index_vectors(map: &mut HashMap<String, Vec<usize>>,
                                            new_index: usize,
                                            patterns: &[String]) {
        for i in patterns {
            map.entry(i.clone()).or_insert_with(Vec::new).push(new_index);
        }
    }

    pub fn contexts_mut(&mut self) -> &mut Vec<Context> {
        &mut self.contexts
    }

    pub fn contexts_iter_mut(&mut self, key: &str) -> Iterator {
        let ids = self.map.get(key);
        Iterator {
            ids: ids,
            pos: 0,
            contexts: &mut self.contexts,
        }
    }
}

pub trait StreamingIterator {
    type Item;
    fn next(&mut self) -> Option<&mut Self::Item>;
}

pub struct Iterator<'a> {
    ids: Option<&'a Vec<usize>>,
    pos: usize,
    contexts: &'a mut Vec<Context>,
}

impl<'a> StreamingIterator for Iterator<'a> {
    type Item = Context;
    fn next(&mut self) -> Option<&mut Context> {
        if let Some(ids) = self.ids {
            if let Some(id) = ids.get(self.pos) {
                self.pos += 1;
                self.contexts.get_mut(*id)
            } else {
                None
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use conditions::ConditionsBuilder;
    use context::{Context, LinearContext, BaseContextBuilder};
    use uuid::Uuid;
    use std::time::Duration;

    fn assert_context_map_contains_uuid(context_map: &mut ContextMap, uuid: &Uuid, key: &str) {
        let mut iter = context_map.contexts_iter_mut(key);
        let context = iter.next().expect("Failed to get back an inserted context");
        if let Context::Linear(ref context) = *context {
            assert_eq!(uuid, context.uuid());
        } else {
            unreachable!();
        }
    }

    #[test]
    fn test_given_context_map_when_a_context_is_inserted_then_its_patters_are_inserted_to_the_map_with_its_id
        () {
        let mut context_map = ContextMap::new();
        let uuid = Uuid::new_v4();
        let context1 = {
            let conditions = {
                ConditionsBuilder::new(Duration::from_millis(100)).build()
            };
            let patterns = vec!["A".to_owned(), "B".to_owned()];
            let base = BaseContextBuilder::new(uuid.clone(), conditions).patterns(patterns).build();
            LinearContext::new(base)
        };
        context_map.insert(Context::Linear(context1));
        assert_eq!(context_map.contexts_mut().len(), 1);
        assert_context_map_contains_uuid(&mut context_map, &uuid, "A");
        assert_context_map_contains_uuid(&mut context_map, &uuid, "B");
    }
}
<commit_msg>tests: fix a to_string() vs to_owned() lint<commit_after>// Copyright (c) 2016 Tibor Benke <ihrwein@gmail.com>
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::collections::HashMap;

use config::ContextConfig;
use context::Context;

pub struct ContextMap {
    map: HashMap<String, Vec<usize>>,
    contexts: Vec<Context>,
}

impl ContextMap {
    pub fn new() -> ContextMap {
        ContextMap {
            map: HashMap::new(),
            contexts: Vec::new(),
        }
    }

    pub fn from_configs(configs: Vec<ContextConfig>) -> ContextMap {
        let mut context_map = ContextMap::new();
        for i in configs {
            context_map.insert(i.into());
        }
        context_map
    }

    pub fn insert(&mut self, context: Context) {
        self.contexts.push(context);
        let last_context = self.contexts
                               .last()
                               .expect("Failed to remove the last Context from a non empty vector");
        let index_of_last_context = self.contexts.len() - 1;
        let patterns = last_context.patterns();
        ContextMap::update_indices(&mut self.map, index_of_last_context, patterns);
    }

    fn update_indices(map: &mut HashMap<String, Vec<usize>>,
                      new_index: usize,
                      patterns: &[String]) {
        if patterns.is_empty() {
            ContextMap::add_index_to_every_index_vectors(map, new_index);
        } else {
            ContextMap::add_index_to_looked_up_index_vectors(map, new_index, patterns);
        }
    }

    fn add_index_to_every_index_vectors(map: &mut HashMap<String, Vec<usize>>, new_index: usize) {
        for (_, v) in map.iter_mut() {
            v.push(new_index);
        }
    }

    fn add_index_to_looked_up_index_vectors(map: &mut HashMap<String, Vec<usize>>,
                                            new_index: usize,
                                            patterns: &[String]) {
        for i in patterns {
            map.entry(i.clone()).or_insert_with(Vec::new).push(new_index);
        }
    }

    pub fn contexts_mut(&mut self) -> &mut Vec<Context> {
        &mut self.contexts
    }

    pub fn contexts_iter_mut(&mut self, key: &str) -> Iterator {
        let ids = self.map.get(key);
        Iterator {
            ids: ids,
            pos: 0,
            contexts: &mut self.contexts,
        }
    }
}

pub trait StreamingIterator {
    type Item;
    fn next(&mut self) -> Option<&mut Self::Item>;
}

pub struct Iterator<'a> {
    ids: Option<&'a Vec<usize>>,
    pos: usize,
    contexts: &'a mut Vec<Context>,
}

impl<'a> StreamingIterator for Iterator<'a> {
    type Item = Context;
    fn next(&mut self) -> Option<&mut Context> {
        if let Some(ids) = self.ids {
            if let Some(id) = ids.get(self.pos) {
                self.pos += 1;
                self.contexts.get_mut(*id)
            } else {
                None
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use conditions::ConditionsBuilder;
    use context::{Context, LinearContext, BaseContextBuilder};
    use uuid::Uuid;
    use std::time::Duration;

    fn assert_context_map_contains_uuid(context_map: &mut ContextMap, uuid: &Uuid, key: &str) {
        let mut iter = context_map.contexts_iter_mut(key);
        let context = iter.next().expect("Failed to get back an inserted context");
        if let Context::Linear(ref context) = *context {
            assert_eq!(uuid, context.uuid());
        } else {
            unreachable!();
        }
    }

    #[test]
    fn test_given_context_map_when_a_context_is_inserted_then_its_patters_are_inserted_to_the_map_with_its_id
        () {
        let mut context_map = ContextMap::new();
        let uuid = Uuid::new_v4();
        let context1 = {
            let conditions = {
                ConditionsBuilder::new(Duration::from_millis(100)).build()
            };
            let patterns = vec!["A".to_owned(), "B".to_owned()];
            let base = BaseContextBuilder::new(uuid.to_owned(), conditions).patterns(patterns).build();
            LinearContext::new(base)
        };
        context_map.insert(Context::Linear(context1));
        assert_eq!(context_map.contexts_mut().len(), 1);
        assert_context_map_contains_uuid(&mut context_map, &uuid, "A");
        assert_context_map_contains_uuid(&mut context_map, &uuid, "B");
    }
}
<|endoftext|>


<commit_before>// !
// Entity component system
//

#![feature(proc_macro)]

extern crate serde;
#[macro_use]
extern crate serde_derive;

use std::default::Default;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::collections::{hash_map, HashMap, HashSet};
use std::collections::hash_set;

/// Handle for an entity in the entity component system.
///
/// The internal value is the unique identifier for the entity. No two
/// entities should get the same UID during the lifetime of the ECS.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Entity(pub usize);

pub trait AnyComponent {
    /// Remove an entity's component.
    fn remove(&mut self, e: Entity);
}

/// Storage for a single component type.
#[derive(Serialize, Deserialize)]
pub struct ComponentData<C> {
    // TODO: Add reused index fields to entities and use VecMap with the
    // index field instead of HashMap with the UID here for more
    // efficient access.
    data: HashMap<Entity, C>,
}

impl<C> ComponentData<C> {
    pub fn new() -> ComponentData<C> {
        ComponentData { data: HashMap::new() }
    }

    /// Insert a component to an entity.
    pub fn insert(&mut self, e: Entity, comp: C) {
        self.data.insert(e, comp);
    }

    /// Return whether an entity contains this component.
    pub fn contains(&self, e: Entity) -> bool {
        self.data.contains_key(&e)
    }

    /// Get a reference to a component only if it exists for this entity.
    pub fn get(&self, e: Entity) -> Option<&C> {
        self.data.get(&e)
    }

    /// Get a mutable reference to a component only if it exists for this entity.
    pub fn get_mut(&mut self, e: Entity) -> Option<&mut C> {
        self.data.get_mut(&e)
    }

    /// Iterate entity-component pairs for this component.
    pub fn iter(&self) -> hash_map::Iter<Entity, C> {
        self.data.iter()
    }

    /// Iterate mutable entity-component pairs for this component.
    pub fn iter_mut(&mut self) -> hash_map::IterMut<Entity, C> {
        self.data.iter_mut()
    }
}

impl<C> Index<Entity> for ComponentData<C> {
    type Output = C;

    fn index<'a>(&'a self, e: Entity) -> &'a C {
        self.data.get(&e).unwrap()
    }
}

impl<C> IndexMut<Entity> for ComponentData<C> {
    fn index_mut<'a>(&'a mut self, e: Entity) -> &'a mut C {
        self.data.get_mut(&e).unwrap()
    }
}

impl<C> AnyComponent for ComponentData<C> {
    fn remove(&mut self, e: Entity) {
        self.data.remove(&e);
    }
}

pub trait Store {
    /// Perform an operation for each component container.
    fn for_each_component<F>(&mut self, f: F) where F: FnMut(&mut AnyComponent);
}

#[derive(Serialize, Deserialize)]
pub struct Ecs<ST> {
    next_uid: usize,
    active: HashSet<Entity>,
    store: ST,
}

impl<ST: Default + Store> Ecs<ST> {
    pub fn new() -> Ecs<ST> {
        Ecs {
            next_uid: 1,
            active: HashSet::new(),
            store: Default::default(),
        }
    }

    /// Create a new empty entity.
    pub fn make(&mut self) -> Entity {
        let next = self.next_uid;
        self.next_uid += 1;
        let ret = Entity(next);
        self.active.insert(ret);
        ret
    }

    /// Remove an entity from the system and clear its components.
    pub fn remove(&mut self, e: Entity) {
        self.active.remove(&e);
        self.store.for_each_component(|c| c.remove(e));
    }

    /// Return whether the system contains an entity.
    pub fn contains(&self, e: Entity) -> bool {
        self.active.contains(&e)
    }

    pub fn iter(&self) -> hash_set::Iter<Entity> {
        self.active.iter()
    }
}

impl<ST> Deref for Ecs<ST> {
    type Target = ST;

    fn deref(&self) -> &ST {
        &self.store
    }
}

impl<ST> DerefMut for Ecs<ST> {
    fn deref_mut(&mut self) -> &mut ST {
        &mut self.store
    }
}

/// Entity component system builder macro.
///
/// Defines a local `Ecs` type that's parametrized with a custom component
/// store type with the component types you specify. Will also define a trait
/// `Component` which will be implemented for the component types.
#[macro_export]
macro_rules! Ecs {
    {
        // Declare the type of the (plain old data) component and the
        // identifier to use for it in the ECS.
        $($compname:ident: $comptype:ty,)+
    } => {
        mod _ecs_inner {
            // Use the enum to convert components to numbers for component bit masks etc.
            #[allow(non_camel_case_types, dead_code)]
            pub enum ComponentNum {
                $($compname,)+
            }

        }

        pub use self::_ecs_inner::ComponentNum;

        pub struct _ComponentStore {
            $(pub $compname: $crate::ComponentData<$comptype>),+
        }

        impl ::serde::Serialize for _ComponentStore {
            fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
                where S: ::serde::Serializer {
                $(try!(self.$compname.serialize(serializer));)+
                Ok(())
            }
        }

        impl ::serde::Deserialize for _ComponentStore {
            fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
                where D: ::serde::Deserializer {
                Ok(_ComponentStore {
                    $($compname: try!($crate::ComponentData::deserialize(deserializer))),+
                })
            }
        }

        impl ::std::default::Default for _ComponentStore {
            fn default() -> _ComponentStore {
                _ComponentStore {
                    $($compname: $crate::ComponentData::new()),+
                }
            }
        }

        impl $crate::Store for _ComponentStore {
            fn for_each_component<F>(&mut self, mut f: F)
                where F: FnMut(&mut $crate::AnyComponent)
            {
                $(f(&mut self.$compname as &mut $crate::AnyComponent);)+
            }
        }

        #[allow(dead_code)]
        pub fn matches_mask(ecs: &$crate::Ecs<_ComponentStore>, e: $crate::Entity, mask: u64) -> bool {
            $(if mask & (1 << ComponentNum::$compname as u8) != 0 && !ecs.$compname.contains(e) {
                return false;
            })+
            return true;
        }

        /// Common operations for ECS component value types.
        pub trait Component {
            /// Add a clone of the component value to an entity in an ECS.
            ///
            /// Can't move the component itself since we might be using this
            /// through a trait object.
            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity);

            /// Add a clone of the component to a loadout struct.
            fn add_to_loadout(self, loadout: &mut Loadout);
        }

        $(impl Component for $comptype {
            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity) {
                ecs.$compname.insert(e, self.clone());
            }

            fn add_to_loadout(self, loadout: &mut Loadout) {
                loadout.$compname = Some(self);
            }
        })+

        pub type Ecs = $crate::Ecs<_ComponentStore>;

        /// A straightforward representation for the complete data of an
        /// entity.
        #[derive(Clone, Debug, Serialize, Deserialize)]
        pub struct Loadout {
            $(pub $compname: Option<$comptype>),+
        }

        impl ::std::default::Default for Loadout {
            fn default() -> Loadout {
                Loadout {
                    $($compname: None),+
                }
            }
        }

        #[allow(dead_code)]
        impl Loadout {
            /// Create a new blank loadout.
            pub fn new() -> Loadout { Default::default() }

            /// Get the loadout that corresponds to an existing entity.
            pub fn get(ecs: &Ecs, e: $crate::Entity) -> Loadout {
                Loadout {
                    $($compname: ecs.$compname.get(e).map(|e| e.clone())),+
                }
            }

            /// Create a new entity in the ECS with this loadout.
            pub fn make(&self, ecs: &mut Ecs) -> $crate::Entity {
                let e = ecs.make();
                $(self.$compname.as_ref().map(|c| ecs.$compname.insert(e, c.clone()));)+
                e
            }

            /// Builder method for adding a component to this loadout.
            pub fn c<C: Component>(mut self, comp: C) -> Loadout {
                comp.add_to_loadout(&mut self);
                self
            }
        }
    }
}

/// Build a component type mask to match component iteration with.
///
/// You must have ComponentNum enum from the Ecs! macro expansion in scope
/// when using this.
#[macro_export]
macro_rules! build_mask {
    ( $($compname:ident),+ ) => {
        0u64 $(| (1u64 << ComponentNum::$compname as u8))+
    }
}
<commit_msg>Simplify use statement<commit_after>// !
// Entity component system
//

#![feature(proc_macro)]

extern crate serde;
#[macro_use]
extern crate serde_derive;

use std::default::Default;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::collections::{hash_map, HashMap, hash_set, HashSet};

/// Handle for an entity in the entity component system.
///
/// The internal value is the unique identifier for the entity. No two
/// entities should get the same UID during the lifetime of the ECS.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Entity(pub usize);

pub trait AnyComponent {
    /// Remove an entity's component.
    fn remove(&mut self, e: Entity);
}

/// Storage for a single component type.
#[derive(Serialize, Deserialize)]
pub struct ComponentData<C> {
    // TODO: Add reused index fields to entities and use VecMap with the
    // index field instead of HashMap with the UID here for more
    // efficient access.
    data: HashMap<Entity, C>,
}

impl<C> ComponentData<C> {
    pub fn new() -> ComponentData<C> {
        ComponentData { data: HashMap::new() }
    }

    /// Insert a component to an entity.
    pub fn insert(&mut self, e: Entity, comp: C) {
        self.data.insert(e, comp);
    }

    /// Return whether an entity contains this component.
    pub fn contains(&self, e: Entity) -> bool {
        self.data.contains_key(&e)
    }

    /// Get a reference to a component only if it exists for this entity.
    pub fn get(&self, e: Entity) -> Option<&C> {
        self.data.get(&e)
    }

    /// Get a mutable reference to a component only if it exists for this entity.
    pub fn get_mut(&mut self, e: Entity) -> Option<&mut C> {
        self.data.get_mut(&e)
    }

    /// Iterate entity-component pairs for this component.
    pub fn iter(&self) -> hash_map::Iter<Entity, C> {
        self.data.iter()
    }

    /// Iterate mutable entity-component pairs for this component.
    pub fn iter_mut(&mut self) -> hash_map::IterMut<Entity, C> {
        self.data.iter_mut()
    }
}

impl<C> Index<Entity> for ComponentData<C> {
    type Output = C;

    fn index<'a>(&'a self, e: Entity) -> &'a C {
        self.data.get(&e).unwrap()
    }
}

impl<C> IndexMut<Entity> for ComponentData<C> {
    fn index_mut<'a>(&'a mut self, e: Entity) -> &'a mut C {
        self.data.get_mut(&e).unwrap()
    }
}

impl<C> AnyComponent for ComponentData<C> {
    fn remove(&mut self, e: Entity) {
        self.data.remove(&e);
    }
}

pub trait Store {
    /// Perform an operation for each component container.
    fn for_each_component<F>(&mut self, f: F) where F: FnMut(&mut AnyComponent);
}

#[derive(Serialize, Deserialize)]
pub struct Ecs<ST> {
    next_uid: usize,
    active: HashSet<Entity>,
    store: ST,
}

impl<ST: Default + Store> Ecs<ST> {
    pub fn new() -> Ecs<ST> {
        Ecs {
            next_uid: 1,
            active: HashSet::new(),
            store: Default::default(),
        }
    }

    /// Create a new empty entity.
    pub fn make(&mut self) -> Entity {
        let next = self.next_uid;
        self.next_uid += 1;
        let ret = Entity(next);
        self.active.insert(ret);
        ret
    }

    /// Remove an entity from the system and clear its components.
    pub fn remove(&mut self, e: Entity) {
        self.active.remove(&e);
        self.store.for_each_component(|c| c.remove(e));
    }

    /// Return whether the system contains an entity.
    pub fn contains(&self, e: Entity) -> bool {
        self.active.contains(&e)
    }

    pub fn iter(&self) -> hash_set::Iter<Entity> {
        self.active.iter()
    }
}

impl<ST> Deref for Ecs<ST> {
    type Target = ST;

    fn deref(&self) -> &ST {
        &self.store
    }
}

impl<ST> DerefMut for Ecs<ST> {
    fn deref_mut(&mut self) -> &mut ST {
        &mut self.store
    }
}

/// Entity component system builder macro.
///
/// Defines a local `Ecs` type that's parametrized with a custom component
/// store type with the component types you specify. Will also define a trait
/// `Component` which will be implemented for the component types.
#[macro_export]
macro_rules! Ecs {
    {
        // Declare the type of the (plain old data) component and the
        // identifier to use for it in the ECS.
        $($compname:ident: $comptype:ty,)+
    } => {
        mod _ecs_inner {
            // Use the enum to convert components to numbers for component bit masks etc.
            #[allow(non_camel_case_types, dead_code)]
            pub enum ComponentNum {
                $($compname,)+
            }

        }

        pub use self::_ecs_inner::ComponentNum;

        pub struct _ComponentStore {
            $(pub $compname: $crate::ComponentData<$comptype>),+
        }

        impl ::serde::Serialize for _ComponentStore {
            fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
                where S: ::serde::Serializer {
                $(try!(self.$compname.serialize(serializer));)+
                Ok(())
            }
        }

        impl ::serde::Deserialize for _ComponentStore {
            fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
                where D: ::serde::Deserializer {
                Ok(_ComponentStore {
                    $($compname: try!($crate::ComponentData::deserialize(deserializer))),+
                })
            }
        }

        impl ::std::default::Default for _ComponentStore {
            fn default() -> _ComponentStore {
                _ComponentStore {
                    $($compname: $crate::ComponentData::new()),+
                }
            }
        }

        impl $crate::Store for _ComponentStore {
            fn for_each_component<F>(&mut self, mut f: F)
                where F: FnMut(&mut $crate::AnyComponent)
            {
                $(f(&mut self.$compname as &mut $crate::AnyComponent);)+
            }
        }

        #[allow(dead_code)]
        pub fn matches_mask(ecs: &$crate::Ecs<_ComponentStore>, e: $crate::Entity, mask: u64) -> bool {
            $(if mask & (1 << ComponentNum::$compname as u8) != 0 && !ecs.$compname.contains(e) {
                return false;
            })+
            return true;
        }

        /// Common operations for ECS component value types.
        pub trait Component {
            /// Add a clone of the component value to an entity in an ECS.
            ///
            /// Can't move the component itself since we might be using this
            /// through a trait object.
            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity);

            /// Add a clone of the component to a loadout struct.
            fn add_to_loadout(self, loadout: &mut Loadout);
        }

        $(impl Component for $comptype {
            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity) {
                ecs.$compname.insert(e, self.clone());
            }

            fn add_to_loadout(self, loadout: &mut Loadout) {
                loadout.$compname = Some(self);
            }
        })+

        pub type Ecs = $crate::Ecs<_ComponentStore>;

        /// A straightforward representation for the complete data of an
        /// entity.
        #[derive(Clone, Debug, Serialize, Deserialize)]
        pub struct Loadout {
            $(pub $compname: Option<$comptype>),+
        }

        impl ::std::default::Default for Loadout {
            fn default() -> Loadout {
                Loadout {
                    $($compname: None),+
                }
            }
        }

        #[allow(dead_code)]
        impl Loadout {
            /// Create a new blank loadout.
            pub fn new() -> Loadout { Default::default() }

            /// Get the loadout that corresponds to an existing entity.
            pub fn get(ecs: &Ecs, e: $crate::Entity) -> Loadout {
                Loadout {
                    $($compname: ecs.$compname.get(e).map(|e| e.clone())),+
                }
            }

            /// Create a new entity in the ECS with this loadout.
            pub fn make(&self, ecs: &mut Ecs) -> $crate::Entity {
                let e = ecs.make();
                $(self.$compname.as_ref().map(|c| ecs.$compname.insert(e, c.clone()));)+
                e
            }

            /// Builder method for adding a component to this loadout.
            pub fn c<C: Component>(mut self, comp: C) -> Loadout {
                comp.add_to_loadout(&mut self);
                self
            }
        }
    }
}

/// Build a component type mask to match component iteration with.
///
/// You must have ComponentNum enum from the Ecs! macro expansion in scope
/// when using this.
#[macro_export]
macro_rules! build_mask {
    ( $($compname:ident),+ ) => {
        0u64 $(| (1u64 << ComponentNum::$compname as u8))+
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Macros for deriving `VertexFormat` and `ShaderParam`.

#[macro_export]
macro_rules! gfx_vertex {
    ($name:ident {
        $($gl_name:ident@ $field:ident: $ty:ty,)*
    }) => {
        #[derive(Clone, Copy, Debug)]
        pub struct $name {
            $(pub $field: $ty,)*
        }
        impl $crate::VertexFormat for $name {
            fn generate<R: $crate::Resources>(buffer: &$crate::handle::Buffer<R, $name>)
                        -> Vec<$crate::Attribute<R>> {
                use std::mem::size_of;
                use $crate::attrib::{Offset, Stride};
                use $crate::attrib::format::ToFormat;
                let stride = size_of::<$name>() as Stride;
                let mut offset = 0 as Offset;
                let mut attributes = Vec::new();
                $(
                    let (count, etype) = <$ty as ToFormat>::describe();
                    let format = $crate::attrib::Format {
                        elem_count: count,
                        elem_type: etype,
                        offset: offset,
                        stride: stride,
                        instance_rate: 0,
                    };
                    attributes.push($crate::Attribute {
                        name: stringify!($gl_name).to_string(),
                        format: format,
                        buffer: buffer.raw().clone(),
                    });
                    offset += size_of::<$ty>() as Offset;
                )*
                assert_eq!(offset, stride as Offset);
                attributes
            }
        }
    }
}

#[macro_export]
macro_rules! gfx_parameters {
    ($name:ident {
        $($gl_name:ident@ $field:ident: $ty:ty,)*
    }) => {
        #[derive(Clone, Debug)]
        pub struct $name<R: $crate::Resources> {
            $(pub $field: $ty,)*
            pub _r: ::std::marker::PhantomData<R>,
        }

        impl<R: $crate::Resources> $crate::shade::ShaderParam for $name<R> {
            type Resources = R;
            type Link = ($((Option<$crate::shade::ParameterId>, ::std::marker::PhantomData<$ty>),)*);

            fn create_link(_: Option<&$name<R>>, info: &$crate::ProgramInfo)
                           -> Result<Self::Link, $crate::shade::ParameterError>
            {
                use $crate::shade::Parameter;
                $(
                    let mut $field = None;
                )*
                // scan uniforms
                for (i, u) in info.uniforms.iter().enumerate() {
                    match &u.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_uniform(u) {
                                return Err($crate::shade::ParameterError::BadUniform(u.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingUniform(u.name.clone()))
                    }
                }
                // scan uniform blocks
                for (i, b) in info.blocks.iter().enumerate() {
                    match &b.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_block(b) {
                                return Err($crate::shade::ParameterError::BadBlock(b.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingBlock(b.name.clone()))
                    }
                }
                // scan textures
                for (i, t) in info.textures.iter().enumerate() {
                    match &t.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_texture(t) {
                                return Err($crate::shade::ParameterError::BadBlock(t.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingBlock(t.name.clone()))
                    }
                }
                Ok(( $(($field, ::std::marker::PhantomData),)* ))
            }

            fn fill_params(&self, link: &Self::Link, storage: &mut $crate::ParamStorage<R>) {
                use $crate::shade::Parameter;
                let &($(($field, _),)*) = link;
                $(
                    if let Some(id) = $field {
                        self.$field.put(id, storage);
                    }
                )*
            }
        }
    }
}
<commit_msg>gfx_vertex! UB fix<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Macros for deriving `VertexFormat` and `ShaderParam`.

#[macro_export]
macro_rules! gfx_vertex {
    ($name:ident {
        $($gl_name:ident@ $field:ident: $ty:ty,)*
    }) => {
        #[derive(Clone, Copy, Debug)]
        pub struct $name {
            $(pub $field: $ty,)*
        }
        impl $crate::VertexFormat for $name {
            fn generate<R: $crate::Resources>(buffer: &$crate::handle::Buffer<R, $name>)
                        -> Vec<$crate::Attribute<R>> {
                use std::mem::size_of;
                use $crate::attrib::{Offset, Stride};
                use $crate::attrib::format::ToFormat;
                let stride = size_of::<$name>() as Stride;
                let tmp: $name = unsafe{ ::std::mem::uninitialized() };
                let mut attributes = Vec::new();
                $(
                    let (count, etype) = <$ty as ToFormat>::describe();
                    let format = $crate::attrib::Format {
                        elem_count: count,
                        elem_type: etype,
                        offset: (&tmp.$field as *const _ as usize) - (&tmp as *const _ as usize),
                        stride: stride,
                        instance_rate: 0,
                    };
                    attributes.push($crate::Attribute {
                        name: stringify!($gl_name).to_string(),
                        format: format,
                        buffer: buffer.raw().clone(),
                    });
                )*
                attributes
            }
        }
    }
}

#[macro_export]
macro_rules! gfx_parameters {
    ($name:ident {
        $($gl_name:ident@ $field:ident: $ty:ty,)*
    }) => {
        #[derive(Clone, Debug)]
        pub struct $name<R: $crate::Resources> {
            $(pub $field: $ty,)*
            pub _r: ::std::marker::PhantomData<R>,
        }

        impl<R: $crate::Resources> $crate::shade::ShaderParam for $name<R> {
            type Resources = R;
            type Link = ($((Option<$crate::shade::ParameterId>, ::std::marker::PhantomData<$ty>),)*);

            fn create_link(_: Option<&$name<R>>, info: &$crate::ProgramInfo)
                           -> Result<Self::Link, $crate::shade::ParameterError>
            {
                use $crate::shade::Parameter;
                $(
                    let mut $field = None;
                )*
                // scan uniforms
                for (i, u) in info.uniforms.iter().enumerate() {
                    match &u.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_uniform(u) {
                                return Err($crate::shade::ParameterError::BadUniform(u.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingUniform(u.name.clone()))
                    }
                }
                // scan uniform blocks
                for (i, b) in info.blocks.iter().enumerate() {
                    match &b.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_block(b) {
                                return Err($crate::shade::ParameterError::BadBlock(b.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingBlock(b.name.clone()))
                    }
                }
                // scan textures
                for (i, t) in info.textures.iter().enumerate() {
                    match &t.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_texture(t) {
                                return Err($crate::shade::ParameterError::BadBlock(t.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingBlock(t.name.clone()))
                    }
                }
                Ok(( $(($field, ::std::marker::PhantomData),)* ))
            }

            fn fill_params(&self, link: &Self::Link, storage: &mut $crate::ParamStorage<R>) {
                use $crate::shade::Parameter;
                let &($(($field, _),)*) = link;
                $(
                    if let Some(id) = $field {
                        self.$field.put(id, storage);
                    }
                )*
            }
        }
    }
}
<|endoftext|>