<commit_before>#[cfg(feature = "parsing")]
use buffer::Cursor;
#[cfg(feature = "parsing")]
use {lookahead, private};
#[cfg(feature = "parsing")]
use parse::{Parse, ParseStream, Result};
#[cfg(feature = "parsing")]
use token::Token;

pub use proc_macro2::Ident;

#[cfg(feature = "parsing")]
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn Ident(marker: lookahead::TokenMarker) -> Ident {
    match marker {}
}

#[cfg(feature = "parsing")]
fn accept_as_ident(ident: &Ident) -> bool {
    match ident.to_string().as_str() {
        "_" |
        // Based on https://doc.rust-lang.org/grammar.html#keywords
        // and https://github.com/rust-lang/rfcs/blob/master/text/2421-unreservations-2018.md
        // and https://github.com/rust-lang/rfcs/blob/master/text/2420-unreserve-proc.md
        "abstract" | "as" | "become" | "box" | "break" | "const" | "continue" |
        "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" |
        "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" |
        "mod" | "move" | "mut" | "override" | "priv" | "pub" | "ref" |
        "return" | "Self" | "self" | "static" | "struct" | "super" | "trait" |
        "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" |
        "where" | "while" | "yield" => false,
        _ => true,
    }
}

#[cfg(feature = "parsing")]
impl Parse for Ident {
    fn parse(input: ParseStream) -> Result<Self> {
        input.step(|cursor| {
            if let Some((ident, rest)) = cursor.ident() {
                if accept_as_ident(&ident) {
                    return Ok((ident, rest));
                }
            }
            Err(cursor.error("expected identifier"))
        })
    }
}

#[cfg(feature = "parsing")]
impl Token for Ident {
    fn peek(cursor: Cursor) -> bool {
        if let Some((ident, _rest)) = cursor.ident() {
            accept_as_ident(&ident)
        } else {
            false
        }
    }

    fn display() -> &'static str {
        "identifier"
    }
}

macro_rules! ident_from_token {
    ($token:ident) => {
        impl From<Token![$token]> for Ident {
            fn from(token: Token![$token]) -> Ident {
                Ident::new(stringify!($token), token.span)
            }
        }
    };
}

ident_from_token!(self);
ident_from_token!(Self);
ident_from_token!(super);
ident_from_token!(crate);
ident_from_token!(extern);

impl From<Token![_]> for Ident {
    fn from(token: Token![_]) -> Ident {
        Ident::new("_", token.span)
    }
}

#[cfg(feature = "parsing")]
impl private {
    #[cfg(syn_can_use_associated_constants)]
    pub fn peek_any_ident(input: ParseStream) -> bool {
        use ext::IdentExt;
        input.peek(Ident::peek_any)
    }

    #[cfg(not(syn_can_use_associated_constants))]
    pub fn peek_any_ident(input: ParseStream) -> bool {
        input.cursor().ident().is_some()
    }
}
<commit_msg>Format with rustfmt 2019-06-09<commit_after>#[cfg(feature = "parsing")]
use buffer::Cursor;
#[cfg(feature = "parsing")]
use parse::{Parse, ParseStream, Result};
#[cfg(feature = "parsing")]
use token::Token;
#[cfg(feature = "parsing")]
use {lookahead, private};

pub use proc_macro2::Ident;

#[cfg(feature = "parsing")]
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn Ident(marker: lookahead::TokenMarker) -> Ident {
    match marker {}
}

#[cfg(feature = "parsing")]
fn accept_as_ident(ident: &Ident) -> bool {
    match ident.to_string().as_str() {
        "_" |
        // Based on https://doc.rust-lang.org/grammar.html#keywords
        // and https://github.com/rust-lang/rfcs/blob/master/text/2421-unreservations-2018.md
        // and https://github.com/rust-lang/rfcs/blob/master/text/2420-unreserve-proc.md
        "abstract" | "as" | "become" | "box" | "break" | "const" | "continue" |
        "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" |
        "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" |
        "mod" | "move" | "mut" | "override" | "priv" | "pub" | "ref" |
        "return" | "Self" | "self" | "static" | "struct" | "super" | "trait" |
        "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" |
        "where" | "while" | "yield" => false,
        _ => true,
    }
}

#[cfg(feature = "parsing")]
impl Parse for Ident {
    fn parse(input: ParseStream) -> Result<Self> {
        input.step(|cursor| {
            if let Some((ident, rest)) = cursor.ident() {
                if accept_as_ident(&ident) {
                    return Ok((ident, rest));
                }
            }
            Err(cursor.error("expected identifier"))
        })
    }
}

#[cfg(feature = "parsing")]
impl Token for Ident {
    fn peek(cursor: Cursor) -> bool {
        if let Some((ident, _rest)) = cursor.ident() {
            accept_as_ident(&ident)
        } else {
            false
        }
    }

    fn display() -> &'static str {
        "identifier"
    }
}

macro_rules! ident_from_token {
    ($token:ident) => {
        impl From<Token![$token]> for Ident {
            fn from(token: Token![$token]) -> Ident {
                Ident::new(stringify!($token), token.span)
            }
        }
    };
}

ident_from_token!(self);
ident_from_token!(Self);
ident_from_token!(super);
ident_from_token!(crate);
ident_from_token!(extern);

impl From<Token![_]> for Ident {
    fn from(token: Token![_]) -> Ident {
        Ident::new("_", token.span)
    }
}

#[cfg(feature = "parsing")]
impl private {
    #[cfg(syn_can_use_associated_constants)]
    pub fn peek_any_ident(input: ParseStream) -> bool {
        use ext::IdentExt;
        input.peek(Ident::peek_any)
    }

    #[cfg(not(syn_can_use_associated_constants))]
    pub fn peek_any_ident(input: ParseStream) -> bool {
        input.cursor().ident().is_some()
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Martin Grabmueller. See the LICENSE file at the
// top-level directory of this distribution for license information.

//! Simple implementation of an LZ77+Huffman compressor.

use std::io::{Read, Write};
use std::io;

const WINDOW_SIZE: usize = 40; //1 << 12;
const LOOK_AHEAD_SIZE: usize = 17;

const WINDOW_BUFFER_SIZE: usize = WINDOW_SIZE * 2 + LOOK_AHEAD_SIZE;

pub struct CompressWriter<W> {
    inner: W,
    window: [u8; WINDOW_BUFFER_SIZE],
    position: usize,
    limit: usize,
    current_buffer: usize,
}

impl<W> CompressWriter<W> {
    pub fn new(inner: W) -> CompressWriter<W>{
        CompressWriter {
            inner: inner,
            window: [0; WINDOW_BUFFER_SIZE],
            position: 0,
            limit: 0,
            current_buffer: 0,
        }
    }

    pub fn dump_window(&self) {
        println!("");
        for i in 0..WINDOW_BUFFER_SIZE {
            if i == 0 {
                print!("|");
            } else if i == WINDOW_SIZE {
                print!("|");
            } else if i == WINDOW_SIZE * 2 {
                print!("|");
            } else {
                print!(" ");
            }
        }
        println!("|");
        for i in 0..WINDOW_BUFFER_SIZE + 1 {
            if i == self.position + LOOK_AHEAD_SIZE {
                print!("v");
            } else {
                print!(" ");
            }
        }
        println!("");
        for i in 0..self.limit {
            if self.window[i] >= 32 && self.window[i] < 128 {
                print!("{}", self.window[i] as char);
            } else {
                print!("?");
            }
        }
        for _ in self.limit..WINDOW_BUFFER_SIZE {
            print!("~");
        }
        println!("");
        for i in 0..WINDOW_BUFFER_SIZE + 1 {
            if i == self.position {
                print!("p");
            } else if i == self.limit {
                print!("|");
            } else if i + WINDOW_SIZE >= self.position && i < self.position {
                print!("-");
            } else {
                print!(" ");
            }
        }
        println!("");
        for i in 0..WINDOW_BUFFER_SIZE + 1 {
            if i == self.limit {
                print!("l");
            } else {
                print!(" ");
            }
        }
        println!("");
    }

    fn process(&mut self, flush: bool) {
        let headroom = if flush { 0 } else { LOOK_AHEAD_SIZE };
        while self.position + headroom < self.limit {

            // Do compression magic here...

            // ... and advance position.
            let pos = self.position;
            self.hash(pos);
            self.position += 1;
        }
    }

    fn hash(&mut self, _i: usize) {
        // Add entry at position `i` to hash table.
    }

    fn unhash(&mut self, _i: usize) {
        // Remove entry at position `i` from hash table because it is
        // about to be overwritten.
    }

    fn slide_down(&mut self) {
        for i in 0..WINDOW_SIZE + LOOK_AHEAD_SIZE {
            self.unhash(i);
            self.window[i] = self.window[i + WINDOW_SIZE];
        }
        self.position -= WINDOW_SIZE;
        self.limit -= WINDOW_SIZE;
    }
}

impl<W: Write> Write for CompressWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let space = WINDOW_BUFFER_SIZE - self.limit;
        if space > 0 {
            let amount = ::std::cmp::min(space, buf.len());
            for t in 0..amount {
                self.window[self.limit + t] = buf[t];
            }
            self.limit += amount;

            self.process(false);

            if self.position >= WINDOW_SIZE * 2 {
                self.slide_down();
            }
            Ok(amount)
        } else {
            Ok(0)
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        while self.position < self.limit {
            self.process(true);
        }
        Ok(())
    }
}

pub struct DecompressReader<R> {
    inner: R,
}

impl<R> DecompressReader<R> {
    pub fn new(inner: R) -> DecompressReader<R> {
        DecompressReader {
            inner: inner,
        }
    }
}

impl<R: Read> Read for DecompressReader<R> {
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
        Ok(0)
    }
}

