<commit_before>export prime, factors;

enum grow_cond { count(uint), value(u64) }

class prime {
    priv {
        let mut vec: [u64];

        fn is_coprime(num: u64) -> bool {
            for self.vec.each() {|p|
                if p * p > num {
                    ret true;
                }
                if num % p == 0u64 {
                    ret false;
                }
            }
            ret true;
        }

        fn check_cond(cond: grow_cond) -> bool {
            alt cond {
              count(cnt) { cnt < self.vec.len() }
              value(val) {
                alt vec::last_opt(self.vec) {
                  some(x) { val < x }
                  none    { false }
                }
              }
            }
        }

        fn grow_until(cond: grow_cond) {
            if self.check_cond(cond) {
                ret;
            }

            let mut num = alt vec::last_opt(self.vec) {
              none       { self.vec =  [2u64]; ret self.grow_until(cond); }
              some(2u64) { self.vec += [3u64]; ret self.grow_until(cond); }
              some(x)    { x + 2u64 }
            };

            while !self.check_cond(cond) {
                if self.is_coprime(num) {
                    self.vec += [num];
                }
                num += 2u64;
            }
        }
    }

    new() { self.vec = []; }

    fn [](idx: uint) -> u64 {
        self.grow_until(count(idx + 1u));
        ret self.vec[idx];
    }

    fn is_prime(num: u64) -> bool {
        if num < 2u64 {
            ret false;
        }
        self.grow_until(value(calc::isqrt(num)));

        for self.vec.each() {|p|
            if p * p > num {
                ret true;
            }
            if num % p == 0u {
                ret false;
            }
        };
        ret true;
    }

    fn each(f: fn(&&u64) -> bool) {
        let mut idx = 0u64;
        for self.vec.each {|p|
            if !f(p) {
                ret;
            }
            idx += 1u;
        }
        loop {
            if !f(self[idx]) {
                ret;
            }
            idx += 1u;
        }
    }
}

fn div_multi(&num: u64, f: u64) -> u64 {
    let mut exp = 0u64;
    while (num % f == 0u64) {
        exp += 1u64;
        num /= f;
    }
    ret exp;
}