#[cfg(test)]
mod tests {
//    use ::std::io::Cursor;

    use super::CompressWriter;
    use ::std::io::Write;

    #[test]
    fn compress_empty() {
        let mut cw = CompressWriter::new(vec![]);
        let data = b"abcdefg. ";
        cw.write(&data[..]).unwrap();
        cw.dump_window();

        let data = b"let x = 1; let y = 2; let z = x * 2 + y;";
        cw.write(&data[..]).unwrap();
        cw.dump_window();

        let data = b".0123456789.0123456789.";
        cw.write(&data[..]).unwrap();
        cw.dump_window();

        let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ.";
        cw.write_all(&data[..]).unwrap();
        cw.dump_window();

        cw.flush().unwrap();
        cw.dump_window();
//        assert!(false);
    }

    #[test]
    fn compress_decompress() {
        let input = include_bytes!("lzmg1.rs");
        let mut cw = CompressWriter::new(vec![]);
        cw.write_all(&input[..]).unwrap();
        cw.dump_window();
        cw.flush().unwrap();
        cw.dump_window();
        assert!(false);
    }
}
<commit_msg>Implement variant of LZ77 compression as a Writer.<commit_after>// Copyright 2016 Martin Grabmueller. See the LICENSE file at the
// top-level directory of this distribution for license information.

//! Simple implementation of an LZ77+Huffman compressor.

use std::io::{Read, Write};
use std::io;

const MAX_MATCH: usize = 1 << 4;
const MIN_MATCH: usize = 3;

const WINDOW_SIZE: usize = 1 << 12;
//const WINDOW_SIZE: usize = 30;
const LOOK_AHEAD_SIZE: usize = MAX_MATCH + MIN_MATCH;

const WINDOW_BUFFER_SIZE: usize = WINDOW_SIZE * 2 + LOOK_AHEAD_SIZE;
const HASHTAB_SIZE: usize = 1 << 10;
//const HASHTAB_SIZE: usize = 1 << 5;

const UNUSED: usize = !0;

pub struct CompressWriter<W> {
    inner:    W,
    window:   [u8; WINDOW_BUFFER_SIZE],
    hashtab:  [usize; HASHTAB_SIZE],
    hashes:   [usize; WINDOW_BUFFER_SIZE],
    position: usize,
    limit:    usize,

    emit_token: u8,
    emit_cnt: usize,
    emit_data: [u8; 17],
    emit_len: usize,
    hash_collisions: usize,
}

impl<W: Write> CompressWriter<W> {
    pub fn new(inner: W) -> CompressWriter<W>{
        CompressWriter {
            inner:    inner,
            window:   [0; WINDOW_BUFFER_SIZE],
            hashtab:  [UNUSED; HASHTAB_SIZE],
            hashes:   [UNUSED; WINDOW_BUFFER_SIZE],
            position: 0,
            limit:    0,
            emit_token: 0,
            emit_cnt: 0,
            emit_data: [0; 2 * 8 + 1], // max. 2 bytes for pos/len * 8 + token
            emit_len: 0,
            hash_collisions: 0,
        }
    }

    pub fn dump_window(&self) {
        println!("");
        for i in 0..WINDOW_BUFFER_SIZE {
            if i == 0 {
                print!("|");
            } else if i == WINDOW_SIZE {
                print!("|");
            } else if i == WINDOW_SIZE * 2 {
                print!("|");
            } else {
                print!(" ");
            }
        }
        println!("|");
        for i in 0..WINDOW_BUFFER_SIZE + 1 {
            if i == self.position + LOOK_AHEAD_SIZE {
                print!("v");
            } else {
                print!(" ");
            }
        }
        println!("");
        for i in 0..self.limit {
            if self.window[i] >= 32 && self.window[i] < 128 {
                print!("{}", self.window[i] as char);
            } else {
                print!("?");
            }
        }
        for _ in self.limit..WINDOW_BUFFER_SIZE {
            print!("~");
        }
        println!("");
        for i in 0..WINDOW_BUFFER_SIZE + 1 {
            if i == self.position {
                print!("p");
            } else if i == self.limit {
                print!("|");
            } else if i + WINDOW_SIZE >= self.position && i < self.position {
                print!("-");
            } else {
                print!(" ");
            }
        }
        println!("");
        for i in 0..WINDOW_BUFFER_SIZE + 1 {
            if i == self.limit {
                print!("l");
            } else {
                print!(" ");
            }
        }
        println!("");
        for i in 0..WINDOW_BUFFER_SIZE {
            if self.hashes[i] == UNUSED {
                print!(".");
            } else {
                print!("^");
            }
        }
        println!("");
        for i in 0..HASHTAB_SIZE {
            if self.hashtab[i] == UNUSED {
                print!("|--");
            } else {
                print!("|{:2}", self.hashtab[i]);
            }
        }
        println!("|");
        println!("Hash coll: {}", self.hash_collisions);
    }

    fn emit_flush(&mut self) -> io::Result<()> {

        self.emit_data[0] = self.emit_token;
        try!(self.inner.write(&self.emit_data[0..self.emit_len + 1]));
        self.emit_token = 0;
        self.emit_cnt = 0;
        self.emit_len = 0;
        Ok(())
    }

    fn emit_literal(&mut self, l: u8) -> io::Result<()> {
        if self.emit_cnt == 8 {
            try!(self.emit_flush());
        }
        self.emit_token = (self.emit_token << 1) | 1;
        self.emit_data[self.emit_len + 1] = l;
        self.emit_cnt += 1;
        self.emit_len += 1;
        Ok(())
    }

    fn emit_match(&mut self, ofs: usize, len: usize) -> io::Result<()> {
        if self.emit_cnt == 8 {
            try!(self.emit_flush());
        }
        let lp1: u8 = ((((len - MIN_MATCH) as u8) & 0x0f)  << 4) | (ofs as u8) & 0x0f;
        let p2: u8 = ((ofs as u8) >> 4) & 0xff;
        self.emit_token = self.emit_token << 1;
        self.emit_data[self.emit_len + 1] = lp1;
        self.emit_data[self.emit_len + 2] = p2;
        self.emit_cnt += 1;
        self.emit_len += 2;
        Ok(())
    }

    fn process(&mut self, flush: bool) -> io::Result<()> {
        let headroom = if flush { 0 } else { LOOK_AHEAD_SIZE };
        while self.position + headroom < self.limit {

            let h = self.calc_hash(self.position);
            let search_pos = self.hashtab[h];
            let mut match_len = 0;

            if search_pos != UNUSED {
                for i in 0..MAX_MATCH {
                    if search_pos + i >= self.limit {
                        break;
                    }
                    if self.window[search_pos + i] != self.window[self.position + i] {
                        break;
                    }
                    match_len += 1;
                }
                if match_len > 0 {
                }
            }
            let replace =
                if match_len > MIN_MATCH {
                    let ofs = self.position - search_pos;
                    try!(self.emit_match(ofs, match_len));
                    println!("match: len: {}, ofs: {} ({} -> {})", match_len, ofs,
                             search_pos, self.position);
                    match_len
                } else {
                    let lit = self.window[self.position];
                    try!(self.emit_literal(lit));
                    println!("literal: {:?}", self.window[self.position]);
                    1
                };
            for _ in 0..replace {
                let pos = self.position;
                if pos >= WINDOW_SIZE {
                    self.unhash(pos - WINDOW_SIZE);
                }
                self.hash(pos);
                self.position += 1;
            }
        }
        Ok(())
    }

    fn calc_hash(&self, i: usize) -> usize {
        let mut hash: usize = 0;
        for x in i .. ::std::cmp::min(i + 3, self.limit) {
            hash = (hash << 8) | self.window[x] as usize;
        }
        hash = ((hash >> 5) ^ hash) & (HASHTAB_SIZE - 1);
        hash
    }

    fn hash(&mut self, i: usize) {
        let hash = self.calc_hash(i);
        if self.hashtab[hash] != UNUSED {
            self.hash_collisions += 1;
        }
        self.hashtab[hash] = i;
        self.hashes[i] = hash;
    }

    fn unhash(&mut self, i: usize) {
        let hashpos = self.hashes[i];
        if hashpos != UNUSED {
            self.hashtab[hashpos] = UNUSED;
            self.hashes[i] = UNUSED;
        }
    }

    fn slide_down(&mut self) {
        for i in 0..WINDOW_BUFFER_SIZE {
            self.unhash(i);
        }
        for i in 0..WINDOW_SIZE + LOOK_AHEAD_SIZE {
            self.window[i] = self.window[i + WINDOW_SIZE];
        }
        self.position -= WINDOW_SIZE;
        self.limit -= WINDOW_SIZE;
        for i in 0..::std::cmp::min(self.position, WINDOW_SIZE) {
            self.hash(i);
        }
    }

    pub fn to_inner(self) -> W {
        self.inner
    }
}

impl<W: Write> Write for CompressWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let space = WINDOW_BUFFER_SIZE - self.limit;
        if space > 0 {
            let amount = ::std::cmp::min(space, buf.len());
            for t in 0..amount {
                self.window[self.limit + t] = buf[t];
            }
            self.limit += amount;

            try!(self.process(false));

            if self.position >= WINDOW_SIZE * 2 {
                self.slide_down();
            }
            Ok(amount)
        } else {
            Ok(0)
        }
    }

    /// Flush the compression writer.  This will cause all not-yet
    /// written data to be compressed and written to the underlying
    /// Writer, which is also flushed.
    fn flush(&mut self) -> io::Result<()> {
        // Process remaining window contents. `true` indicates to go
        // to the end, including the look-ahead buffer.
        try!(self.process(true));
        try!(self.emit_flush());
        self.inner.flush()
    }
}

pub struct DecompressReader<R> {
    inner: R,
}

impl<R> DecompressReader<R> {
    pub fn new(inner: R) -> DecompressReader<R> {
        DecompressReader {
            inner: inner,
        }
    }
}

impl<R: Read> Read for DecompressReader<R> {
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
        Ok(0)
    }
}

#[cfg(test)]
mod tests {
//    use ::std::io::Cursor;

    use super::CompressWriter;
    use ::std::io::Write;

    #[test]
    fn compress_empty() {
        let mut cw = CompressWriter::new(vec![]);
        let data = b"abcdefghij";
        cw.write(&data[..]).unwrap();
        cw.dump_window();

        cw.write(&data[..]).unwrap();
        cw.dump_window();

        cw.write(&data[..]).unwrap();
        cw.dump_window();

        cw.write(&data[..]).unwrap();
        cw.dump_window();

        cw.flush().unwrap();
        cw.dump_window();
        let compressed = cw.to_inner();
        println!("comp: {:?}", compressed);
        println!("ratio: {:.2}%",
                 1f32 - (compressed.len() as f32 / (data.len() * 4) as f32));
//        assert!(false);
    }

    #[test]
    fn compress_decompress() {
        let input = include_bytes!("lzmg1.rs");
        let mut cw = CompressWriter::new(vec![]);
        cw.write_all(&input[..]).unwrap();
        cw.flush().unwrap();
//        cw.dump_window();
        let compressed = cw.to_inner();
        println!("ratio: {:.2}%",
                 1f32 - (compressed.len() as f32 / input.len() as f32));
        assert!(false);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// 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.

/// Inclusive range from min to max
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct InclusiveRange<T: Copy + PartialOrd> {
    pub min: T,
    pub max: T
}

pub const RANGE_0_1_F32: InclusiveRange<f32> = InclusiveRange { min: 0.0, max: 0.0 };

fn pomax<T: PartialOrd>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

fn pomin<T: PartialOrd>(a: T, b: T) -> T {
    if a < b { a } else { b }
}

impl<T: Copy + PartialOrd> InclusiveRange<T> {
    /// Create an InclusiveRange range from min to max
    pub fn new(min: T, max: T) -> InclusiveRange<T> {
        assert!(min <= max);
        InclusiveRange { min: min, max: max }
    }

    /// Expand `self` as needed to include another range.
    pub fn expand(&mut self, other: &InclusiveRange<T>) {
        self.min = pomin(self.min, other.min);
        self.max = pomax(self.max, other.max);
    }
}

/// Create range covering the overlap between two ranges, or None if
/// there is no overlap.
pub fn range_clamp<T: Copy + PartialOrd>(a: &InclusiveRange<T>,
                                         b: &InclusiveRange<T>)
                                         -> Option<InclusiveRange<T>> {
    let min = pomax(a.min, b.min);
    let max = pomin(a.max, b.max);

    if min <= max {
        Some(InclusiveRange::new(min, max))
    }
    else {
        None
    }
}

/// Create range covering both ranges (and any gap between them).
pub fn range_combine<T: Copy + PartialOrd>(a: &InclusiveRange<T>,
                                           b: &InclusiveRange<T>) -> InclusiveRange<T> {
    InclusiveRange::new(pomin(a.min, b.min),
                        pomax(a.max, b.max))
}

#[test]
fn test_range_clamp() {
    assert!(range_clamp(&InclusiveRange::new(0, 2),
                        &InclusiveRange::new(0, 2)) ==
            Some(InclusiveRange::new(0, 2)));

    assert!(range_clamp(&InclusiveRange::new(0, 1),
                        &InclusiveRange::new(2, 3)) ==
            None);

    assert!(range_clamp(&InclusiveRange::new(2, 3),
                        &InclusiveRange::new(0, 1)) ==
            None);

    assert!(range_clamp(&InclusiveRange::new(0, 2),
                        &InclusiveRange::new(1, 3)) ==
            Some(InclusiveRange::new(1, 2)));

    assert!(range_clamp(&InclusiveRange::new(1, 3),
                        &InclusiveRange::new(0, 2)) ==
            Some(InclusiveRange::new(1, 2)));

    assert!(range_clamp(&InclusiveRange::new(1.0, 3.0),
                        &InclusiveRange::new(0.0, 2.0)) ==
            Some(InclusiveRange::new(1.0, 2.0)));
}

#[test]
fn test_range_expand() {
    let mut r = InclusiveRange::new(0, 1);
    r.expand(&InclusiveRange::new(-1, 2));
    assert!(r == InclusiveRange::new(-1, 2));
}

#[test]
fn test_range_combine() {
    assert!(range_combine(&InclusiveRange::new(0, 2),
                          &InclusiveRange::new(-2, 1)) ==
            InclusiveRange::new(-2, 2));
}
<commit_msg>Add range length<commit_after>// Copyright 2015 Nicholas Bishop
//
// 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.

use std::ops::Sub;

/// Inclusive range from min to max
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct InclusiveRange<T: Copy + PartialOrd + Sub> {
    pub min: T,
    pub max: T
}

pub const RANGE_0_1_F32: InclusiveRange<f32> = InclusiveRange { min: 0.0, max: 0.0 };

fn pomax<T: PartialOrd>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

fn pomin<T: PartialOrd>(a: T, b: T) -> T {
    if a < b { a } else { b }
}

impl<T: Copy + PartialOrd + Sub<Output=T>> InclusiveRange<T> {
    /// Create an InclusiveRange range from min to max
    pub fn new(min: T, max: T) -> InclusiveRange<T> {
        assert!(min <= max);
        InclusiveRange { min: min, max: max }
    }

    /// Distance between self.min and self.max
    pub fn length(&self) -> T {
        self.max - self.min
    }

    /// Expand `self` as needed to include another range.
    pub fn expand(&mut self, other: &InclusiveRange<T>) {
        self.min = pomin(self.min, other.min);
        self.max = pomax(self.max, other.max);
    }
}

/// Create range covering the overlap between two ranges, or None if
/// there is no overlap.
pub fn range_clamp<T: Copy + PartialOrd + Sub<Output=T>>
    (a: &InclusiveRange<T>, b: &InclusiveRange<T>)
     -> Option<InclusiveRange<T>> {
    let min = pomax(a.min, b.min);
    let max = pomin(a.max, b.max);

    if min <= max {
        Some(InclusiveRange::new(min, max))
    }
    else {
        None
    }
}

/// Create range covering both ranges (and any gap between them).
pub fn range_combine<T: Copy + PartialOrd + Sub<Output=T>>(a: &InclusiveRange<T>,
                                                           b: &InclusiveRange<T>)
                                                           -> InclusiveRange<T> {
    InclusiveRange::new(pomin(a.min, b.min),
                        pomax(a.max, b.max))
}

#[test]
fn test_range_clamp() {
    assert!(range_clamp(&InclusiveRange::new(0, 2),
                        &InclusiveRange::new(0, 2)) ==
            Some(InclusiveRange::new(0, 2)));

    assert!(range_clamp(&InclusiveRange::new(0, 1),
                        &InclusiveRange::new(2, 3)) ==
            None);

    assert!(range_clamp(&InclusiveRange::new(2, 3),
                        &InclusiveRange::new(0, 1)) ==
            None);

    assert!(range_clamp(&InclusiveRange::new(0, 2),
                        &InclusiveRange::new(1, 3)) ==
            Some(InclusiveRange::new(1, 2)));

    assert!(range_clamp(&InclusiveRange::new(1, 3),
                        &InclusiveRange::new(0, 2)) ==
            Some(InclusiveRange::new(1, 2)));

    assert!(range_clamp(&InclusiveRange::new(1.0, 3.0),
                        &InclusiveRange::new(0.0, 2.0)) ==
            Some(InclusiveRange::new(1.0, 2.0)));
}

#[test]
fn test_range_expand() {
    let mut r = InclusiveRange::new(0, 1);
    r.expand(&InclusiveRange::new(-1, 2));
    assert!(r == InclusiveRange::new(-1, 2));
}

#[test]
fn test_range_combine() {
    assert!(range_combine(&InclusiveRange::new(0, 2),
                          &InclusiveRange::new(-2, 1)) ==
            InclusiveRange::new(-2, 2));
}

#[test]
fn test_range_length() {
    assert!(InclusiveRange::new(-1, 2).length() == 3);
    assert!(InclusiveRange::new(-1.0, 2.5).length() == 3.5);
}
<|endoftext|>


<commit_before>use std::mem;
use std::os::unix::io::RawFd;
use std::option::Option;
use libc::{self, c_int, c_void, pid_t};
use {Errno, Error, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
libc_bitflags!{
    flags CloneFlags: libc::c_int {
        CLONE_VM,
        CLONE_FS,
        CLONE_FILES,
        CLONE_SIGHAND,
        CLONE_PTRACE,
        CLONE_VFORK,
        CLONE_PARENT,
        CLONE_THREAD,
        CLONE_NEWNS,
        CLONE_SYSVSEM,
        CLONE_SETTLS,
        CLONE_PARENT_SETTID,
        CLONE_CHILD_CLEARTID,
        CLONE_DETACHED,
        CLONE_UNTRACED,
        CLONE_CHILD_SETTID,
        CLONE_NEWUTS,
        CLONE_NEWIPC,
        CLONE_NEWUSER,
        CLONE_NEWPID,
        CLONE_NEWNET,
        CLONE_IO,
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_set: libc::cpu_set_t,
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet { cpu_set: unsafe { mem::zeroed() } }
    }

    pub fn is_set(&self, field: usize) -> Result<bool> {
        if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
            Err(Error::Sys(Errno::EINVAL))
        } else {
            Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
        }
    }

    pub fn set(&mut self, field: usize) -> Result<()> {
        if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
            Err(Error::Sys(Errno::EINVAL))
        } else {
            Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
        }
    }

    pub fn unset(&mut self, field: usize) -> Result<()> {
        if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
            Err(Error::Sys(Errno::EINVAL))
        } else {
            Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
        }
    }
}