fn factors(num: u64, primes: prime, blk: fn((u64, i64))) {
    let mut itr = num;
    for primes.each {|p|
        let exp = div_multi(itr, p);
        if exp > 0u64 {
            blk((p, exp as i64));
        }
        if itr == 1u {
            break;
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_prime_opidx () {
        let table  = [  2u64,  3u64,  5u64,  7u64, 11u64, 13u64, 17u64, 19u64, 23u64, 29u64, 31u64, 37u64, 41u64 ];
        let ps = prime();

        // Generated primes
        for table.eachi() {|i, p|
            assert ps[i] == p;
        }
        // Memoized primes
        for table.eachi() {|i, p|
            assert ps[i] == p;
        }
    }

    #[test]
    fn test_prime_each() {
        let table  = [  2u64,  3u64,  5u64,  7u64, 11u64, 13u64, 17u64, 19u64, 23u64, 29u64, 31u64, 37u64, 41u64 ];
        let table2 = [ 43u64, 47u64, 53u64, 59u64, 61u64, 67u64, 71u64, 73u64, 79u64, 83u64, 89u64, 97u64 ];
        let ps = prime();

        let mut v1 = [];
        for ps.each {|p|
            if p > table.last() {
                break;
            }
            v1 += [ p ];
        }
        assert table == v1;

        let mut v2 = [];
        for ps.each {|p|
            if p > table.last() {
                break;
            }
            v2 += [ p ];
        }
        assert table == v2;

        let mut v3 = [];
        for ps.each {|p|
            if p > table2.last() {
                break;
            }
            v3 += [ p ];
        }
        assert table + table2 == v3;
    }

    #[test]
    fn test_prime_is_prime() {
        let p = prime();
        assert !p.is_prime(1u64);
        assert p.is_prime(2u64);
        assert p.is_prime(3u64);
        assert !p.is_prime(4u64);
        assert p.is_prime(5u64);
        assert !p.is_prime(6u64);
        assert p.is_prime(7u64);
        assert !p.is_prime(100u64);
    }
}
<commit_msg>Reduce extra calculation from  euler::prime::prime::is_prime()<commit_after>export prime, factors;

enum grow_cond { count(uint), value(u64) }

class prime {
    priv {
        let mut vec: [u64];

        fn is_coprime(num: u64) -> bool {
            for self.vec.each() {|p|
                if p * p > num     { ret true; }
                if num % p == 0u64 { ret false; }
            }
            ret true;
        }

        fn check_cond(cond: grow_cond) -> bool {
            alt cond {
              count(cnt) { cnt < self.vec.len() }
              value(val) {
                alt vec::last_opt(self.vec) {
                  some(x) { val < x }
                  none    { false }
                }
              }
            }
        }

        fn grow_until(cond: grow_cond) {
            if self.check_cond(cond) { ret; }

            let mut num = alt vec::last_opt(self.vec) {
              none       { self.vec =  [2u64]; ret self.grow_until(cond); }
              some(2u64) { self.vec += [3u64]; ret self.grow_until(cond); }
              some(x)    { x + 2u64 }
            };

            while !self.check_cond(cond) {
                if self.is_coprime(num) {
                    self.vec += [num];
                }
                num += 2u64;
            }
        }
    }

    new() { self.vec = []; }

    fn [](idx: uint) -> u64 {
        self.grow_until(count(idx + 1u));
        ret self.vec[idx];
    }

    fn is_prime(num: u64) -> bool {
        if num < 2u64 { ret false; }

        for self.each {|p|
            if p * p > num   { ret true; }
            if num % p == 0u { ret false; }
        }
        unreachable();
    }

    fn each(f: fn(&&u64) -> bool) {
        let mut idx = 0u64;
        for self.vec.each {|p|
            if !f(p) { ret; }
            idx += 1u;
        }
        loop {
            if !f(self[idx]) { ret; }
            idx += 1u;
        }
    }
}

fn div_multi(&num: u64, f: u64) -> u64 {
    let mut exp = 0u64;
    while (num % f == 0u64) {
        exp += 1u64;
        num /= f;
    }
    ret exp;
}

fn factors(num: u64, primes: prime, blk: fn((u64, i64))) {
    let mut itr = num;
    for primes.each {|p|
        let exp = div_multi(itr, p);
        if exp > 0u64 { blk((p, exp as i64)); }
        if itr == 1u  { break; }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_prime_opidx () {
        let table  = [  2u64,  3u64,  5u64,  7u64, 11u64, 13u64, 17u64, 19u64, 23u64, 29u64, 31u64, 37u64, 41u64 ];
        let ps = prime();

        // Generated primes
        for table.eachi() {|i, p| assert ps[i] == p; }
        // Memoized primes
        for table.eachi() {|i, p| assert ps[i] == p; }
    }

    #[test]
    fn test_prime_each() {
        let table  = [  2u64,  3u64,  5u64,  7u64, 11u64, 13u64, 17u64, 19u64, 23u64, 29u64, 31u64, 37u64, 41u64 ];
        let table2 = [ 43u64, 47u64, 53u64, 59u64, 61u64, 67u64, 71u64, 73u64, 79u64, 83u64, 89u64, 97u64 ];
        let ps = prime();

        let mut v1 = [];
        for ps.each {|p|
            if p > table.last() { break; }
            v1 += [ p ];
        }
        assert table == v1;

        let mut v2 = [];
        for ps.each {|p|
            if p > table.last() { break; }
            v2 += [ p ];
        }
        assert table == v2;

        let mut v3 = [];
        for ps.each {|p|
            if p > table2.last() { break; }
            v3 += [ p ];
        }
        assert table + table2 == v3;
    }

    #[test]
    fn test_prime_is_prime() {
        let p = prime();
        assert !p.is_prime(0u64);
        assert !p.is_prime(1u64);
        assert p.is_prime(2u64);
        assert p.is_prime(3u64);
        assert !p.is_prime(4u64);
        assert p.is_prime(5u64);
        assert !p.is_prime(6u64);
        assert p.is_prime(7u64);
        assert !p.is_prime(100u64);
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::io;
use std::str;
use std::io::Write;

use itertools::Itertools;
use rust_htslib::bcf;
use rust_htslib::bcf::record::Numeric;

pub struct Writer {
    inner: io::BufWriter<io::Stdout>,
    field_count: usize
}

impl Writer {
    fn new(inner: io::BufWriter<io::Stdout>) -> Self {
        Writer {
            inner: inner,
            field_count: 0
        }
    }

    fn write_integer(&mut self, value: i32) -> Result<(), Box<Error>> {
        self.write_field(format!("{}", value).as_bytes())
    }

    fn write_float(&mut self, value: f32) -> Result<(), Box<Error>> {
        self.write_field(format!("{}", value).as_bytes())
    }

    fn write_flag(&mut self, value: bool) -> Result<(), Box<Error>> {
        self.write_field(format!("{}", value).as_bytes())
    }

    fn write_field(&mut self, value: &[u8]) -> Result<(), Box<Error>> {
        if self.field_count > 0 {
            try!(self.inner.write(b"\t"));
        }
        try!(self.inner.write(value));
        self.field_count += 1;
        Ok(())
    }

    fn newline(&mut self) -> Result<(), Box<Error>> {
        try!(self.inner.write(b"\n"));
        self.field_count = 0;
        Ok(())
    }
}

const HEADER_COMMON: &'static [u8] = b"VARIANT";

pub fn to_txt(
    info_tags: &[&str],
    format_tags: &[&str],
    show_genotypes: bool
) -> Result<(), Box<Error>> {
    let reader = try!(bcf::Reader::new(&"-"));
    let mut writer = Writer::new(io::BufWriter::new(io::stdout()));

    let common_n = 5 + info_tags.len();
    try!(writer.write_field(HEADER_COMMON));
    for _ in 1..common_n {
        try!(writer.write_field(HEADER_COMMON));
    }
    for sample in reader.header.samples() {
        try!(writer.write_field(sample));
        for _ in 1..format_tags.len() + show_genotypes as usize {
            try!(writer.write_field(sample));
        }
    }
    try!(writer.newline());
    try!(writer.write_field(b"CHROM"));
    try!(writer.write_field(b"POS"));
    try!(writer.write_field(b"REF"));
    try!(writer.write_field(b"ALT"));
    try!(writer.write_field(b"QUAL"));
    for name in info_tags {
        try!(writer.write_field(name.as_bytes()));
    }
    for _ in 0..reader.header.sample_count() {
        if show_genotypes {
            try!(writer.write_field(b"GT"));
        }
        for name in format_tags {
            try!(writer.write_field(name.as_bytes()));
        }
    }
    try!(writer.newline());

    let mut record = bcf::Record::new();
    loop {
        if let Err(e) = reader.read(&mut record) {
            if e.is_eof() {
                break;
            } else {
                return Err(Box::new(e));
            }
        }

        let alleles = record.alleles().into_iter().map(|a| a.to_owned()).collect_vec();
        for (i, allele) in alleles[1..].iter().enumerate() {
            try!(writer.write_field(reader.header.rid2name(record.rid().unwrap())));
            try!(writer.write_integer(record.pos() as i32 + 1));
            try!(writer.write_field(&alleles[0]));
            try!(writer.write_field(allele));
            match record.qual() {
                q if q.is_missing() => try!(writer.write_field(b"")),
                q => try!(writer.write_float(q))
            }

            for name in info_tags {
                let _name = name.as_bytes();
                if let Ok((tag_type, tag_length)) = reader.header.info_type(_name) {
                    let get_idx = || {
                        match tag_length {
                            bcf::header::TagLength::Fixed => {
                                Ok(0)
                            },
                            bcf::header::TagLength::AltAlleles => {
                                Ok(i)
                            },
                            _ => Err(Box::new(ParseError::UnsupportedTagLength))
                        }
                    };

                    match tag_type {
                        bcf::header::TagType::Flag => {
                            try!(writer.write_flag(try!(record.info(_name).flag())));
                        },
                        bcf::header::TagType::Integer => {
                            let i = try!(get_idx());
                            if let Some(values) = try!(record.info(_name).integer()) {
                                try!(writer.write_integer(values[i]));
                            } else {
                                try!(writer.write_field(b""));
                            }
                        },
                        bcf::header::TagType::Float => {
                            let i = try!(get_idx());
                            if let Some(values) = try!(record.info(_name).float()) {
                                try!(writer.write_float(values[i]));
                            } else {
                                try!(writer.write_field(b""));
                            }
                        },
                        bcf::header::TagType::String => {
                            let i = try!(get_idx());
                            if let Some(values) = try!(record.info(_name).string()) {
                                try!(writer.write_field(values[i]));
                            } else {
                                try!(writer.write_field(b""));
                            }
                        }
                    }
                } else {
                    // tag undefined, write NA
                    try!(writer.write_field(b""));
                }
            }

            let genotypes = if show_genotypes {
                let genotypes = try!(record.genotypes());
                Some(
                    (0..reader.header.sample_count() as usize).map(|s| {
                        format!("{}", genotypes.get(s))
                    }).collect_vec()
                )
            } else {
                None
            };

            for s in 0..reader.header.sample_count() as usize {
                if let Some(ref genotypes) = genotypes {
                    try!(writer.write_field(genotypes[s].as_bytes()));
                }
                for name in format_tags {
                    let _name = name.as_bytes();
                    if let Ok((tag_type, tag_length)) = reader.header.format_type(_name) {
                        let i = match tag_length {
                            bcf::header::TagLength::Fixed => {
                                0
                            },
                            bcf::header::TagLength::AltAlleles => {
                                i
                            },
                            _ => return Err(Box::new(ParseError::UnsupportedTagLength))
                        };

                        match tag_type {
                            bcf::header::TagType::Flag => {
                                panic!("there is no flag type for format");
                            },
                            bcf::header::TagType::Integer => {
                                try!(writer.write_field(format!("{}", try!(record.format(_name).integer())[s][i]).as_bytes()));
                            },
                            bcf::header::TagType::Float => {
                                try!(writer.write_field(format!("{}", try!(record.format(_name).float())[s][i]).as_bytes()));
                            },
                            bcf::header::TagType::String => {
                                try!(writer.write_field(try!(record.format(_name).string())[s]));
                            }
                        }
                    } else {
                        // tag undefined, write NA
                        try!(writer.write_field(b""));
                    }
                }
            }
            try!(writer.newline());
        }
    }

    Ok(())
}

quick_error! {
    #[derive(Debug)]
    pub enum ParseError {
        UnsupportedTagLength {
            description("currently, only A and 1 are supported multiplicities of tags")
        }

    }
}
<commit_msg>Support variable length<commit_after>use std::error::Error;
use std::io;
use std::str;
use std::io::Write;

use itertools::Itertools;
use rust_htslib::bcf;
use rust_htslib::bcf::record::Numeric;

pub struct Writer {
    inner: io::BufWriter<io::Stdout>,
    field_count: usize
}

impl Writer {
    fn new(inner: io::BufWriter<io::Stdout>) -> Self {
        Writer {
            inner: inner,
            field_count: 0
        }
    }

    fn write_integer(&mut self, value: i32) -> Result<(), Box<Error>> {
        self.write_field(format!("{}", value).as_bytes())
    }

    fn write_float(&mut self, value: f32) -> Result<(), Box<Error>> {
        self.write_field(format!("{}", value).as_bytes())
    }

    fn write_flag(&mut self, value: bool) -> Result<(), Box<Error>> {
        self.write_field(format!("{}", value).as_bytes())
    }

    fn write_field(&mut self, value: &[u8]) -> Result<(), Box<Error>> {
        if self.field_count > 0 {
            try!(self.inner.write(b"\t"));
        }
        try!(self.inner.write(value));
        self.field_count += 1;
        Ok(())
    }

    fn newline(&mut self) -> Result<(), Box<Error>> {
        try!(self.inner.write(b"\n"));
        self.field_count = 0;
        Ok(())
    }
}

const HEADER_COMMON: &'static [u8] = b"VARIANT";

pub fn to_txt(
    info_tags: &[&str],
    format_tags: &[&str],
    show_genotypes: bool
) -> Result<(), Box<Error>> {
    let reader = try!(bcf::Reader::new(&"-"));
    let mut writer = Writer::new(io::BufWriter::new(io::stdout()));

    let common_n = 5 + info_tags.len();
    try!(writer.write_field(HEADER_COMMON));
    for _ in 1..common_n {
        try!(writer.write_field(HEADER_COMMON));
    }
    for sample in reader.header.samples() {
        try!(writer.write_field(sample));
        for _ in 1..format_tags.len() + show_genotypes as usize {
            try!(writer.write_field(sample));
        }
    }
    try!(writer.newline());
    try!(writer.write_field(b"CHROM"));
    try!(writer.write_field(b"POS"));
    try!(writer.write_field(b"REF"));
    try!(writer.write_field(b"ALT"));
    try!(writer.write_field(b"QUAL"));
    for name in info_tags {
        try!(writer.write_field(name.as_bytes()));
    }
    for _ in 0..reader.header.sample_count() {
        if show_genotypes {
            try!(writer.write_field(b"GT"));
        }
        for name in format_tags {
            try!(writer.write_field(name.as_bytes()));
        }
    }
    try!(writer.newline());

    let mut record = bcf::Record::new();
    loop {
        if let Err(e) = reader.read(&mut record) {
            if e.is_eof() {
                break;
            } else {
                return Err(Box::new(e));
            }
        }

        let alleles = record.alleles().into_iter().map(|a| a.to_owned()).collect_vec();
        for (i, allele) in alleles[1..].iter().enumerate() {
            try!(writer.write_field(reader.header.rid2name(record.rid().unwrap())));
            try!(writer.write_integer(record.pos() as i32 + 1));
            try!(writer.write_field(&alleles[0]));
            try!(writer.write_field(allele));
            match record.qual() {
                q if q.is_missing() => try!(writer.write_field(b"")),
                q => try!(writer.write_float(q))
            }

            for name in info_tags {
                let _name = name.as_bytes();
                if let Ok((tag_type, tag_length)) = reader.header.info_type(_name) {
                    let get_idx = || {
                        match tag_length {
                            bcf::header::TagLength::Fixed => {
                                Ok(0)
                            },
                            bcf::header::TagLength::AltAlleles => {
                                Ok(i)
                            },
                            bcf::header::TagLength::Variable => {
                                Ok(i)
                            },
                            _ => Err(Box::new(ParseError::UnsupportedTagLength))
                        }
                    };

                    match tag_type {
                        bcf::header::TagType::Flag => {
                            try!(writer.write_flag(try!(record.info(_name).flag())));
                        },
                        bcf::header::TagType::Integer => {
                            let i = try!(get_idx());
                            if let Some(values) = try!(record.info(_name).integer()) {
                                try!(writer.write_integer(values[i]));
                            } else {
                                try!(writer.write_field(b""));
                            }
                        },
                        bcf::header::TagType::Float => {
                            let i = try!(get_idx());
                            if let Some(values) = try!(record.info(_name).float()) {
                                try!(writer.write_float(values[i]));
                            } else {
                                try!(writer.write_field(b""));
                            }
                        },
                        bcf::header::TagType::String => {
                            let i = try!(get_idx());
                            if let Some(values) = try!(record.info(_name).string()) {
                                try!(writer.write_field(values[i]));
                            } else {
                                try!(writer.write_field(b""));
                            }
                        }
                    }
                } else {
                    // tag undefined, write NA
                    try!(writer.write_field(b""));
                }
            }

            let genotypes = if show_genotypes {
                let genotypes = try!(record.genotypes());
                Some(
                    (0..reader.header.sample_count() as usize).map(|s| {
                        format!("{}", genotypes.get(s))
                    }).collect_vec()
                )
            } else {
                None
            };

            for s in 0..reader.header.sample_count() as usize {
                if let Some(ref genotypes) = genotypes {
                    try!(writer.write_field(genotypes[s].as_bytes()));
                }
                for name in format_tags {
                    let _name = name.as_bytes();
                    if let Ok((tag_type, tag_length)) = reader.header.format_type(_name) {
                        let i = match tag_length {
                            bcf::header::TagLength::Fixed => {
                                0
                            },
                            bcf::header::TagLength::AltAlleles => {
                                i
                            },
                            _ => return Err(Box::new(ParseError::UnsupportedTagLength))
                        };

                        match tag_type {
                            bcf::header::TagType::Flag => {
                                panic!("there is no flag type for format");
                            },
                            bcf::header::TagType::Integer => {
                                try!(writer.write_field(format!("{}", try!(record.format(_name).integer())[s][i]).as_bytes()));
                            },
                            bcf::header::TagType::Float => {
                                try!(writer.write_field(format!("{}", try!(record.format(_name).float())[s][i]).as_bytes()));
                            },
                            bcf::header::TagType::String => {
                                try!(writer.write_field(try!(record.format(_name).string())[s]));
                            }
                        }
                    } else {
                        // tag undefined, write NA
                        try!(writer.write_field(b""));
                    }
                }
            }
            try!(writer.newline());
        }
    }

    Ok(())
}

quick_error! {
    #[derive(Debug)]
    pub enum ParseError {
        UnsupportedTagLength {
            description("currently, only A and 1 are supported multiplicities of tags")
        }

    }
}
<|endoftext|>


<commit_before>use tile_engine::TileEngine;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use dungeon_generator::{BSPGenerator, Room, DungeonGenerator};
use std::collections::HashSet;
use unit::Unit;
use common::*;
use rand::{SeedableRng, StdRng, Rng};

const TEMP_WIDTH: u32 = 800;
const TEMP_HEIGHT: u32 = 600;
const TILE_SCALE: u32 = 4;
const TEMP_TILE_SIZE: u32 = TILE_SIZE/TILE_SCALE;

pub struct Game {
    pub tiles: TileEngine<TileType>,
    pub player: Unit,
    pub enemies: Vec<Unit>,
    rooms: Vec<Room>,
    pressed_keys: HashSet<Keycode>,
}

impl Game {
    pub fn new() -> Game {
        Game {
            tiles: TileEngine::<TileType>::default(),
            player: Unit::new((0, 0)),
            enemies: vec![],
            rooms: vec![],
            pressed_keys: HashSet::<Keycode>::new(),
        }
    }

    pub fn update(&mut self) {

    }

    pub fn proc_event(&mut self, event: Event) {
        match event {
            Event::KeyDown { keycode: Some(key), .. } =>
                self.proc_key_down(key),
            Event::KeyUp { keycode: Some(key), .. } =>
                self.proc_key_up(key),
            _   => return,
        }
    }

    fn proc_key_down(&mut self, key: Keycode) {
        if self.pressed_keys.contains(&key) {
            return;
        }
        self.pressed_keys.insert(key);
        match key {
            Keycode::Up | Keycode::J => {
                self.make_move((0, -1));
            },
            Keycode::Down | Keycode::K => {
                self.make_move((0, 1));
            },
            Keycode::Left | Keycode::H => {
                self.make_move((-1, 0));
            },
            Keycode::Right | Keycode::L => {
                self.make_move((1, 0));
            },
            _ => return,
        }

    }

    fn proc_key_up(&mut self, key: Keycode) {
        self.pressed_keys.remove(&key);
    }

    pub fn generate_level(&mut self, seed: &[usize]) {
        let mut rng: StdRng = SeedableRng::from_seed(seed);
        self.rooms = BSPGenerator::default().min_room_splittable_size(100).coridor_width(15).generate(seed, TEMP_WIDTH, TEMP_HEIGHT);
        let players_start_room = &self.rooms[rng.gen_range(0, self.rooms.len())];
        self.player.tile = ((rng.gen_range(players_start_room.x, players_start_room.x + players_start_room.width)/TEMP_TILE_SIZE) as i32,
                            (rng.gen_range(players_start_room.y, players_start_room.y + players_start_room.height)/TEMP_TILE_SIZE) as i32);
        for room in self.rooms.iter() {
            let unit_pos = ((rng.gen_range(room.x, room.x + room.width)/TEMP_TILE_SIZE) as i32,
                           (rng.gen_range(room.y, room.y + room.height)/TEMP_TILE_SIZE) as i32);
            self.enemies.push(Unit::new(unit_pos));
            let mut x = (room.x/TEMP_TILE_SIZE)*TEMP_TILE_SIZE;
            while x < room.x + room.width {
                let mut y = (room.y/TEMP_TILE_SIZE)*TEMP_TILE_SIZE;
                while y < room.y + room.height {
                    self.tiles.add_tile((TILE_SCALE*x) as i32,
                                        (TILE_SCALE*y) as i32,
                                        TILE_SIZE,
                                        TILE_SIZE,
                                        FLOOR_LAYER_IND,
                                        TileType::Floor(rng.gen_range(0, 4)));
                    y += TEMP_TILE_SIZE;
                }
                x += TEMP_TILE_SIZE;
            }
        }
    }

    fn is_empty(&self, pos: (i32, i32)) -> bool {
        let (pos_x, pos_y) = global_pos(pos);
        let mut enemy_collide = false;
        for enemy in self.enemies.iter() {
            if (pos.0 == enemy.tile.0) && (pos.1 == enemy.tile.1) {
                enemy_collide = true;
                break;
            }
        }
        enemy_collide || self.tiles.tile_at(pos_x, pos_y, FLOOR_LAYER_IND).is_none()
    }

    fn make_move(&mut self, delta: (i32, i32)) {
        if self.is_empty((self.player.tile.0 + delta.0,
                          self.player.tile.1 + delta.1)) {
            return
        }
        self.player.make_move(delta);
        // AI Works here
        for i in 0..self.enemies.len() {
            let mv = self.enemies[i].ai.get_move(&self.enemies[i], &self);
            self.enemies[i].make_move(mv);
        }
    }
}
<commit_msg>Add ability to skip turn<commit_after>use tile_engine::TileEngine;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use dungeon_generator::{BSPGenerator, Room, DungeonGenerator};
use std::collections::HashSet;
use unit::Unit;
use common::*;
use rand::{SeedableRng, StdRng, Rng};

const TEMP_WIDTH: u32 = 800;
const TEMP_HEIGHT: u32 = 600;
const TILE_SCALE: u32 = 4;
const TEMP_TILE_SIZE: u32 = TILE_SIZE/TILE_SCALE;

pub struct Game {
    pub tiles: TileEngine<TileType>,
    pub player: Unit,
    pub enemies: Vec<Unit>,
    rooms: Vec<Room>,
    pressed_keys: HashSet<Keycode>,
}

impl Game {
    pub fn new() -> Game {
        Game {
            tiles: TileEngine::<TileType>::default(),
            player: Unit::new((0, 0)),
            enemies: vec![],
            rooms: vec![],
            pressed_keys: HashSet::<Keycode>::new(),
        }
    }

    pub fn update(&mut self) {

    }

    pub fn proc_event(&mut self, event: Event) {
        match event {
            Event::KeyDown { keycode: Some(key), .. } =>
                self.proc_key_down(key),
            Event::KeyUp { keycode: Some(key), .. } =>
                self.proc_key_up(key),
            _   => return,
        }
    }

    fn proc_key_down(&mut self, key: Keycode) {
        if self.pressed_keys.contains(&key) {
            return;
        }
        self.pressed_keys.insert(key);
        match key {
            Keycode::Up | Keycode::J => {
                self.make_move((0, -1));
            },
            Keycode::Down | Keycode::K => {
                self.make_move((0, 1));
            },
            Keycode::Left | Keycode::H => {
                self.make_move((-1, 0));
            },
            Keycode::Right | Keycode::L => {
                self.make_move((1, 0));
            },
            Keycode::Space => {
                self.make_move((0, 0));
            },
            _ => return,
        }

    }

    fn proc_key_up(&mut self, key: Keycode) {
        self.pressed_keys.remove(&key);
    }

    pub fn generate_level(&mut self, seed: &[usize]) {
        let mut rng: StdRng = SeedableRng::from_seed(seed);
        self.rooms = BSPGenerator::default().min_room_splittable_size(100).coridor_width(15).generate(seed, TEMP_WIDTH, TEMP_HEIGHT);
        let players_start_room = &self.rooms[rng.gen_range(0, self.rooms.len())];
        self.player.tile = ((rng.gen_range(players_start_room.x, players_start_room.x + players_start_room.width)/TEMP_TILE_SIZE) as i32,
                            (rng.gen_range(players_start_room.y, players_start_room.y + players_start_room.height)/TEMP_TILE_SIZE) as i32);
        for room in self.rooms.iter() {
            let unit_pos = ((rng.gen_range(room.x, room.x + room.width)/TEMP_TILE_SIZE) as i32,
                           (rng.gen_range(room.y, room.y + room.height)/TEMP_TILE_SIZE) as i32);
            self.enemies.push(Unit::new(unit_pos));
            let mut x = (room.x/TEMP_TILE_SIZE)*TEMP_TILE_SIZE;
            while x < room.x + room.width {
                let mut y = (room.y/TEMP_TILE_SIZE)*TEMP_TILE_SIZE;
                while y < room.y + room.height {
                    self.tiles.add_tile((TILE_SCALE*x) as i32,
                                        (TILE_SCALE*y) as i32,
                                        TILE_SIZE,
                                        TILE_SIZE,
                                        FLOOR_LAYER_IND,
                                        TileType::Floor(rng.gen_range(0, 4)));
                    y += TEMP_TILE_SIZE;
                }
                x += TEMP_TILE_SIZE;
            }
        }
    }

    fn is_empty(&self, pos: (i32, i32)) -> bool {
        let (pos_x, pos_y) = global_pos(pos);
        let mut enemy_collide = false;
        for enemy in self.enemies.iter() {
            if (pos.0 == enemy.tile.0) && (pos.1 == enemy.tile.1) {
                enemy_collide = true;
                break;
            }
        }
        enemy_collide || self.tiles.tile_at(pos_x, pos_y, FLOOR_LAYER_IND).is_none()
    }

    fn make_move(&mut self, delta: (i32, i32)) {
        if self.is_empty((self.player.tile.0 + delta.0,
                          self.player.tile.1 + delta.1)) {
            return
        }
        self.player.make_move(delta);
        // AI Works here
        for i in 0..self.enemies.len() {
            let mv = self.enemies[i].ai.get_move(&self.enemies[i], &self);
            self.enemies[i].make_move(mv);
        }
    }
}
<|endoftext|>


<commit_before>use ::actions;
use ::board;

use std::hash::{Hash, Hasher, SipHasher};

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Role {
    Dwarf,
    Troll,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Player {
    role: Role,
    name: String,
}

impl Player {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn role(&self) -> Role {
        self.role
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum EndProposal {
    Neither,
    Single(PlayerMarker),
    Both,
}

impl EndProposal {
    fn advance(&mut self, player: PlayerMarker) {
        *self = match *self {
            EndProposal::Single(p) if p != player => EndProposal::Both,
            EndProposal::Neither => EndProposal::Single(player),
            _ => *self,
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum PlayerMarker {
    One,
    Two,
}

impl PlayerMarker {
    pub fn index(self) -> usize {
        match self {
            PlayerMarker::One => 0,
            PlayerMarker::Two => 1,
        }
    }

    pub fn toggle(&mut self) {
        *self = match *self {
            PlayerMarker::One => PlayerMarker::Two,
            PlayerMarker::Two => PlayerMarker::One,
        }
    }
}

pub struct State {
    board: board::Cells,
    players: [Player; 2],
    active_player: PlayerMarker,
    end_proposal: EndProposal,
}

impl State {
    pub fn new(board: board::Cells, player1_name: String, player2_name: String) -> Self {
        State {
            board: board,
            players: [Player { role: Role::Dwarf, name: player1_name, },
                      Player { role: Role::Troll, name: player2_name, },],
            active_player: PlayerMarker::One,
            end_proposal: EndProposal::Neither,
        }
    }

    pub fn new_default(player1_name: String, player2_name: String) -> Self {
        State::new(board::Cells::default(), player1_name, player2_name)
    }

    pub fn active_player(&self) -> &Player {
        &self.players[self.active_player.index()]
    }

    pub fn role_actions<'s>(&'s self, r: Role) -> actions::ActionIterator<'s> {
        self.board.role_actions(r)
    }

    pub fn position_actions<'s>(&'s self, position: board::Coordinate) -> actions::ActionIterator<'s> {
        self.board.position_actions(position)
    }

    pub fn toggle_active_player(&mut self) {
        self.active_player.toggle()
    }

    pub fn do_action(&mut self, a: &actions::Action) {
        match a {
            &actions::Action::Concede => self.end_proposal.advance(self.active_player),
            _ => self.board.do_action(a),
        }
        self.active_player.toggle();
    }

    pub fn terminated(&self) -> bool {
        self.end_proposal == EndProposal::Both
    }

    pub fn board(&self) -> &board::Cells {
        &self.board
    }

    pub fn player(&self, p: PlayerMarker) -> &Player {
        &self.players[p.index()]
    }

    pub fn end_proposal(&self) -> EndProposal {
        self.end_proposal
    }
}

impl Clone for State {
    fn clone(&self) -> Self {
        State {
            board: self.board.clone(),
            players: [self.players[0].clone(),
                      self.players[1].clone()],
            active_player: self.active_player,
            end_proposal: self.end_proposal,
        }
    }
}

impl PartialEq<State> for State {
    fn eq(&self, other: &State) -> bool {
        if self.active_player != other.active_player
            || self.end_proposal == other.end_proposal
            || self.players[0].role() == other.players[0].role() {
                return false
            }
        for row in 0u8..8u8 {
            for col in 0u8..8u8 {
                for &c in [board::Coordinate::new_unchecked(row, col),
                           board::Coordinate::new_unchecked(7u8 - row, col),
                           board::Coordinate::new_unchecked(row, 7u8 - col),
                           board::Coordinate::new_unchecked(7u8 - row, 7u8 - col),
                           board::Coordinate::new_unchecked(col, row),
                           board::Coordinate::new_unchecked(7u8 - col, row),
                           board::Coordinate::new_unchecked(col, 7u8 - row),
                           board::Coordinate::new_unchecked(7u8 - col, 7u8 - row)].iter() {
                    if self.board[c] != other.board[c] {
                        return false
                    }
                }
            }
        }
        true
    }
}

impl Eq for State { }

impl Hash for State {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let mut hashers = [SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new()];
        for h in &mut hashers {
            self.active_player.hash(h);
            self.players[0].role().hash(h);
            self.players[1].role().hash(h);
            self.end_proposal.hash(h);
        }
        for row in 0u8..8u8 {
            for col in 0u8..8u8 {
                let mut i = 0;
                for &c in &[board::Coordinate::new_unchecked(row, col),
                            board::Coordinate::new_unchecked(7u8 - row, col),
                            board::Coordinate::new_unchecked(row, 7u8 - col),
                            board::Coordinate::new_unchecked(7u8 - row, 7u8 - col),
                            board::Coordinate::new_unchecked(col, row),
                            board::Coordinate::new_unchecked(7u8 - col, row),
                            board::Coordinate::new_unchecked(col, 7u8 - row),
                            board::Coordinate::new_unchecked(7u8 - col, 7u8 - row)] {
                    self.board[c].hash(&mut hashers[i]);
                    i += 1;
                }
            }
        }
        let mut hash_values = [hashers[0].finish(),
                               hashers[1].finish(),
                               hashers[2].finish(),
                               hashers[3].finish(),
                               hashers[4].finish(),
                               hashers[5].finish(),
                               hashers[6].finish(),
                               hashers[7].finish()];
        (&mut hash_values).sort();
        for v in &hash_values {
            state.write_u64(*v);
        }
    }
}
<commit_msg>Add PlayerMarker field to player type.<commit_after>use ::actions;
use ::board;

use std::hash::{Hash, Hasher, SipHasher};

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Role {
    Dwarf,
    Troll,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Player {
    role: Role,
    name: String,
    marker: PlayerMarker,
}

impl Player {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn role(&self) -> Role {
        self.role
    }

    pub fn marker(&self) -> PlayerMarker {
        self.marker
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum EndProposal {
    Neither,
    Single(PlayerMarker),
    Both,
}

impl EndProposal {
    fn advance(&mut self, player: PlayerMarker) {
        *self = match *self {
            EndProposal::Single(p) if p != player => EndProposal::Both,
            EndProposal::Neither => EndProposal::Single(player),
            _ => *self,
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum PlayerMarker {
    One,
    Two,
}

impl PlayerMarker {
    pub fn index(self) -> usize {
        match self {
            PlayerMarker::One => 0,
            PlayerMarker::Two => 1,
        }
    }

    pub fn toggle(&mut self) {
        *self = match *self {
            PlayerMarker::One => PlayerMarker::Two,
            PlayerMarker::Two => PlayerMarker::One,
        }
    }
}

pub struct State {
    board: board::Cells,
    players: [Player; 2],
    active_player: PlayerMarker,
    end_proposal: EndProposal,
}

impl State {
    pub fn new(board: board::Cells, player1_name: String, player2_name: String) -> Self {
        State {
            board: board,
            players: [Player { role: Role::Dwarf, marker: PlayerMarker::One, name: player1_name, },
                      Player { role: Role::Troll, marker: PlayerMarker::Two, name: player2_name, },],
            active_player: PlayerMarker::One,
            end_proposal: EndProposal::Neither,
        }
    }

    pub fn new_default(player1_name: String, player2_name: String) -> Self {
        State::new(board::Cells::default(), player1_name, player2_name)
    }

    pub fn active_player(&self) -> &Player {
        &self.players[self.active_player.index()]
    }

    pub fn role_actions<'s>(&'s self, r: Role) -> actions::ActionIterator<'s> {
        self.board.role_actions(r)
    }

    pub fn position_actions<'s>(&'s self, position: board::Coordinate) -> actions::ActionIterator<'s> {
        self.board.position_actions(position)
    }

    pub fn toggle_active_player(&mut self) {
        self.active_player.toggle()
    }

    pub fn do_action(&mut self, a: &actions::Action) {
        match a {
            &actions::Action::Concede => self.end_proposal.advance(self.active_player),
            _ => self.board.do_action(a),
        }
        self.active_player.toggle();
    }

    pub fn terminated(&self) -> bool {
        self.end_proposal == EndProposal::Both
    }

    pub fn board(&self) -> &board::Cells {
        &self.board
    }

    pub fn player(&self, p: PlayerMarker) -> &Player {
        &self.players[p.index()]
    }

    pub fn end_proposal(&self) -> EndProposal {
        self.end_proposal
    }
}

impl Clone for State {
    fn clone(&self) -> Self {
        State {
            board: self.board.clone(),
            players: [self.players[0].clone(),
                      self.players[1].clone()],
            active_player: self.active_player,
            end_proposal: self.end_proposal,
        }
    }
}

impl PartialEq<State> for State {
    fn eq(&self, other: &State) -> bool {
        if self.active_player != other.active_player
            || self.end_proposal == other.end_proposal
            || self.players[0].role() == other.players[0].role() {
                return false
            }
        for row in 0u8..8u8 {
            for col in 0u8..8u8 {
                for &c in [board::Coordinate::new_unchecked(row, col),
                           board::Coordinate::new_unchecked(7u8 - row, col),
                           board::Coordinate::new_unchecked(row, 7u8 - col),
                           board::Coordinate::new_unchecked(7u8 - row, 7u8 - col),
                           board::Coordinate::new_unchecked(col, row),
                           board::Coordinate::new_unchecked(7u8 - col, row),
                           board::Coordinate::new_unchecked(col, 7u8 - row),
                           board::Coordinate::new_unchecked(7u8 - col, 7u8 - row)].iter() {
                    if self.board[c] != other.board[c] {
                        return false
                    }
                }
            }
        }
        true
    }
}

impl Eq for State { }

impl Hash for State {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let mut hashers = [SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new()];
        for h in &mut hashers {
            self.active_player.hash(h);
            self.players[0].role().hash(h);
            self.players[1].role().hash(h);
            self.end_proposal.hash(h);
        }
        for row in 0u8..8u8 {
            for col in 0u8..8u8 {
                let mut i = 0;
                for &c in &[board::Coordinate::new_unchecked(row, col),
                            board::Coordinate::new_unchecked(7u8 - row, col),
                            board::Coordinate::new_unchecked(row, 7u8 - col),
                            board::Coordinate::new_unchecked(7u8 - row, 7u8 - col),
                            board::Coordinate::new_unchecked(col, row),
                            board::Coordinate::new_unchecked(7u8 - col, row),
                            board::Coordinate::new_unchecked(col, 7u8 - row),
                            board::Coordinate::new_unchecked(7u8 - col, 7u8 - row)] {
                    self.board[c].hash(&mut hashers[i]);
                    i += 1;
                }
            }
        }
        let mut hash_values = [hashers[0].finish(),
                               hashers[1].finish(),
                               hashers[2].finish(),
                               hashers[3].finish(),
                               hashers[4].finish(),
                               hashers[5].finish(),
                               hashers[6].finish(),
                               hashers[7].finish()];
        (&mut hash_values).sort();
        for v in &hash_values {
            state.write_u64(*v);
        }
    }
}
<|endoftext|>


<commit_before>//! utilities for convert array

use ndarray::*;

use super::error::*;
use super::lapack::UPLO;
use super::layout::*;
use super::types::*;

pub fn into_col<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((n, 1)).unwrap()
}

pub fn into_row<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((1, n)).unwrap()
}

pub fn flatten<S>(a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix1>
where
    S: Data,
{
    let n = a.len();
    a.into_shape(n).unwrap()
}

pub fn into_matrix<A, S>(l: MatrixLayout, a: Vec<A>) -> Result<ArrayBase<S, Ix2>>
where
    S: DataOwned<Elem = A>,
{
    match l {
        MatrixLayout::C { row, lda } => {
            Ok(ArrayBase::from_shape_vec((row as usize, lda as usize), a)?)
        }
        MatrixLayout::F { col, lda } => Ok(ArrayBase::from_shape_vec(
            (lda as usize, col as usize).f(),
            a,
        )?),
    }
}

fn uninitialized<A, S>(l: MatrixLayout) -> ArrayBase<S, Ix2>
where
    A: Copy,
    S: DataOwned<Elem = A>,
{
    match l {
        MatrixLayout::C { row, lda } => unsafe {
            ArrayBase::uninitialized((row as usize, lda as usize))
        },
        MatrixLayout::F { col, lda } => unsafe {
            ArrayBase::uninitialized((lda as usize, col as usize).f())
        },
    }
}

pub fn replicate<A, Sv, So, D>(a: &ArrayBase<Sv, D>) -> ArrayBase<So, D>
where
    A: Copy,
    Sv: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
    D: Dimension,
{
    let mut b = unsafe { ArrayBase::uninitialized(a.dim()) };
    b.assign(a);
    b
}

fn clone_with_layout<A, Si, So>(l: MatrixLayout, a: &ArrayBase<Si, Ix2>) -> ArrayBase<So, Ix2>
where
    A: Copy,
    Si: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
{
    let mut b = uninitialized(l);
    b.assign(a);
    b
}

pub fn transpose_data<A, S>(a: &mut ArrayBase<S, Ix2>) -> Result<&mut ArrayBase<S, Ix2>>
where
    A: Copy,
    S: DataOwned<Elem = A> + DataMut,
{
    let l = a.layout()?.toggle_order();
    let new = clone_with_layout(l, a);
    ::std::mem::replace(a, new);
    Ok(a)
}

pub fn generalize<A, S, D>(a: Array<A, D>) -> ArrayBase<S, D>
where
    S: DataOwned<Elem = A>,
    D: Dimension,
{
    // FIXME
    // https://github.com/bluss/rust-ndarray/issues/325
    let strides: Vec<isize> = a.strides().to_vec();
    let new = if a.is_standard_layout() {
        ArrayBase::from_shape_vec(a.dim(), a.into_raw_vec()).unwrap()
    } else {
        ArrayBase::from_shape_vec(a.dim().f(), a.into_raw_vec()).unwrap()
    };
    assert_eq!(
        new.strides(),
        strides.as_slice(),
        "Custom stride is not supported"
    );
    new
}

/// Fills in the remainder of a Hermitian matrix that's represented by only one
/// triangle.
///
/// LAPACK methods on Hermitian matrices usually read/write only one triangular
/// portion of the matrix. This function fills in the other half based on the
/// data in the triangular portion corresponding to `uplo`.
///
/// ***Panics*** if `a` is not square.
pub(crate) fn triangular_fill_hermitian<A, S>(a: &mut ArrayBase<S, Ix2>, uplo: UPLO)
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    assert!(a.is_square());
    match uplo {
        UPLO::Upper => {
            for row in 0..a.nrows() {
                for col in 0..row {
                    a[(row, col)] = a[(col, row)].conj();
                }
            }
        }
        UPLO::Lower => {
            for col in 0..a.ncols() {
                for row in 0..col {
                    a[(row, col)] = a[(col, row)].conj();
                }
            }
        }
    }
}
<commit_msg>clippy mem::replace must_use warning<commit_after>//! utilities for convert array

use ndarray::*;

use super::error::*;
use super::lapack::UPLO;
use super::layout::*;
use super::types::*;

pub fn into_col<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((n, 1)).unwrap()
}

pub fn into_row<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((1, n)).unwrap()
}

pub fn flatten<S>(a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix1>
where
    S: Data,
{
    let n = a.len();
    a.into_shape(n).unwrap()
}

pub fn into_matrix<A, S>(l: MatrixLayout, a: Vec<A>) -> Result<ArrayBase<S, Ix2>>
where
    S: DataOwned<Elem = A>,
{
    match l {
        MatrixLayout::C { row, lda } => {
            Ok(ArrayBase::from_shape_vec((row as usize, lda as usize), a)?)
        }
        MatrixLayout::F { col, lda } => Ok(ArrayBase::from_shape_vec(
            (lda as usize, col as usize).f(),
            a,
        )?),
    }
}

fn uninitialized<A, S>(l: MatrixLayout) -> ArrayBase<S, Ix2>
where
    A: Copy,
    S: DataOwned<Elem = A>,
{
    match l {
        MatrixLayout::C { row, lda } => unsafe {
            ArrayBase::uninitialized((row as usize, lda as usize))
        },
        MatrixLayout::F { col, lda } => unsafe {
            ArrayBase::uninitialized((lda as usize, col as usize).f())
        },
    }
}

pub fn replicate<A, Sv, So, D>(a: &ArrayBase<Sv, D>) -> ArrayBase<So, D>
where
    A: Copy,
    Sv: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
    D: Dimension,
{
    let mut b = unsafe { ArrayBase::uninitialized(a.dim()) };
    b.assign(a);
    b
}

fn clone_with_layout<A, Si, So>(l: MatrixLayout, a: &ArrayBase<Si, Ix2>) -> ArrayBase<So, Ix2>
where
    A: Copy,
    Si: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
{
    let mut b = uninitialized(l);
    b.assign(a);
    b
}

pub fn transpose_data<A, S>(a: &mut ArrayBase<S, Ix2>) -> Result<&mut ArrayBase<S, Ix2>>
where
    A: Copy,
    S: DataOwned<Elem = A> + DataMut,
{
    let l = a.layout()?.toggle_order();
    let new = clone_with_layout(l, a);
    *a = new;
    Ok(a)
}

pub fn generalize<A, S, D>(a: Array<A, D>) -> ArrayBase<S, D>
where
    S: DataOwned<Elem = A>,
    D: Dimension,
{
    // FIXME
    // https://github.com/bluss/rust-ndarray/issues/325
    let strides: Vec<isize> = a.strides().to_vec();
    let new = if a.is_standard_layout() {
        ArrayBase::from_shape_vec(a.dim(), a.into_raw_vec()).unwrap()
    } else {
        ArrayBase::from_shape_vec(a.dim().f(), a.into_raw_vec()).unwrap()
    };
    assert_eq!(
        new.strides(),
        strides.as_slice(),
        "Custom stride is not supported"
    );
    new
}

/// Fills in the remainder of a Hermitian matrix that's represented by only one
/// triangle.
///
/// LAPACK methods on Hermitian matrices usually read/write only one triangular
/// portion of the matrix. This function fills in the other half based on the
/// data in the triangular portion corresponding to `uplo`.
///
/// ***Panics*** if `a` is not square.
pub(crate) fn triangular_fill_hermitian<A, S>(a: &mut ArrayBase<S, Ix2>, uplo: UPLO)
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    assert!(a.is_square());
    match uplo {
        UPLO::Upper => {
            for row in 0..a.nrows() {
                for col in 0..row {
                    a[(row, col)] = a[(col, row)].conj();
                }
            }
        }
        UPLO::Lower => {
            for col in 0..a.ncols() {
                for row in 0..col {
                    a[(row, col)] = a[(col, row)].conj();
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

//! Local state for external blobs and their states.

use diesel;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;

use errors::DieselError;

use sodiumoxide::randombytes::randombytes;
use std::sync::{Mutex, MutexGuard};

use super::schema;
use tags;
use util;

#[derive(Clone, Debug, Default)]
pub struct BlobDesc {
    pub name: Vec<u8>,
    pub id: i64,
}

pub struct InternalBlobIndex {
    conn: SqliteConnection,
    next_id: i64,
}

pub struct BlobIndex(Mutex<InternalBlobIndex>);

impl InternalBlobIndex {
    pub fn new(path: &str) -> Result<InternalBlobIndex, DieselError> {
        let conn = try!(SqliteConnection::establish(path));

        let mut bi = InternalBlobIndex {
            conn: conn,
            next_id: -1,
        };

        let dir = try!(diesel::migrations::find_migrations_directory());
        try!(diesel::migrations::run_pending_migrations_in_directory(&bi.conn,
                                                                     &dir,
                                                                     &mut util::InfoWriter));
        try!(bi.conn.begin_transaction());
        bi.refresh_next_id();
        Ok(bi)
    }

    fn new_blob_desc(&mut self) -> BlobDesc {
        BlobDesc {
            name: randombytes(24),
            id: self.next_id(),
        }
    }

    pub fn refresh_next_id(&mut self) {
        use diesel::expression::max;
        use super::schema::blobs::dsl::*;

        let id_opt = blobs.select(max(id).nullable())
            .first::<Option<i64>>(&self.conn)
            .optional()
            .expect("Error querying blobs")
            .and_then(|x| x);

        self.next_id = 1 + id_opt.unwrap_or(0);
    }

    fn next_id(&mut self) -> i64 {
        let id = self.next_id;
        self.next_id += 1;

        id
    }

    fn recover(&mut self, name: Vec<u8>) -> BlobDesc {
        if let Some(id) = self.find_id(&name[..]) {
            // Blob exists.
            return BlobDesc {
                name: name,
                id: id,
            };
        }

        let blob = BlobDesc {
            name: name,
            id: self.next_id(),
        };
        self.in_air(&blob);
        self.commit_blob(&blob);

        blob
    }

    fn reserve(&mut self) -> BlobDesc {
        self.new_blob_desc()
    }

    fn in_air(&mut self, blob: &BlobDesc) {
        use super::schema::blobs::dsl::*;

        let new = schema::NewBlob {
            id: blob.id,
            name: &blob.name,
            tag: tags::Tag::InProgress as i32,
        };
        diesel::insert(&new)
            .into(blobs)
            .execute(&self.conn)
            .expect("Error inserting blob");

        self.new_transaction();
    }

    fn new_transaction(&mut self) {
        self.conn.commit_transaction().unwrap();
        self.conn.begin_transaction().unwrap();
    }

    fn commit_blob(&mut self, blob: &BlobDesc) {
        use super::schema::blobs::dsl::*;

        diesel::update(blobs.find(blob.id))
            .set(tag.eq(tags::Tag::Done as i32))
            .execute(&self.conn)
            .expect("Error updating blob");
        self.new_transaction();
    }

    fn find_id(&mut self, name_: &[u8]) -> Option<i64> {
        use super::schema::blobs::dsl::*;
        blobs.filter(name.eq(name_))
            .select(id)
            .first::<i64>(&self.conn)
            .optional()
            .expect("Error reading blob")
    }

    fn tag(&mut self, tag_: tags::Tag, target: Option<&BlobDesc>) {
        use super::schema::blobs::dsl::*;
        match target {
            None => {
                diesel::update(blobs)
                    .set(tag.eq(tag_ as i32))
                    .execute(&self.conn)
                    .expect("Error updating blob tags")
            }
            Some(t) if t.id > 0 => {
                diesel::update(blobs.find(t.id))
                    .set(tag.eq(tag_ as i32))
                    .execute(&self.conn)
                    .expect("Error updating blob tags")
            }
            Some(t) if !t.name.is_empty() => {
                diesel::update(blobs.filter(name.eq(&t.name)))
                    .set(tag.eq(tag_ as i32))
                    .execute(&self.conn)
                    .expect("Error updating blob tags")
            }
            _ => unreachable!(),
        };
    }

    fn delete_by_tag(&mut self, tag_: tags::Tag) {
        use super::schema::blobs::dsl::*;
        diesel::delete(blobs.filter(tag.eq(tag_ as i32)))
            .execute(&self.conn)
            .expect("Error deleting blobs");
    }

    fn list_by_tag(&mut self, tag_: tags::Tag) -> Vec<BlobDesc> {
        use super::schema::blobs::dsl::*;
        blobs.filter(tag.eq(tag_ as i32))
            .load::<schema::Blob>(&self.conn)
            .expect("Error listing blobs")
            .into_iter()
            .map(|blob_| {
                BlobDesc {
                    id: blob_.id,
                    name: blob_.name,
                }
            })
            .collect()
    }
}

impl BlobIndex {
    pub fn new(path: &str) -> Result<BlobIndex, DieselError> {
        InternalBlobIndex::new(path).map(|index| BlobIndex(Mutex::new(index)))
    }

    #[cfg(test)]
    pub fn new_for_testing() -> Result<BlobIndex, DieselError> {
        BlobIndex::new(":memory:")
    }

    fn lock(&self) -> MutexGuard<InternalBlobIndex> {
        self.0.lock().expect("index-process has failed")
    }

    /// Reserve an internal `BlobDesc` for a new blob.
    pub fn reserve(&self) -> BlobDesc {
        self.lock().reserve()
    }

    /// Report that this blob is in the process of being committed to persistent storage. If a
    /// blob is in this state when the system starts up, it may or may not exist in the persistent
    /// storage, but **should not** be referenced elsewhere, and is therefore safe to delete.
    pub fn in_air(&self, blob: &BlobDesc) {
        self.lock().in_air(blob)
    }

    /// Report that this blob has been fully committed to persistent storage. We can now use its
    /// reference internally. Only committed blobs are considered "safe to use".
    pub fn commit_done(&self, blob: &BlobDesc) {
        self.lock().commit_blob(blob)
    }

    /// Reinstall blob recovered by from external storage.
    /// Creates a new blob by a known external name.
    pub fn recover(&self, name: Vec<u8>) -> BlobDesc {
        self.lock().recover(name)
    }

    pub fn tag(&self, blob: &BlobDesc, tag: tags::Tag) {
        self.lock().tag(tag, Some(blob))
    }

    pub fn tag_all(&self, tag: tags::Tag) {
        self.lock().tag(tag, None)
    }

    pub fn list_by_tag(&self, tag: tags::Tag) -> Vec<BlobDesc> {
        self.lock().list_by_tag(tag)
    }

    pub fn delete_by_tag(&self, tag: tags::Tag) {
        self.lock().delete_by_tag(tag)
    }

    pub fn flush(&self) {
        self.lock().new_transaction()
    }
}
<commit_msg>Change blob names to encrypted IDs.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

//! Local state for external blobs and their states.

use crypto;

use diesel;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;

use errors::DieselError;

use sodiumoxide::randombytes::randombytes;
use std::sync::{Mutex, MutexGuard};

use super::schema;
use tags;
use util;

#[derive(Clone, Debug, Default)]
pub struct BlobDesc {
    pub name: Vec<u8>,
    pub id: i64,
}

pub struct InternalBlobIndex {
    conn: SqliteConnection,
    next_id: i64,
    name_key: crypto::FixedKey,
}

pub struct BlobIndex(Mutex<InternalBlobIndex>);

impl InternalBlobIndex {
    pub fn new(path: &str) -> Result<InternalBlobIndex, DieselError> {
        let conn = try!(SqliteConnection::establish(path));

        // TODO(jos): Plug an actual crypto key through somehow.
        let pubkey = crypto::sealed::desc::PublicKey::from_slice(&[215, 136, 80, 128, 158, 109,
                                                                   227, 141, 219, 63, 118, 91,
                                                                   123, 97, 1, 97, 65, 237, 62,
                                                                   171, 83, 159, 200, 11, 68,
                                                                   138, 40, 82, 24, 47, 187, 29])
            .unwrap();
        let seckey = crypto::sealed::desc::SecretKey::from_slice(&[94, 13, 181, 81, 97, 87, 76,
                                                                   37, 53, 92, 120, 232, 17, 126,
                                                                   234, 78, 12, 23, 141, 61, 40,
                                                                   10, 136, 127, 103, 192, 255,
                                                                   193, 142, 154, 101, 35])
            .unwrap();
        let name_key = crypto::FixedKey::new(pubkey, Some(seckey));

        let mut bi = InternalBlobIndex {
            conn: conn,
            next_id: -1,
            name_key: name_key,
        };

        let dir = try!(diesel::migrations::find_migrations_directory());
        try!(diesel::migrations::run_pending_migrations_in_directory(&bi.conn,
                                                                     &dir,
                                                                     &mut util::InfoWriter));
        try!(bi.conn.begin_transaction());
        bi.refresh_next_id();
        Ok(bi)
    }

    fn name_of_id(&self, id: i64) -> Vec<u8> {
        return self.name_key.seal(crypto::PlainText::from_i64(id).as_ref()).to_vec();
    }

    fn new_blob_desc(&mut self) -> BlobDesc {
        let id = self.next_id();
        BlobDesc {
            name: self.name_of_id(id),
            id: id,
        }
    }

    pub fn refresh_next_id(&mut self) {
        use diesel::expression::max;
        use super::schema::blobs::dsl::*;

        let id_opt = blobs.select(max(id).nullable())
            .first::<Option<i64>>(&self.conn)
            .optional()
            .expect("Error querying blobs")
            .and_then(|x| x);

        self.next_id = 1 + id_opt.unwrap_or(0);
    }

    fn next_id(&mut self) -> i64 {
        let id = self.next_id;
        self.next_id += 1;
        id
    }

    fn recover(&mut self, name: Vec<u8>) -> BlobDesc {
        if let Some(id) = self.find_id(&name[..]) {
            // Blob exists.
            return BlobDesc {
                name: name,
                id: id,
            };
        }

        let blob = BlobDesc {
            name: name,
            id: self.next_id(),
        };
        self.in_air(&blob);
        self.commit_blob(&blob);

        blob
    }

    fn reserve(&mut self) -> BlobDesc {
        self.new_blob_desc()
    }

    fn in_air(&mut self, blob: &BlobDesc) {
        use super::schema::blobs::dsl::*;

        let new = schema::NewBlob {
            id: blob.id,
            name: &blob.name,
            tag: tags::Tag::InProgress as i32,
        };
        diesel::insert(&new)
            .into(blobs)
            .execute(&self.conn)
            .expect("Error inserting blob");

        self.new_transaction();
    }

    fn new_transaction(&mut self) {
        self.conn.commit_transaction().unwrap();
        self.conn.begin_transaction().unwrap();
    }

    fn commit_blob(&mut self, blob: &BlobDesc) {
        use super::schema::blobs::dsl::*;

        diesel::update(blobs.find(blob.id))
            .set(tag.eq(tags::Tag::Done as i32))
            .execute(&self.conn)
            .expect("Error updating blob");
        self.new_transaction();
    }

    fn find_id(&mut self, name_: &[u8]) -> Option<i64> {
        use super::schema::blobs::dsl::*;
        blobs.filter(name.eq(name_))
            .select(id)
            .first::<i64>(&self.conn)
            .optional()
            .expect("Error reading blob")
    }

    fn tag(&mut self, tag_: tags::Tag, target: Option<&BlobDesc>) {
        use super::schema::blobs::dsl::*;
        match target {
            None => {
                diesel::update(blobs)
                    .set(tag.eq(tag_ as i32))
                    .execute(&self.conn)
                    .expect("Error updating blob tags")
            }
            Some(t) if t.id > 0 => {
                diesel::update(blobs.find(t.id))
                    .set(tag.eq(tag_ as i32))
                    .execute(&self.conn)
                    .expect("Error updating blob tags")
            }
            Some(t) if !t.name.is_empty() => {
                diesel::update(blobs.filter(name.eq(&t.name)))
                    .set(tag.eq(tag_ as i32))
                    .execute(&self.conn)
                    .expect("Error updating blob tags")
            }
            _ => unreachable!(),
        };
    }

    fn delete_by_tag(&mut self, tag_: tags::Tag) {
        use super::schema::blobs::dsl::*;
        diesel::delete(blobs.filter(tag.eq(tag_ as i32)))
            .execute(&self.conn)
            .expect("Error deleting blobs");
    }

    fn list_by_tag(&mut self, tag_: tags::Tag) -> Vec<BlobDesc> {
        use super::schema::blobs::dsl::*;
        blobs.filter(tag.eq(tag_ as i32))
            .load::<schema::Blob>(&self.conn)
            .expect("Error listing blobs")
            .into_iter()
            .map(|blob_| {
                BlobDesc {
                    id: blob_.id,
                    name: blob_.name,
                }
            })
            .collect()
    }
}

impl BlobIndex {
    pub fn new(path: &str) -> Result<BlobIndex, DieselError> {
        InternalBlobIndex::new(path).map(|index| BlobIndex(Mutex::new(index)))
    }

    #[cfg(test)]
    pub fn new_for_testing() -> Result<BlobIndex, DieselError> {
        BlobIndex::new(":memory:")
    }

    fn lock(&self) -> MutexGuard<InternalBlobIndex> {
        self.0.lock().expect("index-process has failed")
    }

    /// Reserve an internal `BlobDesc` for a new blob.
    pub fn reserve(&self) -> BlobDesc {
        self.lock().reserve()
    }

    /// Report that this blob is in the process of being committed to persistent storage. If a
    /// blob is in this state when the system starts up, it may or may not exist in the persistent
    /// storage, but **should not** be referenced elsewhere, and is therefore safe to delete.
    pub fn in_air(&self, blob: &BlobDesc) {
        self.lock().in_air(blob)
    }

    /// Report that this blob has been fully committed to persistent storage. We can now use its
    /// reference internally. Only committed blobs are considered "safe to use".
    pub fn commit_done(&self, blob: &BlobDesc) {
        self.lock().commit_blob(blob)
    }

    /// Reinstall blob recovered by from external storage.
    /// Creates a new blob by a known external name.
    pub fn recover(&self, name: Vec<u8>) -> BlobDesc {
        self.lock().recover(name)
    }

    pub fn tag(&self, blob: &BlobDesc, tag: tags::Tag) {
        self.lock().tag(tag, Some(blob))
    }

    pub fn tag_all(&self, tag: tags::Tag) {
        self.lock().tag(tag, None)
    }

    pub fn list_by_tag(&self, tag: tags::Tag) -> Vec<BlobDesc> {
        self.lock().list_by_tag(tag)
    }

    pub fn delete_by_tag(&self, tag: tags::Tag) {
        self.lock().delete_by_tag(tag)
    }

    pub fn flush(&self) {
        self.lock().new_transaction()
    }
}
<|endoftext|>


<commit_before>use std::char;
use entities;
use entities::ENTITIES;

pub fn as_html(i: u32) -> String {
    // Some characters have multiple entity options
    // e.g. " and "
    let entity_options = ENTITIES.iter()
        .filter(|e| {
            match e.codepoints {
                entities::Codepoints::Single(cp) => cp == i,
                _ => false,
            }
        })
        .collect::<Vec<_>>();

    if entity_options.is_empty() {
        format!("&#x{:01$X};", i, 4)
    } else {
        let nicest = choose_nice_entity(entity_options);
        nicest.entity.to_string()
    }
}

// "nice" means prefer lowercase and ends with a semicolon
fn choose_nice_entity(options: Vec<&entities::Entity>) -> &entities::Entity {
    assert!(!options.is_empty());

    let nicest_entity = options.iter().find(|entity| has_semicolon(entity) && !is_all_caps(entity));

    if let Some(entity) = nicest_entity {
        return entity;
    }

    let less_nice_entity = options.iter().find(|entity| has_semicolon(entity));

    if let Some(entity) = less_nice_entity {
        return entity;
    }

    let ok_entity = options.iter().find(|entity| !is_all_caps(entity));

    if let Some(entity) = ok_entity {
        return entity;
    }

    options[0]
}

fn has_semicolon(entity: &entities::Entity) -> bool {
    entity.entity.ends_with(";")
}

fn is_all_caps(entity: &entities::Entity) -> bool {
    !entity.entity.chars().any(char::is_lowercase)
}

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

    #[test]
    fn test_as_html() {
        assert_eq!(as_html(0), r"�");
        assert_eq!(as_html(0xFFFF), r"");
        assert_ne!(as_html(0xBEEF), r"뻯");
        assert_eq!(as_html(',' as u32), r",");
        assert_eq!(as_html('>' as u32), r">");
        // assert_eq!(as_html(0x10000), ?);
    }
}
<commit_msg>Add nice html entity tests<commit_after>use std::char;
use entities::{ENTITIES, Codepoints};

pub fn as_html(i: u32) -> String {
    // Some characters have multiple entity options
    // e.g. " and "
    let entity_options = ENTITIES.iter()
        .filter_map(|e| {
            match e.codepoints {
                Codepoints::Single(cp) => if cp == i { Some(e.entity) } else { None },
                _ => None,
            }
        })
        .collect::<Vec<_>>();

    if entity_options.is_empty() {
        format!("&#x{:01$X};", i, 4)
    } else {
        choose_nice_entity(entity_options).to_string()
    }
}

// "nice" means prefer lowercase and ends with a semicolon
fn choose_nice_entity(options: Vec<&str>) -> &str {
    assert!(!options.is_empty());

    let nicest_entity = options.iter()
        .find(|entity| ends_with_semicolon(entity) && is_all_lowercase(entity));

    if let Some(entity) = nicest_entity {
        return entity;
    }

    let less_nice_entity = options.iter()
        .find(|entity| ends_with_semicolon(entity) && !is_all_caps(entity));

    if let Some(entity) = less_nice_entity {
        return entity;
    }

    let ok_entity = options.iter().find(|entity| ends_with_semicolon(entity));

    if let Some(entity) = ok_entity {
        return entity;
    }

    let no_semi_entity = options.iter().find(|entity| is_all_lowercase(entity));

    if let Some(entity) = no_semi_entity {
        return entity;
    }

    let worst_entity = options.iter().find(|entity| !is_all_caps(entity));

    if let Some(entity) = worst_entity {
        return entity;
    }

    options[0]
}

fn ends_with_semicolon(entity: &str) -> bool {
    entity.ends_with(";")
}

fn is_all_caps(entity: &str) -> bool {
    !entity.chars().any(char::is_lowercase)
}

fn is_all_lowercase(entity: &str) -> bool {
    !entity.chars().any(char::is_uppercase)
}

#[cfg(test)]
mod tests {
    use super::{as_html, ends_with_semicolon, choose_nice_entity, is_all_caps, is_all_lowercase};

    #[test]
    fn test_as_html() {
        assert_eq!(as_html(0), r"�");
        assert_eq!(as_html(0xFFFF), r"");
        assert_ne!(as_html(0xBEEF), r"뻯");
        assert_eq!(as_html(',' as u32), r",");
        assert_eq!(as_html('>' as u32), r">");
        // assert_eq!(as_html(0x10000), ?);
    }

    #[test]
    fn test_choose_nice_entity() {
        let e = ["&BAD", "&Bad", "&bad", "&BAD;", "&Bad;", "&bad;"];

        assert_eq!(choose_nice_entity(vec![e[0], e[1], e[2], e[3], e[4], e[5]]),
                   "&bad;");
        assert_eq!(choose_nice_entity(vec![e[0], e[1], e[2], e[3], e[4]]),
                   "&Bad;");
        assert_eq!(choose_nice_entity(vec![e[0], e[1], e[2], e[3]]), "&BAD;");
        assert_eq!(choose_nice_entity(vec![e[0], e[1], e[2]]), "&bad");
        assert_eq!(choose_nice_entity(vec![e[0], e[1]]), "&Bad");
        assert_eq!(choose_nice_entity(vec![e[0]]), "&BAD");
    }

    #[test]
    fn test_ends_with_semicolon() {
        assert!(ends_with_semicolon(";"));
        assert!(!ends_with_semicolon("beef"));
        assert!(!ends_with_semicolon(";Beef"));
        assert!(ends_with_semicolon("WITH SPACES;"));
        assert!(ends_with_semicolon("Double semicolon;;"));
    }

    #[test]
    fn test_is_all_caps() {
        assert!(is_all_caps("BEEF"));
        assert!(!is_all_caps("beef"));
        assert!(!is_all_caps("Beef"));
        assert!(is_all_caps("WITH SPACES"));
        assert!(is_all_caps("WITH_SYMBOLS&&;;"));
        assert!(!is_all_caps("&WithSymbols"));
    }

    #[test]
    fn test_is_all_lowercase() {
        assert!(!is_all_lowercase("BEEF"));
        assert!(is_all_lowercase("beef"));
        assert!(!is_all_lowercase("Beef"));
        assert!(is_all_lowercase("with spaces"));
        assert!(is_all_lowercase("with_symbols&&;;"));
        assert!(!is_all_lowercase("&WithSymbols"));
    }
}
<|endoftext|>


<commit_before>//! Bindings to IOCP, I/O Completion Ports

use std::cmp;
use std::io;
use std::mem;
use std::os::windows::io::*;

use handle::Handle;
use winapi::*;
use kernel32::*;
use Overlapped;

/// A handle to an Windows I/O Completion Port.
#[derive(Debug)]
pub struct CompletionPort {
    handle: Handle,
}

/// A status message received from an I/O completion port.
///
/// These statuses can be created via the `new` or `empty` constructors and then
/// provided to a completion port, or they are read out of a completion port.
/// The fields of each status are read through its accessor methods.
#[derive(Clone, Copy, Debug)]
pub struct CompletionStatus(OVERLAPPED_ENTRY);

unsafe impl Send for CompletionStatus {}
unsafe impl Sync for CompletionStatus {}

impl CompletionPort {
    /// Creates a new I/O completion port with the specified concurrency value.
    ///
    /// The number of threads given corresponds to the level of concurrency
    /// allowed for threads associated with this port. Consult the Windows
    /// documentation for more information about this value.
    pub fn new(threads: u32) -> io::Result<CompletionPort> {
        let ret = unsafe {
            CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0 as *mut _,
                                   0, threads)
        };
        if ret.is_null() {
            Err(io::Error::last_os_error())
        } else {
            Ok(CompletionPort { handle: Handle::new(ret) })
        }
    }

    /// Associates a new `HANDLE` to this I/O completion port.
    ///
    /// This function will associate the given handle to this port with the
    /// given `token` to be returned in status messages whenever it receives a
    /// notification.
    ///
    /// Any object which is convertible to a `HANDLE` via the `AsRawHandle`
    /// trait can be provided to this function, such as `std::fs::File` and
    /// friends.
    pub fn add_handle<T: AsRawHandle + ?Sized>(&self, token: usize,
                                               t: &T) -> io::Result<()> {
        self._add(token, t.as_raw_handle())
    }

    /// Associates a new `SOCKET` to this I/O completion port.
    ///
    /// This function will associate the given socket to this port with the
    /// given `token` to be returned in status messages whenever it receives a
    /// notification.
    ///
    /// Any object which is convertible to a `SOCKET` via the `AsRawSocket`
    /// trait can be provided to this function, such as `std::net::TcpStream`
    /// and friends.
    pub fn add_socket<T: AsRawSocket + ?Sized>(&self, token: usize,
                                               t: &T) -> io::Result<()> {
        self._add(token, t.as_raw_socket() as HANDLE)
    }

    fn _add(&self, token: usize, handle: HANDLE) -> io::Result<()> {
        assert_eq!(mem::size_of_val(&token), mem::size_of::<ULONG_PTR>());
        let ret = unsafe {
            CreateIoCompletionPort(handle, self.handle.raw(),
                                   token as ULONG_PTR, 0)
        };
        if ret.is_null() {
            Err(io::Error::last_os_error())
        } else {
            debug_assert_eq!(ret, self.handle.raw());
            Ok(())
        }
    }

    /// Dequeue a completion status from this I/O completion port.
    ///
    /// This function will associate the calling thread with this completion
    /// port and then wait for a status message to become available. The precise
    /// semantics on when this function returns depends on the concurrency value
    /// specified when the port was created.
    ///
    /// A timeout (in milliseconds) can optionally be specified to this
    /// function. If `None` is provided this function will not time out, and
    /// otherwise it will time out after the specified duration has passed.
    ///
    /// On success this will return the status message which was dequeued from
    /// this completion port.
    pub fn get(&self, timeout_ms: Option<u32>) -> io::Result<CompletionStatus> {
        let mut bytes = 0;
        let mut token = 0;
        let mut overlapped = 0 as *mut _;
        let timeout = timeout_ms.unwrap_or(INFINITE);
        let ret = unsafe {
            GetQueuedCompletionStatus(self.handle.raw(),
                                      &mut bytes,
                                      &mut token,
                                      &mut overlapped,
                                      timeout)
        };
        ::cvt(ret).map(|_| {
            CompletionStatus(OVERLAPPED_ENTRY {
                dwNumberOfBytesTransferred: bytes,
                lpCompletionKey: token,
                lpOverlapped: overlapped,
                Internal: 0,
            })
        })
    }

    /// Dequeues a number of completion statuses from this I/O completion port.
    ///
    /// This function is the same as `get` except that it may return more than
    /// one status. A buffer of "zero" statuses is provided (the contents are
    /// not read) and then on success this function will return a sub-slice of
    /// statuses which represent those which were dequeued from this port. This
    /// function does not wait to fill up the entire list of statuses provided.
    ///
    /// Like with `get`, a timeout may be specified for this operation.
    pub fn get_many<'a>(&self,
                        list: &'a mut [CompletionStatus],
                        timeout_ms: Option<u32>)
                        -> io::Result<&'a mut [CompletionStatus]>
    {
        debug_assert_eq!(mem::size_of::<CompletionStatus>(),
                         mem::size_of::<OVERLAPPED_ENTRY>());
        let mut removed = 0;
        let timeout = timeout_ms.unwrap_or(INFINITE);
        let len = cmp::min(list.len(), <ULONG>::max_value() as usize) as ULONG;
        let ret = unsafe {
            GetQueuedCompletionStatusEx(self.handle.raw(),
                                        list.as_ptr() as *mut _,
                                        len,
                                        &mut removed,
                                        timeout,
                                        FALSE)
        };
        match ::cvt(ret) {
            Ok(_) => Ok(&mut list[..removed as usize]),
            Err(e) => Err(e),
        }
    }

    /// Posts a new completion status onto this I/O completion port.
    ///
    /// This function will post the given status, with custom parameters, to the
    /// port. Threads blocked in `get` or `get_many` will eventually receive
    /// this status.
    pub fn post(&self, status: CompletionStatus) -> io::Result<()> {
        let ret = unsafe {
            PostQueuedCompletionStatus(self.handle.raw(),
                                       status.0.dwNumberOfBytesTransferred,
                                       status.0.lpCompletionKey,
                                       status.0.lpOverlapped)
        };
        ::cvt(ret).map(|_| ())
    }
}

impl AsRawHandle for CompletionPort {
    fn as_raw_handle(&self) -> HANDLE {
        self.handle.raw()
    }
}

impl FromRawHandle for CompletionPort {
    unsafe fn from_raw_handle(handle: HANDLE) -> CompletionPort {
        CompletionPort { handle: Handle::new(handle) }
    }
}

impl IntoRawHandle for CompletionPort {
    fn into_raw_handle(self) -> HANDLE {
        self.handle.into_raw()
    }
}

impl CompletionStatus {
    /// Creates a new completion status with the provided parameters.
    ///
    /// This function is useful when creating a status to send to a port with
    /// the `post` method. The parameters are opaquely passed through and not
    /// interpreted by the system at all.
    pub fn new(bytes: u32, token: usize, overlapped: *mut Overlapped)
               -> CompletionStatus {
        assert_eq!(mem::size_of_val(&token), mem::size_of::<ULONG_PTR>());
        CompletionStatus(OVERLAPPED_ENTRY {
            dwNumberOfBytesTransferred: bytes,
            lpCompletionKey: token as ULONG_PTR,
            lpOverlapped: overlapped as *mut _,
            Internal: 0,
        })
    }

    /// Creates a new borrowed completion status from the borrowed
    /// `OVERLAPPED_ENTRY` argument provided.
    ///
    /// This method will wrap the `OVERLAPPED_ENTRY` in a `CompletionStatus`,
    /// returning the wrapped structure.
    pub fn from_entry(entry: &OVERLAPPED_ENTRY) -> &CompletionStatus {
        unsafe { &*(entry as *const _ as *const _) }
    }

    /// Creates a new "zero" completion status.
    ///
    /// This function is useful when creating a stack buffer or vector of
    /// completion statuses to be passed to the `get_many` function.
    pub fn zero() -> CompletionStatus {
        CompletionStatus::new(0, 0, 0 as *mut _)
    }

    /// Returns the number of bytes that were transferred for the I/O operation
    /// associated with this completion status.
    pub fn bytes_transferred(&self) -> u32 {
        self.0.dwNumberOfBytesTransferred
    }

    /// Returns the completion key value associated with the file handle whose
    /// I/O operation has completed.
    ///
    /// A completion key is a per-handle key that is specified when it is added
    /// to an I/O completion port via `add_handle` or `add_socket`.
    pub fn token(&self) -> usize {
        self.0.lpCompletionKey as usize
    }

    /// Returns a pointer to the `Overlapped` structure that was specified when
    /// the I/O operation was started.
    pub fn overlapped(&self) -> *mut Overlapped {
        self.0.lpOverlapped as *mut _
    }

    /// Returns a pointer to the internal `OVERLAPPED_ENTRY` object.
    pub fn entry(&self) -> &OVERLAPPED_ENTRY {
        &self.0
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use winapi::*;

    use iocp::{CompletionPort, CompletionStatus};

    #[test]
    fn is_send_sync() {
        fn is_send_sync<T: Send + Sync>() {}
        is_send_sync::<CompletionPort>();
    }

    #[test]
    fn token_right_size() {
        assert_eq!(mem::size_of::<usize>(), mem::size_of::<ULONG_PTR>());
    }

    #[test]
    fn timeout() {
        let c = CompletionPort::new(1).unwrap();
        let err = c.get(Some(1)).unwrap_err();
        assert_eq!(err.raw_os_error(), Some(WAIT_TIMEOUT as i32));
    }

    #[test]
    fn get() {
        let c = CompletionPort::new(1).unwrap();
        c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap();
        let s = c.get(None).unwrap();
        assert_eq!(s.bytes_transferred(), 1);
        assert_eq!(s.token(), 2);
        assert_eq!(s.overlapped(), 3 as *mut _);
    }

    #[test]
    fn get_many() {
        let c = CompletionPort::new(1).unwrap();

        c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap();
        c.post(CompletionStatus::new(4, 5, 6 as *mut _)).unwrap();

        let mut s = vec![CompletionStatus::zero(); 4];
        {
            let s = c.get_many(&mut s, None).unwrap();
            assert_eq!(s.len(), 2);
            assert_eq!(s[0].bytes_transferred(), 1);
            assert_eq!(s[0].token(), 2);
            assert_eq!(s[0].overlapped(), 3 as *mut _);
            assert_eq!(s[1].bytes_transferred(), 4);
            assert_eq!(s[1].token(), 5);
            assert_eq!(s[1].overlapped(), 6 as *mut _);
        }
        assert_eq!(s[2].bytes_transferred(), 0);
        assert_eq!(s[2].token(), 0);
        assert_eq!(s[2].overlapped(), 0 as *mut _);
    }
}
<commit_msg>Take a Duration instead of u32 ms<commit_after>//! Bindings to IOCP, I/O Completion Ports

use std::cmp;
use std::io;
use std::mem;
use std::os::windows::io::*;
use std::time::Duration;

use handle::Handle;
use winapi::*;
use kernel32::*;
use Overlapped;

/// A handle to an Windows I/O Completion Port.
#[derive(Debug)]
pub struct CompletionPort {
    handle: Handle,
}

/// A status message received from an I/O completion port.
///
/// These statuses can be created via the `new` or `empty` constructors and then
/// provided to a completion port, or they are read out of a completion port.
/// The fields of each status are read through its accessor methods.
#[derive(Clone, Copy, Debug)]
pub struct CompletionStatus(OVERLAPPED_ENTRY);

unsafe impl Send for CompletionStatus {}
unsafe impl Sync for CompletionStatus {}

impl CompletionPort {
    /// Creates a new I/O completion port with the specified concurrency value.
    ///
    /// The number of threads given corresponds to the level of concurrency
    /// allowed for threads associated with this port. Consult the Windows
    /// documentation for more information about this value.
    pub fn new(threads: u32) -> io::Result<CompletionPort> {
        let ret = unsafe {
            CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0 as *mut _,
                                   0, threads)
        };
        if ret.is_null() {
            Err(io::Error::last_os_error())
        } else {
            Ok(CompletionPort { handle: Handle::new(ret) })
        }
    }

    /// Associates a new `HANDLE` to this I/O completion port.
    ///
    /// This function will associate the given handle to this port with the
    /// given `token` to be returned in status messages whenever it receives a
    /// notification.
    ///
    /// Any object which is convertible to a `HANDLE` via the `AsRawHandle`
    /// trait can be provided to this function, such as `std::fs::File` and
    /// friends.
    pub fn add_handle<T: AsRawHandle + ?Sized>(&self, token: usize,
                                               t: &T) -> io::Result<()> {
        self._add(token, t.as_raw_handle())
    }

    /// Associates a new `SOCKET` to this I/O completion port.
    ///
    /// This function will associate the given socket to this port with the
    /// given `token` to be returned in status messages whenever it receives a
    /// notification.
    ///
    /// Any object which is convertible to a `SOCKET` via the `AsRawSocket`
    /// trait can be provided to this function, such as `std::net::TcpStream`
    /// and friends.
    pub fn add_socket<T: AsRawSocket + ?Sized>(&self, token: usize,
                                               t: &T) -> io::Result<()> {
        self._add(token, t.as_raw_socket() as HANDLE)
    }

    fn _add(&self, token: usize, handle: HANDLE) -> io::Result<()> {
        assert_eq!(mem::size_of_val(&token), mem::size_of::<ULONG_PTR>());
        let ret = unsafe {
            CreateIoCompletionPort(handle, self.handle.raw(),
                                   token as ULONG_PTR, 0)
        };
        if ret.is_null() {
            Err(io::Error::last_os_error())
        } else {
            debug_assert_eq!(ret, self.handle.raw());
            Ok(())
        }
    }

    /// Dequeue a completion status from this I/O completion port.
    ///
    /// This function will associate the calling thread with this completion
    /// port and then wait for a status message to become available. The precise
    /// semantics on when this function returns depends on the concurrency value
    /// specified when the port was created.
    ///
    /// A timeout can optionally be specified to this function. If `None` is
    /// provided this function will not time out, and otherwise it will time out
    /// after the specified duration has passed.
    ///
    /// On success this will return the status message which was dequeued from
    /// this completion port.
    pub fn get(&self, timeout: Option<Duration>) -> io::Result<CompletionStatus> {
        let mut bytes = 0;
        let mut token = 0;
        let mut overlapped = 0 as *mut _;
        let timeout = dur2ms(timeout);
        let ret = unsafe {
            GetQueuedCompletionStatus(self.handle.raw(),
                                      &mut bytes,
                                      &mut token,
                                      &mut overlapped,
                                      timeout)
        };
        ::cvt(ret).map(|_| {
            CompletionStatus(OVERLAPPED_ENTRY {
                dwNumberOfBytesTransferred: bytes,
                lpCompletionKey: token,
                lpOverlapped: overlapped,
                Internal: 0,
            })
        })
    }

    /// Dequeues a number of completion statuses from this I/O completion port.
    ///
    /// This function is the same as `get` except that it may return more than
    /// one status. A buffer of "zero" statuses is provided (the contents are
    /// not read) and then on success this function will return a sub-slice of
    /// statuses which represent those which were dequeued from this port. This
    /// function does not wait to fill up the entire list of statuses provided.
    ///
    /// Like with `get`, a timeout may be specified for this operation.
    pub fn get_many<'a>(&self,
                        list: &'a mut [CompletionStatus],
                        timeout: Option<Duration>)
                        -> io::Result<&'a mut [CompletionStatus]>
    {
        debug_assert_eq!(mem::size_of::<CompletionStatus>(),
                         mem::size_of::<OVERLAPPED_ENTRY>());
        let mut removed = 0;
        let timeout = dur2ms(timeout);
        let len = cmp::min(list.len(), <ULONG>::max_value() as usize) as ULONG;
        let ret = unsafe {
            GetQueuedCompletionStatusEx(self.handle.raw(),
                                        list.as_ptr() as *mut _,
                                        len,
                                        &mut removed,
                                        timeout,
                                        FALSE)
        };
        match ::cvt(ret) {
            Ok(_) => Ok(&mut list[..removed as usize]),
            Err(e) => Err(e),
        }
    }

    /// Posts a new completion status onto this I/O completion port.
    ///
    /// This function will post the given status, with custom parameters, to the
    /// port. Threads blocked in `get` or `get_many` will eventually receive
    /// this status.
    pub fn post(&self, status: CompletionStatus) -> io::Result<()> {
        let ret = unsafe {
            PostQueuedCompletionStatus(self.handle.raw(),
                                       status.0.dwNumberOfBytesTransferred,
                                       status.0.lpCompletionKey,
                                       status.0.lpOverlapped)
        };
        ::cvt(ret).map(|_| ())
    }
}

fn dur2ms(dur: Option<Duration>) -> u32 {
    let dur = match dur {
        Some(dur) => dur,
        None => return INFINITE,
    };
    let ms = dur.as_secs().checked_mul(1_000);
    let ms_extra = dur.subsec_nanos() / 1_000_000;
    ms.and_then(|ms| {
        ms.checked_add(ms_extra as u64)
    }).map(|ms| {
        cmp::min(u32::max_value() as u64, ms) as u32
    }).unwrap_or(INFINITE - 1)
}

impl AsRawHandle for CompletionPort {
    fn as_raw_handle(&self) -> HANDLE {
        self.handle.raw()
    }
}

impl FromRawHandle for CompletionPort {
    unsafe fn from_raw_handle(handle: HANDLE) -> CompletionPort {
        CompletionPort { handle: Handle::new(handle) }
    }
}

impl IntoRawHandle for CompletionPort {
    fn into_raw_handle(self) -> HANDLE {
        self.handle.into_raw()
    }
}

impl CompletionStatus {
    /// Creates a new completion status with the provided parameters.
    ///
    /// This function is useful when creating a status to send to a port with
    /// the `post` method. The parameters are opaquely passed through and not
    /// interpreted by the system at all.
    pub fn new(bytes: u32, token: usize, overlapped: *mut Overlapped)
               -> CompletionStatus {
        assert_eq!(mem::size_of_val(&token), mem::size_of::<ULONG_PTR>());
        CompletionStatus(OVERLAPPED_ENTRY {
            dwNumberOfBytesTransferred: bytes,
            lpCompletionKey: token as ULONG_PTR,
            lpOverlapped: overlapped as *mut _,
            Internal: 0,
        })
    }

    /// Creates a new borrowed completion status from the borrowed
    /// `OVERLAPPED_ENTRY` argument provided.
    ///
    /// This method will wrap the `OVERLAPPED_ENTRY` in a `CompletionStatus`,
    /// returning the wrapped structure.
    pub fn from_entry(entry: &OVERLAPPED_ENTRY) -> &CompletionStatus {
        unsafe { &*(entry as *const _ as *const _) }
    }

    /// Creates a new "zero" completion status.
    ///
    /// This function is useful when creating a stack buffer or vector of
    /// completion statuses to be passed to the `get_many` function.
    pub fn zero() -> CompletionStatus {
        CompletionStatus::new(0, 0, 0 as *mut _)
    }

    /// Returns the number of bytes that were transferred for the I/O operation
    /// associated with this completion status.
    pub fn bytes_transferred(&self) -> u32 {
        self.0.dwNumberOfBytesTransferred
    }

    /// Returns the completion key value associated with the file handle whose
    /// I/O operation has completed.
    ///
    /// A completion key is a per-handle key that is specified when it is added
    /// to an I/O completion port via `add_handle` or `add_socket`.
    pub fn token(&self) -> usize {
        self.0.lpCompletionKey as usize
    }

    /// Returns a pointer to the `Overlapped` structure that was specified when
    /// the I/O operation was started.
    pub fn overlapped(&self) -> *mut Overlapped {
        self.0.lpOverlapped as *mut _
    }

    /// Returns a pointer to the internal `OVERLAPPED_ENTRY` object.
    pub fn entry(&self) -> &OVERLAPPED_ENTRY {
        &self.0
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use winapi::*;

    use iocp::{CompletionPort, CompletionStatus};

    #[test]
    fn is_send_sync() {
        fn is_send_sync<T: Send + Sync>() {}
        is_send_sync::<CompletionPort>();
    }

    #[test]
    fn token_right_size() {
        assert_eq!(mem::size_of::<usize>(), mem::size_of::<ULONG_PTR>());
    }

    #[test]
    fn timeout() {
        let c = CompletionPort::new(1).unwrap();
        let err = c.get(Some(1)).unwrap_err();
        assert_eq!(err.raw_os_error(), Some(WAIT_TIMEOUT as i32));
    }

    #[test]
    fn get() {
        let c = CompletionPort::new(1).unwrap();
        c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap();
        let s = c.get(None).unwrap();
        assert_eq!(s.bytes_transferred(), 1);
        assert_eq!(s.token(), 2);
        assert_eq!(s.overlapped(), 3 as *mut _);
    }

    #[test]
    fn get_many() {
        let c = CompletionPort::new(1).unwrap();

        c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap();
        c.post(CompletionStatus::new(4, 5, 6 as *mut _)).unwrap();

        let mut s = vec![CompletionStatus::zero(); 4];
        {
            let s = c.get_many(&mut s, None).unwrap();
            assert_eq!(s.len(), 2);
            assert_eq!(s[0].bytes_transferred(), 1);
            assert_eq!(s[0].token(), 2);
            assert_eq!(s[0].overlapped(), 3 as *mut _);
            assert_eq!(s[1].bytes_transferred(), 4);
            assert_eq!(s[1].token(), 5);
            assert_eq!(s[1].overlapped(), 6 as *mut _);
        }
        assert_eq!(s[2].bytes_transferred(), 0);
        assert_eq!(s[2].token(), 0);
        assert_eq!(s[2].overlapped(), 0 as *mut _);
    }
}
<|endoftext|>