mod ffi {
    use libc::{c_void, c_int};

    pub type CloneCb = extern "C" fn(data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern "C" {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(cb: *const CloneCb,
                     child_stack: *mut c_void,
                     flags: c_int,
                     arg: *mut super::CloneCb,
                     ...)
                     -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    let res = unsafe {
        libc::sched_setaffinity(pid as libc::pid_t,
                                mem::size_of::<CpuSet>() as libc::size_t,
                                mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb,
             stack: &mut [u8],
             flags: CloneFlags,
             signal: Option<c_int>)
             -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let combined = flags.bits() | signal.unwrap_or(0);
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32),
                   ptr as *mut c_void,
                   combined,
                   &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { libc::unshare(flags.bits()) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { libc::setns(fd, nstype.bits()) };

    Errno::result(res).map(drop)
}
<commit_msg>Add CLONE_NEWCGROUP<commit_after>use std::mem;
use std::os::unix::io::RawFd;
use std::option::Option;
use libc::{self, c_int, c_void, pid_t};
use {Errno, Error, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
libc_bitflags!{
    flags CloneFlags: libc::c_int {
        CLONE_VM,
        CLONE_FS,
        CLONE_FILES,
        CLONE_SIGHAND,
        CLONE_PTRACE,
        CLONE_VFORK,
        CLONE_PARENT,
        CLONE_THREAD,
        CLONE_NEWNS,
        CLONE_SYSVSEM,
        CLONE_SETTLS,
        CLONE_PARENT_SETTID,
        CLONE_CHILD_CLEARTID,
        CLONE_DETACHED,
        CLONE_UNTRACED,
        CLONE_CHILD_SETTID,
        CLONE_NEWCGROUP,
        CLONE_NEWUTS,
        CLONE_NEWIPC,
        CLONE_NEWUSER,
        CLONE_NEWPID,
        CLONE_NEWNET,
        CLONE_IO,
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_set: libc::cpu_set_t,
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet { cpu_set: unsafe { mem::zeroed() } }
    }

    pub fn is_set(&self, field: usize) -> Result<bool> {
        if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
            Err(Error::Sys(Errno::EINVAL))
        } else {
            Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
        }
    }

    pub fn set(&mut self, field: usize) -> Result<()> {
        if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
            Err(Error::Sys(Errno::EINVAL))
        } else {
            Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
        }
    }

    pub fn unset(&mut self, field: usize) -> Result<()> {
        if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
            Err(Error::Sys(Errno::EINVAL))
        } else {
            Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
        }
    }
}

mod ffi {
    use libc::{c_void, c_int};

    pub type CloneCb = extern "C" fn(data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern "C" {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(cb: *const CloneCb,
                     child_stack: *mut c_void,
                     flags: c_int,
                     arg: *mut super::CloneCb,
                     ...)
                     -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    let res = unsafe {
        libc::sched_setaffinity(pid as libc::pid_t,
                                mem::size_of::<CpuSet>() as libc::size_t,
                                mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb,
             stack: &mut [u8],
             flags: CloneFlags,
             signal: Option<c_int>)
             -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let combined = flags.bits() | signal.unwrap_or(0);
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32),
                   ptr as *mut c_void,
                   combined,
                   &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { libc::unshare(flags.bits()) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { libc::setns(fd, nstype.bits()) };

    Errno::result(res).map(drop)
}
<|endoftext|>


<commit_before>use std::mem;
use std::os::unix::io::RawFd;
use libc::{self, c_int, c_void, c_ulong, pid_t};
use {Errno, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
bitflags!{
    flags CloneFlags: c_int {
        const CLONE_VM             = libc::CLONE_VM,
        const CLONE_FS             = libc::CLONE_FS,
        const CLONE_FILES          = libc::CLONE_FILES,
        const CLONE_SIGHAND        = libc::CLONE_SIGHAND,
        const CLONE_PTRACE         = libc::CLONE_PTRACE,
        const CLONE_VFORK          = libc::CLONE_VFORK,
        const CLONE_PARENT         = libc::CLONE_PARENT,
        const CLONE_THREAD         = libc::CLONE_THREAD,
        const CLONE_NEWNS          = libc::CLONE_NEWNS,
        const CLONE_SYSVSEM        = libc::CLONE_SYSVSEM,
        const CLONE_SETTLS         = libc::CLONE_SETTLS,
        const CLONE_PARENT_SETTID  = libc::CLONE_PARENT_SETTID,
        const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID,
        const CLONE_DETACHED       = libc::CLONE_DETACHED,
        const CLONE_UNTRACED       = libc::CLONE_UNTRACED,
        const CLONE_CHILD_SETTID   = libc::CLONE_CHILD_SETTID,
        // TODO: Once, we use a version containing
        // https://github.com/rust-lang-nursery/libc/pull/147
        // get rid of the casts.
        const CLONE_NEWUTS         = libc::CLONE_NEWUTS as c_int,
        const CLONE_NEWIPC         = libc::CLONE_NEWIPC as c_int,
        const CLONE_NEWUSER        = libc::CLONE_NEWUSER as c_int,
        const CLONE_NEWPID         = libc::CLONE_NEWPID as c_int,
        const CLONE_NEWNET         = libc::CLONE_NEWNET as c_int,
        const CLONE_IO             = libc::CLONE_IO as c_int,
    }
}

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "android"))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:          usize = 1024;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: c_int,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: c_int) -> c_int;

        // reassociate thread with a namespace
        // doc: http://man7.org/linux/man-pages/man2/setns.2.html
        pub fn setns(fd: c_int, nstype: c_int) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback), ptr as *mut c_void, flags.bits(), &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags.bits()) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::setns(fd, nstype.bits()) };

    Errno::result(res).map(drop)
}
<commit_msg>Auto merge of #353 - fiveop:nightly_warning, r=kamalmarhubi<commit_after>use std::mem;
use std::os::unix::io::RawFd;
use libc::{self, c_int, c_void, c_ulong, pid_t};
use {Errno, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
bitflags!{
    flags CloneFlags: c_int {
        const CLONE_VM             = libc::CLONE_VM,
        const CLONE_FS             = libc::CLONE_FS,
        const CLONE_FILES          = libc::CLONE_FILES,
        const CLONE_SIGHAND        = libc::CLONE_SIGHAND,
        const CLONE_PTRACE         = libc::CLONE_PTRACE,
        const CLONE_VFORK          = libc::CLONE_VFORK,
        const CLONE_PARENT         = libc::CLONE_PARENT,
        const CLONE_THREAD         = libc::CLONE_THREAD,
        const CLONE_NEWNS          = libc::CLONE_NEWNS,
        const CLONE_SYSVSEM        = libc::CLONE_SYSVSEM,
        const CLONE_SETTLS         = libc::CLONE_SETTLS,
        const CLONE_PARENT_SETTID  = libc::CLONE_PARENT_SETTID,
        const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID,
        const CLONE_DETACHED       = libc::CLONE_DETACHED,
        const CLONE_UNTRACED       = libc::CLONE_UNTRACED,
        const CLONE_CHILD_SETTID   = libc::CLONE_CHILD_SETTID,
        // TODO: Once, we use a version containing
        // https://github.com/rust-lang-nursery/libc/pull/147
        // get rid of the casts.
        const CLONE_NEWUTS         = libc::CLONE_NEWUTS as c_int,
        const CLONE_NEWIPC         = libc::CLONE_NEWIPC as c_int,
        const CLONE_NEWUSER        = libc::CLONE_NEWUSER as c_int,
        const CLONE_NEWPID         = libc::CLONE_NEWPID as c_int,
        const CLONE_NEWNET         = libc::CLONE_NEWNET as c_int,
        const CLONE_IO             = libc::CLONE_IO as c_int,
    }
}

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "android"))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:          usize = 1024;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: c_int,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: c_int) -> c_int;

        // reassociate thread with a namespace
        // doc: http://man7.org/linux/man-pages/man2/setns.2.html
        pub fn setns(fd: c_int, nstype: c_int) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32),
                   ptr as *mut c_void,
                   flags.bits(),
                   &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags.bits()) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::setns(fd, nstype.bits()) };

    Errno::result(res).map(drop)
}
<|endoftext|>


<commit_before>//! This module contains the parallel iterator types for slices
//! (`[T]`). You will rarely need to interact with it directly unless
//! you have need to name one of those types.

use iter::*;
use iter::internal::*;

/// Parallel extensions for slices.
///
/// Implementing this trait is not permitted outside of `rayon`.
pub trait ParallelSlice<T> {
    private_decl!{}

    /// Returns a parallel iterator over all contiguous windows of
    /// length `size`. The windows overlap.
    fn par_windows(&self, size: usize) -> Windows<T> where T: Sync;

    /// Returns a parallel iterator over at most `size` elements of
    /// `self` at a time. The chunks do not overlap.
    fn par_chunks(&self, size: usize) -> Chunks<T> where T: Sync;

    /// Returns a parallel iterator over at most `size` elements of
    /// `self` at a time. The chunks are mutable and do not overlap.
    fn par_chunks_mut(&mut self, size: usize) -> ChunksMut<T> where T: Send;
}

impl<T> ParallelSlice<T> for [T] {
    private_impl!{}

    fn par_windows(&self, window_size: usize) -> Windows<T> where T: Sync {
        Windows {
            window_size: window_size,
            slice: self,
        }
    }

    fn par_chunks(&self, chunk_size: usize) -> Chunks<T> where T: Sync {
        Chunks {
            chunk_size: chunk_size,
            slice: self,
        }
    }

    fn par_chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> where T: Send {
        ChunksMut {
            chunk_size: chunk_size,
            slice: self,
        }
    }
}

impl<'data, T: Sync + 'data> IntoParallelIterator for &'data [T] {
    type Item = &'data T;
    type Iter = Iter<'data, T>;

    fn into_par_iter(self) -> Self::Iter {
        Iter { slice: self }
    }
}

impl<'data, T: Sync + 'data> IntoParallelIterator for &'data Vec<T> {
    type Item = &'data T;
    type Iter = Iter<'data, T>;

    fn into_par_iter(self) -> Self::Iter {
        Iter { slice: self }
    }
}

impl<'data, T: Send + 'data> IntoParallelIterator for &'data mut [T] {
    type Item = &'data mut T;
    type Iter = IterMut<'data, T>;

    fn into_par_iter(self) -> Self::Iter {
        IterMut { slice: self }
    }
}

impl<'data, T: Send + 'data> IntoParallelIterator for &'data mut Vec<T> {
    type Item = &'data mut T;
    type Iter = IterMut<'data, T>;

    fn into_par_iter(self) -> Self::Iter {
        IterMut { slice: self }
    }
}

/// Parallel iterator over immutable items in a slice
pub struct Iter<'data, T: 'data + Sync> {
    slice: &'data [T],
}

impl<'data, T: Sync + 'data> ParallelIterator for Iter<'data, T> {
    type Item = &'data T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Sync + 'data> BoundedParallelIterator for Iter<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Sync + 'data> ExactParallelIterator for Iter<'data, T> {
    fn len(&mut self) -> usize {
        self.slice.len()
    }
}

impl<'data, T: Sync + 'data> IndexedParallelIterator for Iter<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(IterProducer { slice: self.slice })
    }
}

struct IterProducer<'data, T: 'data + Sync> {
    slice: &'data [T],
}

impl<'data, T: 'data + Sync> Producer for IterProducer<'data, T> {
    type Item = &'data T;
    type IntoIter = ::std::slice::Iter<'data, T>;

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

    fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.slice.split_at(index);
        (IterProducer { slice: left }, IterProducer { slice: right })
    }
}

/// Parallel iterator over immutable non-overlapping chunks of a slice
pub struct Chunks<'data, T: 'data + Sync> {
    chunk_size: usize,
    slice: &'data [T],
}

impl<'data, T: Sync + 'data> ParallelIterator for Chunks<'data, T> {
    type Item = &'data [T];

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Sync + 'data> BoundedParallelIterator for Chunks<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Sync + 'data> ExactParallelIterator for Chunks<'data, T> {
    fn len(&mut self) -> usize {
        (self.slice.len() + (self.chunk_size - 1)) / self.chunk_size
    }
}

impl<'data, T: Sync + 'data> IndexedParallelIterator for Chunks<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(ChunksProducer {
            chunk_size: self.chunk_size,
            slice: self.slice,
        })
    }
}

struct ChunksProducer<'data, T: 'data + Sync> {
    chunk_size: usize,
    slice: &'data [T],
}

impl<'data, T: 'data + Sync> Producer for ChunksProducer<'data, T> {
    type Item = &'data [T];
    type IntoIter = ::std::slice::Chunks<'data, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.slice.chunks(self.chunk_size)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let elem_index = index * self.chunk_size;
        let (left, right) = self.slice.split_at(elem_index);
        (ChunksProducer {
             chunk_size: self.chunk_size,
             slice: left,
         },
         ChunksProducer {
             chunk_size: self.chunk_size,
             slice: right,
         })
    }
}

/// Parallel iterator over immutable overlapping windows of a slice
pub struct Windows<'data, T: 'data + Sync> {
    window_size: usize,
    slice: &'data [T],
}

impl<'data, T: Sync + 'data> ParallelIterator for Windows<'data, T> {
    type Item = &'data [T];

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Sync + 'data> BoundedParallelIterator for Windows<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Sync + 'data> ExactParallelIterator for Windows<'data, T> {
    fn len(&mut self) -> usize {
        assert!(self.window_size >= 1);
        self.slice.len().saturating_sub(self.window_size - 1)
    }
}

impl<'data, T: Sync + 'data> IndexedParallelIterator for Windows<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(WindowsProducer {
            window_size: self.window_size,
            slice: self.slice,
        })
    }
}

struct WindowsProducer<'data, T: 'data + Sync> {
    window_size: usize,
    slice: &'data [T],
}

impl<'data, T: 'data + Sync> Producer for WindowsProducer<'data, T> {
    type Item = &'data [T];
    type IntoIter = ::std::slice::Windows<'data, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.slice.windows(self.window_size)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let left = &self.slice[..index + (self.window_size - 1)];
        let right = &self.slice[index..];
        (WindowsProducer {
             window_size: self.window_size,
             slice: left,
         },
         WindowsProducer {
             window_size: self.window_size,
             slice: right,
         })
    }
}

/// Parallel iterator over mutable items in a slice
pub struct IterMut<'data, T: 'data + Send> {
    slice: &'data mut [T],
}

impl<'data, T: Send + 'data> ParallelIterator for IterMut<'data, T> {
    type Item = &'data mut T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Send + 'data> BoundedParallelIterator for IterMut<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Send + 'data> ExactParallelIterator for IterMut<'data, T> {
    fn len(&mut self) -> usize {
        self.slice.len()
    }
}

impl<'data, T: Send + 'data> IndexedParallelIterator for IterMut<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(IterMutProducer { slice: self.slice })
    }
}

struct IterMutProducer<'data, T: 'data + Send> {
    slice: &'data mut [T],
}

impl<'data, T: 'data + Send> Producer for IterMutProducer<'data, T> {
    type Item = &'data mut T;
    type IntoIter = ::std::slice::IterMut<'data, T>;

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

    fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.slice.split_at_mut(index);
        (IterMutProducer { slice: left }, IterMutProducer { slice: right })
    }
}

/// Parallel iterator over mutable non-overlapping chunks of a slice
pub struct ChunksMut<'data, T: 'data + Send> {
    chunk_size: usize,
    slice: &'data mut [T],
}

impl<'data, T: Send + 'data> ParallelIterator for ChunksMut<'data, T> {
    type Item = &'data mut [T];

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Send + 'data> BoundedParallelIterator for ChunksMut<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Send + 'data> ExactParallelIterator for ChunksMut<'data, T> {
    fn len(&mut self) -> usize {
        (self.slice.len() + (self.chunk_size - 1)) / self.chunk_size
    }
}

impl<'data, T: Send + 'data> IndexedParallelIterator for ChunksMut<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(ChunksMutProducer {
            chunk_size: self.chunk_size,
            slice: self.slice,
        })
    }
}

struct ChunksMutProducer<'data, T: 'data + Send> {
    chunk_size: usize,
    slice: &'data mut [T],
}

impl<'data, T: 'data + Send> Producer for ChunksMutProducer<'data, T> {
    type Item = &'data mut [T];
    type IntoIter = ::std::slice::ChunksMut<'data, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.slice.chunks_mut(self.chunk_size)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let elem_index = index * self.chunk_size;
        let (left, right) = self.slice.split_at_mut(elem_index);
        (ChunksMutProducer {
             chunk_size: self.chunk_size,
             slice: left,
         },
         ChunksMutProducer {
             chunk_size: self.chunk_size,
             slice: right,
         })
    }
}
<commit_msg>rustfmt slice.rs<commit_after>//! This module contains the parallel iterator types for slices
//! (`[T]`). You will rarely need to interact with it directly unless
//! you have need to name one of those types.

use iter::*;
use iter::internal::*;

/// Parallel extensions for slices.
///
/// Implementing this trait is not permitted outside of `rayon`.
pub trait ParallelSlice<T> {
    private_decl!{}

    /// Returns a parallel iterator over all contiguous windows of
    /// length `size`. The windows overlap.
    fn par_windows(&self, size: usize) -> Windows<T> where T: Sync;

    /// Returns a parallel iterator over at most `size` elements of
    /// `self` at a time. The chunks do not overlap.
    fn par_chunks(&self, size: usize) -> Chunks<T> where T: Sync;

    /// Returns a parallel iterator over at most `size` elements of
    /// `self` at a time. The chunks are mutable and do not overlap.
    fn par_chunks_mut(&mut self, size: usize) -> ChunksMut<T> where T: Send;
}

impl<T> ParallelSlice<T> for [T] {
    private_impl!{}

    fn par_windows(&self, window_size: usize) -> Windows<T>
        where T: Sync
    {
        Windows {
            window_size: window_size,
            slice: self,
        }
    }

    fn par_chunks(&self, chunk_size: usize) -> Chunks<T>
        where T: Sync
    {
        Chunks {
            chunk_size: chunk_size,
            slice: self,
        }
    }

    fn par_chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T>
        where T: Send
    {
        ChunksMut {
            chunk_size: chunk_size,
            slice: self,
        }
    }
}

impl<'data, T: Sync + 'data> IntoParallelIterator for &'data [T] {
    type Item = &'data T;
    type Iter = Iter<'data, T>;

    fn into_par_iter(self) -> Self::Iter {
        Iter { slice: self }
    }
}

impl<'data, T: Sync + 'data> IntoParallelIterator for &'data Vec<T> {
    type Item = &'data T;
    type Iter = Iter<'data, T>;

    fn into_par_iter(self) -> Self::Iter {
        Iter { slice: self }
    }
}

impl<'data, T: Send + 'data> IntoParallelIterator for &'data mut [T] {
    type Item = &'data mut T;
    type Iter = IterMut<'data, T>;

    fn into_par_iter(self) -> Self::Iter {
        IterMut { slice: self }
    }
}

impl<'data, T: Send + 'data> IntoParallelIterator for &'data mut Vec<T> {
    type Item = &'data mut T;
    type Iter = IterMut<'data, T>;

    fn into_par_iter(self) -> Self::Iter {
        IterMut { slice: self }
    }
}

/// Parallel iterator over immutable items in a slice
pub struct Iter<'data, T: 'data + Sync> {
    slice: &'data [T],
}

impl<'data, T: Sync + 'data> ParallelIterator for Iter<'data, T> {
    type Item = &'data T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Sync + 'data> BoundedParallelIterator for Iter<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Sync + 'data> ExactParallelIterator for Iter<'data, T> {
    fn len(&mut self) -> usize {
        self.slice.len()
    }
}

impl<'data, T: Sync + 'data> IndexedParallelIterator for Iter<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(IterProducer { slice: self.slice })
    }
}

struct IterProducer<'data, T: 'data + Sync> {
    slice: &'data [T],
}

impl<'data, T: 'data + Sync> Producer for IterProducer<'data, T> {
    type Item = &'data T;
    type IntoIter = ::std::slice::Iter<'data, T>;

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

    fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.slice.split_at(index);
        (IterProducer { slice: left }, IterProducer { slice: right })
    }
}

/// Parallel iterator over immutable non-overlapping chunks of a slice
pub struct Chunks<'data, T: 'data + Sync> {
    chunk_size: usize,
    slice: &'data [T],
}

impl<'data, T: Sync + 'data> ParallelIterator for Chunks<'data, T> {
    type Item = &'data [T];

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Sync + 'data> BoundedParallelIterator for Chunks<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Sync + 'data> ExactParallelIterator for Chunks<'data, T> {
    fn len(&mut self) -> usize {
        (self.slice.len() + (self.chunk_size - 1)) / self.chunk_size
    }
}

impl<'data, T: Sync + 'data> IndexedParallelIterator for Chunks<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(ChunksProducer {
                              chunk_size: self.chunk_size,
                              slice: self.slice,
                          })
    }
}

struct ChunksProducer<'data, T: 'data + Sync> {
    chunk_size: usize,
    slice: &'data [T],
}

impl<'data, T: 'data + Sync> Producer for ChunksProducer<'data, T> {
    type Item = &'data [T];
    type IntoIter = ::std::slice::Chunks<'data, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.slice.chunks(self.chunk_size)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let elem_index = index * self.chunk_size;
        let (left, right) = self.slice.split_at(elem_index);
        (ChunksProducer {
             chunk_size: self.chunk_size,
             slice: left,
         },
         ChunksProducer {
             chunk_size: self.chunk_size,
             slice: right,
         })
    }
}

/// Parallel iterator over immutable overlapping windows of a slice
pub struct Windows<'data, T: 'data + Sync> {
    window_size: usize,
    slice: &'data [T],
}

impl<'data, T: Sync + 'data> ParallelIterator for Windows<'data, T> {
    type Item = &'data [T];

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Sync + 'data> BoundedParallelIterator for Windows<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Sync + 'data> ExactParallelIterator for Windows<'data, T> {
    fn len(&mut self) -> usize {
        assert!(self.window_size >= 1);
        self.slice.len().saturating_sub(self.window_size - 1)
    }
}

impl<'data, T: Sync + 'data> IndexedParallelIterator for Windows<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(WindowsProducer {
                              window_size: self.window_size,
                              slice: self.slice,
                          })
    }
}

struct WindowsProducer<'data, T: 'data + Sync> {
    window_size: usize,
    slice: &'data [T],
}

impl<'data, T: 'data + Sync> Producer for WindowsProducer<'data, T> {
    type Item = &'data [T];
    type IntoIter = ::std::slice::Windows<'data, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.slice.windows(self.window_size)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let left = &self.slice[..index + (self.window_size - 1)];
        let right = &self.slice[index..];
        (WindowsProducer {
             window_size: self.window_size,
             slice: left,
         },
         WindowsProducer {
             window_size: self.window_size,
             slice: right,
         })
    }
}

/// Parallel iterator over mutable items in a slice
pub struct IterMut<'data, T: 'data + Send> {
    slice: &'data mut [T],
}

impl<'data, T: Send + 'data> ParallelIterator for IterMut<'data, T> {
    type Item = &'data mut T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Send + 'data> BoundedParallelIterator for IterMut<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Send + 'data> ExactParallelIterator for IterMut<'data, T> {
    fn len(&mut self) -> usize {
        self.slice.len()
    }
}

impl<'data, T: Send + 'data> IndexedParallelIterator for IterMut<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(IterMutProducer { slice: self.slice })
    }
}

struct IterMutProducer<'data, T: 'data + Send> {
    slice: &'data mut [T],
}

impl<'data, T: 'data + Send> Producer for IterMutProducer<'data, T> {
    type Item = &'data mut T;
    type IntoIter = ::std::slice::IterMut<'data, T>;

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

    fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.slice.split_at_mut(index);
        (IterMutProducer { slice: left }, IterMutProducer { slice: right })
    }
}

/// Parallel iterator over mutable non-overlapping chunks of a slice
pub struct ChunksMut<'data, T: 'data + Send> {
    chunk_size: usize,
    slice: &'data mut [T],
}

impl<'data, T: Send + 'data> ParallelIterator for ChunksMut<'data, T> {
    type Item = &'data mut [T];

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<'data, T: Send + 'data> BoundedParallelIterator for ChunksMut<'data, T> {
    fn upper_bound(&mut self) -> usize {
        ExactParallelIterator::len(self)
    }

    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }
}

impl<'data, T: Send + 'data> ExactParallelIterator for ChunksMut<'data, T> {
    fn len(&mut self) -> usize {
        (self.slice.len() + (self.chunk_size - 1)) / self.chunk_size
    }
}

impl<'data, T: Send + 'data> IndexedParallelIterator for ChunksMut<'data, T> {
    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(ChunksMutProducer {
                              chunk_size: self.chunk_size,
                              slice: self.slice,
                          })
    }
}

struct ChunksMutProducer<'data, T: 'data + Send> {
    chunk_size: usize,
    slice: &'data mut [T],
}

impl<'data, T: 'data + Send> Producer for ChunksMutProducer<'data, T> {
    type Item = &'data mut [T];
    type IntoIter = ::std::slice::ChunksMut<'data, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.slice.chunks_mut(self.chunk_size)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let elem_index = index * self.chunk_size;
        let (left, right) = self.slice.split_at_mut(elem_index);
        (ChunksMutProducer {
             chunk_size: self.chunk_size,
             slice: left,
         },
         ChunksMutProducer {
             chunk_size: self.chunk_size,
             slice: right,
         })
    }
}
<|endoftext|>


<commit_before>#[derive(Eq,PartialEq,Debug,Copy,Clone,Hash,RustcEncodable,RustcDecodable)]
pub struct Locale {
    pub rank: u8,
    pub file: u8,
}

static INDEX_TO_FILE_NAME: [char; 8] = [
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'
];

lazy_static! {
    static ref LOCALE_STASH: fnv::FnvHashMap<(u8, u8), Locale> = {
        let mut m: fnv::FnvHashMap<(u8, u8), Locale> = fnv::FnvHashMap::default();
        for rank in 0..8 {
            for file in 0..8 {
                m.insert((rank, file), Locale { rank, file });
            }
        }
        m
    };
}

impl Locale {
    pub fn new(rank: u8, file: u8) -> Self {
        *LOCALE_STASH.get(&(rank, file)).unwrap()
    }

    pub fn to_algebraic(&self) -> String {
        format!("{}{}", INDEX_TO_FILE_NAME[self.file as usize], self.rank + 1)
    }

    pub fn from_algebraic(notation: &str) -> Self {
        let mut notation_pieces = notation.chars();
        let file_note = notation_pieces.next()
            .expect("expected a first character");
        let rank_note = notation_pieces.next()
            .expect("expected a second character");
        Locale {
            rank: (rank_note as u8) - 49, // 49 == '1'
            file: (file_note as u8) - 97, // 97 == 'a'
        }
    }

    pub fn pindex(&self) -> u32 {
        (8u32 * u32::from(self.rank)) + u32::from(self.file)
    }

    pub fn pinpoint(&self) -> Pinfield {
        Pinfield(1u64 << self.pindex())
    }

    pub fn is_legal(&self) -> bool {
        self.rank < 8 && self.file < 8
    }

    pub fn displace(&self, offset: (i8, i8)) -> Option<Self> {
        let (rank_offset, file_offset) = offset;
        let potential_locale = Locale {
            // XXX: it won't happen with the arguments we expect to
            // give it in this program, but in the interests of Safety,
            // this is an overflow bug (-1i8 as u8 == 255u8)
            rank: (self.rank as i8 + rank_offset) as u8,
            file: (self.file as i8 + file_offset) as u8,
        };
        if potential_locale.is_legal() {
            Some(potential_locale)
        } else {
            None
        }
    }

    pub fn multidisplace(&self, offset: (i8, i8), factor: i8) -> Option<Self> {
        let (rank_offset, file_offset) = offset;
        let (real_rank, real_file) = (factor * rank_offset,
                                      factor * file_offset);

        let potential_locale = Locale {
            // XXX: could overflow given unrealistic arguments
            rank: (self.rank as i8 + real_rank) as u8,
            file: (self.file as i8 + real_file) as u8,
        };
        if potential_locale.is_legal() {
            Some(potential_locale)
        } else {
            None
        }
    }
}

#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash, Default)]
pub struct Pinfield(pub u64);

impl Pinfield {
    pub fn new() -> Self {
        Pinfield(0)
    }

    pub fn init(starters: &[Locale]) -> Pinfield {
        let mut board = Pinfield::new();
        for &starter in starters.iter() {
            board = board.alight(starter);
        }
        board
    }

    pub fn union(&self, other: Pinfield) -> Pinfield {
        let Pinfield(our_bits) = *self;
        let Pinfield(their_bits) = other;
        Pinfield(our_bits | their_bits)
    }

    pub fn intersection(&self, other: Pinfield) -> Pinfield {
        let Pinfield(our_bits) = *self;
        let Pinfield(their_bits) = other;
        Pinfield(our_bits & their_bits)
    }

    pub fn invert(&self) -> Pinfield {
        let Pinfield(our_bits) = *self;
        Pinfield(!our_bits)
    }

    pub fn alight(&self, station: Locale) -> Pinfield {
        // classic `|= (1 << n)` would probably be more efficient, huh &c.
        self.union(station.pinpoint())
    }

    pub fn quench(&self, station: Locale) -> Pinfield {
        self.intersection(station.pinpoint().invert())
    }

    pub fn transit(&self, departure: Locale, destination: Locale) -> Pinfield {
        // empirically, pulling function calls out of this and replacing
        // them with bit manipulation directly doesnt help.
        self.quench(departure).alight(destination)
    }

    pub fn query(&self, station: Locale) -> bool {
        let Pinfield(our_bits) = *self;
        let Pinfield(beacon_bits) = station.pinpoint();
        (our_bits & beacon_bits) != 0
    }

    pub fn to_locales(&self) -> Vec<Locale> {
        let mut locales = Vec::with_capacity(8);
        let Pinfield(bits) = *self;
        let mut bitfield = 1u64;
        for rank in 0..8 {
            for file in 0..8 {
                if bitfield & bits != 0 {
                    let locale = Locale::new(rank, file);
                    locales.push(locale);
                }
                bitfield <<= 1;
            }
        }
        locales
    }

    pub fn pincount(&self) -> u8 {
        let Pinfield(bits) = *self;
        bits.count_ones() as u8
    }

    // TODO: convert to Display::fmt
    #[allow(dead_code)]
    pub fn display(&self) {
        for rank in 0..8 {
            for file in 0..8 {
                if self.query(Locale::new(rank, file)) {
                    print!("• ");
                } else {
                    print!("_ ");
                }
            }
            println!();
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    extern crate rand;
    use self::test::{Bencher, black_box};
    use super::{Locale, Pinfield};
    use fnv;
    use twox_hash::XxHash;
    use std::hash::Hash;
    use std::collections::hash_map;
    use space::tests::rand::prelude::*;

    static ALGEBRAICS: [&'static str; 64] = [
        "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
        "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
        "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
        "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
        "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
        "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
        "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
        "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8"
    ];

    #[bench]
    fn benchmark_hashing_tuple_fnv(b: &mut Bencher) {
        let mut hasher = fnv::FnvHasher::default();
        let t: (u8, u8) = (1, 4);

        b.iter(|| {
            for _ in 0..1000 {
                t.hash(&mut hasher);
            }
        });
    }

    #[bench]
    fn benchmark_hashing_tuple_xx(b: &mut Bencher) {
        let mut hasher = XxHash::default();
        let t: (u8, u8) = (1, 4);

        b.iter(|| {
            for _ in 0..1000 {
                t.hash(&mut hasher);
            }
        });
    }

    #[bench]
    fn benchmark_hashing_tuple_sip(b: &mut Bencher) {
        let mut hasher = hash_map::DefaultHasher::new();
        let t: (u8, u8) = (1, 4);

        b.iter(|| {
            for _ in 0..1000 {
                t.hash(&mut hasher);
            }
        });
    }

    #[bench]
    fn benchmark_locale_lookup(b: &mut Bencher) {
        let mut args = Vec::with_capacity(64);
        for rank in 0..8 {
            for file in 0..8 {
                args.push((rank, file));
            }
        }
        let mut rng = thread_rng();
        args.shuffle(&mut rng);
        b.iter(|| {
            for (r, f) in &args {
                black_box(Locale::new(*r, *f));
            }
        });

    }

    #[bench]
    fn benchmark_to_locales(b: &mut Bencher) {
        let mut stage = Pinfield(0);
        for r in 0..8 {
            stage = stage.alight(Locale::new(1, r));
            stage = stage.alight(Locale::new(7, r));
        }

        b.iter(|| stage.to_locales());
    }

    #[bench]
    fn benchmark_transit(b: &mut Bencher) {
        let mut stage = Pinfield(0);
        let from = Locale::new(1, 3);
        let to = Locale::new(2, 5);
        stage = stage.alight(from);

        b.iter(|| {
            for _ in 0..10000 {
                black_box(stage.transit(from, to));
            }
        });
    }

    #[test]
    fn concerning_converting_to_algebraic() {
        let actual = iproduct!(0..8, 0..8)
                         .map(|t| Locale::new(t.0, t.1))
                         .map(|l| l.to_algebraic());
        for (expectation, actuality) in ALGEBRAICS.iter().zip(actual) {
            // TODO: it's more elegant if the conversion happens in
            // the iterator rather than the body of this
            // assertion-iteration
            assert_eq!(expectation.to_owned(), actuality);
        }
    }

    #[test]
    fn concerning_converting_from_algebraic() {
        let expected = iproduct!(0..8, 0..8).map(|t| Locale::new(t.0, t.1));
        for (expectation, actuality) in expected.zip(ALGEBRAICS.iter()) {
            assert_eq!(expectation,
                       // TODO: again, conversion in iterator
                       Locale::from_algebraic(*actuality));
        }
    }

    #[test]
    fn test_locale() {
        let a1 = Locale::new(0, 0);
        assert_eq!(Pinfield(1u64), a1.pinpoint());

        let c4 = Locale::new(2, 3);
        assert_eq!(Pinfield(524288u64), c4.pinpoint());
    }

    #[test]
    fn test_displace_locale() {
        assert_eq!(
            Some(Locale::new(3, 5)),
            Locale::new(4, 4).displace((-1, 1))
        );
        assert_eq!(
            None,
            Locale::new(0, 0).displace((-1, 1))
        )
    }

    #[test]
    fn concerning_multidisplacement() {
        for i in 0..8 {
            assert_eq!(
                Some(Locale { rank: i as u8, file: i as u8 }),
                Locale::new(0, 0).multidisplace((1, 1), i)
            )
        }
        assert_eq!(None, Locale::new(0, 0).multidisplace((1, 1), 8));
    }

    #[test]
    fn test_alight_and_quench() {
        let mut stage = Pinfield(0);
        let b5 = Locale::new(1, 4);
        stage = stage.alight(b5);
        assert!(stage.query(b5));
        stage = stage.quench(b5);
        assert!(!stage.query(b5));
    }

    #[test]
    fn test_init_pinfield() {
        let starters = vec![Locale::new(1, 2),
                            Locale::new(3, 4),
                            Locale::new(5, 6)];
        let stage = Pinfield::init(&starters);
        for &starter in &starters {
            assert!(stage.query(starter));
        }
    }

    #[test]
    fn concerning_pincount() {
        let starters = vec![Locale::new(1, 2),
                            Locale::new(3, 4),
                            Locale::new(5, 6)];
        let stage = Pinfield::init(&starters);
        assert_eq!(3, stage.pincount());
    }
}
<commit_msg>Locale lookup w/ arrays<commit_after>#[derive(Eq,PartialEq,Debug,Copy,Clone,Hash,RustcEncodable,RustcDecodable)]
pub struct Locale {
    pub rank: u8,
    pub file: u8,
}

static INDEX_TO_FILE_NAME: [char; 8] = [
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'
];

lazy_static! {
    static ref LOCALE_STASH: [Locale; 64] = {
        let mut m: [Locale; 64] = [Locale {rank: 0, file: 0}; 64];
        for rank in 0..8 {
            for file in 0..8 {
                let idx = (rank*8 + file) as usize;

                m[idx] = Locale { rank, file };
            }
        }
        m
    };
}

impl Locale {
    pub fn new(rank: u8, file: u8) -> Self {
        let idx = (rank*8 + file) as usize;
        LOCALE_STASH[idx]
    }

    pub fn to_algebraic(&self) -> String {
        format!("{}{}", INDEX_TO_FILE_NAME[self.file as usize], self.rank + 1)
    }

    pub fn from_algebraic(notation: &str) -> Self {
        let mut notation_pieces = notation.chars();
        let file_note = notation_pieces.next()
            .expect("expected a first character");
        let rank_note = notation_pieces.next()
            .expect("expected a second character");
        Locale {
            rank: (rank_note as u8) - 49, // 49 == '1'
            file: (file_note as u8) - 97, // 97 == 'a'
        }
    }

    pub fn pindex(&self) -> u32 {
        (8u32 * u32::from(self.rank)) + u32::from(self.file)
    }

    pub fn pinpoint(&self) -> Pinfield {
        Pinfield(1u64 << self.pindex())
    }

    pub fn is_legal(&self) -> bool {
        self.rank < 8 && self.file < 8
    }

    pub fn displace(&self, offset: (i8, i8)) -> Option<Self> {
        let (rank_offset, file_offset) = offset;
        let potential_locale = Locale {
            // XXX: it won't happen with the arguments we expect to
            // give it in this program, but in the interests of Safety,
            // this is an overflow bug (-1i8 as u8 == 255u8)
            rank: (self.rank as i8 + rank_offset) as u8,
            file: (self.file as i8 + file_offset) as u8,
        };
        if potential_locale.is_legal() {
            Some(potential_locale)
        } else {
            None
        }
    }

    pub fn multidisplace(&self, offset: (i8, i8), factor: i8) -> Option<Self> {
        let (rank_offset, file_offset) = offset;
        let (real_rank, real_file) = (factor * rank_offset,
                                      factor * file_offset);

        let potential_locale = Locale {
            // XXX: could overflow given unrealistic arguments
            rank: (self.rank as i8 + real_rank) as u8,
            file: (self.file as i8 + real_file) as u8,
        };
        if potential_locale.is_legal() {
            Some(potential_locale)
        } else {
            None
        }
    }
}

#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash, Default)]
pub struct Pinfield(pub u64);

impl Pinfield {
    pub fn new() -> Self {
        Pinfield(0)
    }

    pub fn init(starters: &[Locale]) -> Pinfield {
        let mut board = Pinfield::new();
        for &starter in starters.iter() {
            board = board.alight(starter);
        }
        board
    }

    pub fn union(&self, other: Pinfield) -> Pinfield {
        let Pinfield(our_bits) = *self;
        let Pinfield(their_bits) = other;
        Pinfield(our_bits | their_bits)
    }

    pub fn intersection(&self, other: Pinfield) -> Pinfield {
        let Pinfield(our_bits) = *self;
        let Pinfield(their_bits) = other;
        Pinfield(our_bits & their_bits)
    }

    pub fn invert(&self) -> Pinfield {
        let Pinfield(our_bits) = *self;
        Pinfield(!our_bits)
    }

    pub fn alight(&self, station: Locale) -> Pinfield {
        // classic `|= (1 << n)` would probably be more efficient, huh &c.
        self.union(station.pinpoint())
    }

    pub fn quench(&self, station: Locale) -> Pinfield {
        self.intersection(station.pinpoint().invert())
    }

    pub fn transit(&self, departure: Locale, destination: Locale) -> Pinfield {
        // empirically, pulling function calls out of this and replacing
        // them with bit manipulation directly doesnt help.
        self.quench(departure).alight(destination)
    }

    pub fn query(&self, station: Locale) -> bool {
        let Pinfield(our_bits) = *self;
        let Pinfield(beacon_bits) = station.pinpoint();
        (our_bits & beacon_bits) != 0
    }

    pub fn to_locales(&self) -> Vec<Locale> {
        let mut locales = Vec::with_capacity(8);
        let Pinfield(bits) = *self;
        let mut bitfield = 1u64;
        for rank in 0..8 {
            for file in 0..8 {
                if bitfield & bits != 0 {
                    let locale = Locale::new(rank, file);
                    locales.push(locale);
                }
                bitfield <<= 1;
            }
        }
        locales
    }

    pub fn pincount(&self) -> u8 {
        let Pinfield(bits) = *self;
        bits.count_ones() as u8
    }

    // TODO: convert to Display::fmt
    #[allow(dead_code)]
    pub fn display(&self) {
        for rank in 0..8 {
            for file in 0..8 {
                if self.query(Locale::new(rank, file)) {
                    print!("• ");
                } else {
                    print!("_ ");
                }
            }
            println!();
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    extern crate rand;
    use self::test::{Bencher, black_box};
    use super::{Locale, Pinfield};
    use fnv;
    use twox_hash::XxHash;
    use std::hash::Hash;
    use std::collections::hash_map;
    use space::tests::rand::prelude::*;

    static ALGEBRAICS: [&'static str; 64] = [
        "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
        "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
        "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
        "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
        "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
        "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
        "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
        "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8"
    ];

    #[bench]
    fn benchmark_hashing_tuple_fnv(b: &mut Bencher) {
        let mut hasher = fnv::FnvHasher::default();
        let t: (u8, u8) = (1, 4);

        b.iter(|| {
            for _ in 0..1000 {
                t.hash(&mut hasher);
            }
        });
    }

    #[bench]
    fn benchmark_hashing_tuple_xx(b: &mut Bencher) {
        let mut hasher = XxHash::default();
        let t: (u8, u8) = (1, 4);

        b.iter(|| {
            for _ in 0..1000 {
                t.hash(&mut hasher);
            }
        });
    }

    #[bench]
    fn benchmark_hashing_tuple_sip(b: &mut Bencher) {
        let mut hasher = hash_map::DefaultHasher::new();
        let t: (u8, u8) = (1, 4);

        b.iter(|| {
            for _ in 0..1000 {
                t.hash(&mut hasher);
            }
        });
    }

    #[bench]
    fn benchmark_locale_lookup(b: &mut Bencher) {
        let mut args = Vec::with_capacity(64);
        for rank in 0..8 {
            for file in 0..8 {
                args.push((rank, file));
            }
        }
        let mut rng = thread_rng();
        args.shuffle(&mut rng);
        b.iter(|| {
            for (r, f) in &args {
                black_box(Locale::new(*r, *f));
            }
        });

    }

    #[bench]
    fn benchmark_to_locales(b: &mut Bencher) {
        let mut stage = Pinfield(0);
        for r in 0..8 {
            stage = stage.alight(Locale::new(1, r));
            stage = stage.alight(Locale::new(7, r));
        }

        b.iter(|| stage.to_locales());
    }

    #[bench]
    fn benchmark_transit(b: &mut Bencher) {
        let mut stage = Pinfield(0);
        let from = Locale::new(1, 3);
        let to = Locale::new(2, 5);
        stage = stage.alight(from);

        b.iter(|| {
            for _ in 0..10000 {
                black_box(stage.transit(from, to));
            }
        });
    }

    #[test]
    fn concerning_converting_to_algebraic() {
        let actual = iproduct!(0..8, 0..8)
                         .map(|t| Locale::new(t.0, t.1))
                         .map(|l| l.to_algebraic());
        for (expectation, actuality) in ALGEBRAICS.iter().zip(actual) {
            // TODO: it's more elegant if the conversion happens in
            // the iterator rather than the body of this
            // assertion-iteration
            assert_eq!(expectation.to_owned(), actuality);
        }
    }

    #[test]
    fn concerning_converting_from_algebraic() {
        let expected = iproduct!(0..8, 0..8).map(|t| Locale::new(t.0, t.1));
        for (expectation, actuality) in expected.zip(ALGEBRAICS.iter()) {
            assert_eq!(expectation,
                       // TODO: again, conversion in iterator
                       Locale::from_algebraic(*actuality));
        }
    }

    #[test]
    fn test_locale() {
        let a1 = Locale::new(0, 0);
        assert_eq!(Pinfield(1u64), a1.pinpoint());

        let c4 = Locale::new(2, 3);
        assert_eq!(Pinfield(524288u64), c4.pinpoint());
    }

    #[test]
    fn test_displace_locale() {
        assert_eq!(
            Some(Locale::new(3, 5)),
            Locale::new(4, 4).displace((-1, 1))
        );
        assert_eq!(
            None,
            Locale::new(0, 0).displace((-1, 1))
        )
    }

    #[test]
    fn concerning_multidisplacement() {
        for i in 0..8 {
            assert_eq!(
                Some(Locale { rank: i as u8, file: i as u8 }),
                Locale::new(0, 0).multidisplace((1, 1), i)
            )
        }
        assert_eq!(None, Locale::new(0, 0).multidisplace((1, 1), 8));
    }

    #[test]
    fn test_alight_and_quench() {
        let mut stage = Pinfield(0);
        let b5 = Locale::new(1, 4);
        stage = stage.alight(b5);
        assert!(stage.query(b5));
        stage = stage.quench(b5);
        assert!(!stage.query(b5));
    }

    #[test]
    fn test_init_pinfield() {
        let starters = vec![Locale::new(1, 2),
                            Locale::new(3, 4),
                            Locale::new(5, 6)];
        let stage = Pinfield::init(&starters);
        for &starter in &starters {
            assert!(stage.query(starter));
        }
    }

    #[test]
    fn concerning_pincount() {
        let starters = vec![Locale::new(1, 2),
                            Locale::new(3, 4),
                            Locale::new(5, 6)];
        let stage = Pinfield::init(&starters);
        assert_eq!(3, stage.pincount());
    }
}
<|endoftext|>