<commit_before>#![allow(dead_code)]

use std::collections::VecDeque;
use std::iter::FromIterator;

use lexicon::Lexicon;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Orientation {
    Across,
    Down
}

impl Orientation {
    pub fn reverse(&self) -> Self {
        match *self {
            Orientation::Across => Orientation::Down,
            Orientation::Down => Orientation::Across
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Locale {
    row: usize,
    col: usize
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct WordspanAddress {
    start_row: usize,
    start_col: usize,
    orientation: Orientation,
    length: usize
}

impl WordspanAddress {
    pub fn new(start_row: usize, start_col: usize,
               orientation: Orientation, length: usize) -> Self {
        WordspanAddress {
            start_row: start_row,
            start_col: start_col,
            orientation: orientation,
            length: length
        }
    }

    pub fn oriented_new(start_this: usize, start_cross: usize,
                        orientation: Orientation, length: usize) -> Self {
        match orientation {
            Orientation::Across => WordspanAddress::new(
                start_this, start_cross, orientation, length),
            Orientation::Down => WordspanAddress::new(
                start_cross, start_this, orientation, length)
        }
    }

    pub fn encompassed_locales(&self) -> Vec<Locale> {
        (0..self.length).map(|offset| {
            match self.orientation {
                Orientation::Across => Locale {
                    row: self.start_row,
                    col: self.start_col + offset
                },
                Orientation::Down => Locale {
                    row: self.start_row + offset,
                    col: self.start_col
                }
            }
        }).collect()
    }
}

pub const BARRIER: char = '█';

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CrossRequirement {
    length: usize,
    prefix: Vec<char>
}

impl CrossRequirement {
    pub fn new(length: usize, prefix: Vec<char>) -> Self {
        CrossRequirement {
            length: length,
            prefix: prefix,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Puzzle {
    rows: usize,
    cols: usize,
    backing: Vec<char>
}

impl Puzzle {
    pub fn read(&self, row_index: usize, col_index: usize) -> char {
        self.backing[self.cols*row_index + col_index]
    }

    pub fn oriented_read(&self, orientation: Orientation,
                         this: usize, cross: usize) -> char {
        match orientation {
            Orientation::Across => self.read(this, cross),
            Orientation::Down => self.read(cross, this)
        }
    }

    pub fn write(&mut self, row_index: usize, col_index: usize,
                 letter: char) {
        self.backing[self.cols*row_index + col_index] = letter;
    }

    // XXX: returning a Vec<_> implies an allocation, but we can't return a
    // slice because the Down case isn't contiguous. Can we return a
    // Cow<[char]>? Profile and decide later
    pub fn read_wordspan(&self, address: WordspanAddress) -> Vec<char> {
        let start_square = self.cols*address.start_row + address.start_col;
        match address.orientation {
            Orientation::Across => {
                self.backing[start_square..start_square+address.length].to_vec()
            },
            Orientation::Down => {
                (0..address.length).map(|r| {
                    self.backing[start_square + self.cols*r]
                }).collect()
            }
        }
    }

    pub fn write_wordspan(&mut self, address: WordspanAddress, word: Vec<char>) {
        let start_square = self.cols*address.start_row + address.start_col;
        let mut offset = 0;
        for character in word {
            self.backing[start_square + offset] = character;
            offset += match address.orientation {
                Orientation::Across => 1,
                Orientation::Down => self.cols
            }
        }
    }

    pub fn oriented_wordspan_addresses(&self, orientation: Orientation)
                                       -> Vec<WordspanAddress> {
        let mut addresses = Vec::new();
        let (this_dimension, cross_dimension) = match orientation {
            Orientation::Across => (self.rows, self.cols),
            Orientation::Down => (self.cols, self.rows)
        };
        for beam in 0..this_dimension {
            let mut open_word_from: Option<usize> = None;
            for crossbeam in 0..cross_dimension {
                match open_word_from {
                    None => {
                        if self.oriented_read(orientation,
                                              beam, crossbeam) == BARRIER {
                            continue;
                        } else {
                            open_word_from = Some(crossbeam);
                        }
                    },
                    Some(open_from) => {
                        if self.oriented_read(orientation,
                                              beam, crossbeam) == BARRIER {
                            let address = WordspanAddress::oriented_new(
                                beam, open_from, orientation,
                                crossbeam-open_from
                            );
                            addresses.push(address);
                            open_word_from = None;
                        } else {
                            continue;
                        }
                    }
                }
            }
            // close off word closed by edge of puzzle rather than barrier
            if let Some(open_from) = open_word_from {
                let address = WordspanAddress::oriented_new(
                    beam, open_from, orientation,
                    cross_dimension-open_from
                );
                addresses.push(address);
            }
        }
        addresses
    }

    pub fn wordspan_addresses(&self) -> Vec<WordspanAddress> {
        let mut addresses = self.oriented_wordspan_addresses(Orientation::Across);
        addresses.extend(self.oriented_wordspan_addresses(Orientation::Down));
        addresses
    }

    pub fn is_solved(&self, lexicon: &Lexicon) -> bool {
        for address in self.wordspan_addresses() {
            let word = self.read_wordspan(address);
            if !lexicon.contains(&word) {
                return false;
            }
        }
        true
    }

    pub fn gather_cross_requirements(&self, address: WordspanAddress)
                                     -> Vec<CrossRequirement> {
        let mut cross_requirements = Vec::new();
        let mut our_locales = VecDeque::from_iter(
            address.encompassed_locales().into_iter());
        for cross_address in self.oriented_wordspan_addresses(
                address.orientation.reverse()) {
            if cross_address.encompassed_locales().contains(&our_locales[0]) {
                our_locales.pop_front();
                let requirement = CrossRequirement {
                    length: cross_address.length,
                    prefix: self.read_wordspan(cross_address).into_iter()
                        .take_while(|c| *c != ' ').collect()
                };
                cross_requirements.push(requirement);
            }
        }
        cross_requirements
    }

    pub fn is_full(&self) -> bool {
        self.backing.iter().all(|c| *c != ' ')
    }
}

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

    fn test_puzzle_i() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 5,
            backing: vec![
                'W', 'R', 'I', 'T', 'E',
                'A', 'A', 'R', 'O', 'N',
                'G', 'I', 'A', 'N', 'T',
                'E', 'S', 'T', 'E', 'R',
                'R', 'E', 'E', 'D', 'Y',
            ]
        }
    }

    fn test_puzzle_ii() -> Puzzle {
        Puzzle {
            rows: 7,
            cols: 11,
            backing: vec![
                'S', 'W', 'I', 'F', 'T', '█', 'S', 'T', 'A', 'C', 'K',
                'L', 'A', 'M', 'A', 'S', '█', 'L', 'A', 'M', 'A', 'R',
                'A', 'L', 'A', 'N', '█', 'L', 'E', 'G', 'A', 'T', 'O',
                'B', 'E', 'G', '█', 'L', 'A', 'D', '█', 'D', 'E', 'C',
                '█', 'S', 'E', 'L', 'I', 'M', '█', 'F', 'E', 'R', '█',
                '█', 'A', 'R', 'E', 'S', '█', 'P', 'I', 'U', 'S', '█',
                '█', '█', 'Y', 'I', 'P', '█', 'L', 'E', 'S', '█', '█',
            ]
        }
    }

    fn test_puzzle_iii() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 4,
            backing: vec![
                'Q', 'U', 'I', 'Z',
                'U', 'N', 'D', 'O',
                'A', 'I', 'L', 'S',
                ' ', ' ', ' ', ' ', // ITEM
                ' ', ' ', ' ', ' ', // LEDA (in case you were wondering)
            ],
        }
    }

    #[test]
    fn concerning_read_wordspan_across() {
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        assert_eq!(test_puzzle_i().read_wordspan(write_address),
                   charvec![WRITE]);
    }

    #[test]
    fn concerning_read_wordspan_down() {
        let raise_address = WordspanAddress::new(0, 1, Orientation::Down, 5);
        assert_eq!(test_puzzle_i().read_wordspan(raise_address),
                   charvec![RAISE]);
    }

    #[test]
    fn concerning_write_wordspan_across() {
        let mut puzzle = test_puzzle_i();
        // in more ways than one
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        puzzle.write_wordspan(write_address, charvec![PLATE]);
        assert_eq!(puzzle.read_wordspan(write_address),
                   charvec![PLATE]);
    }

    #[test]
    fn concerning_write_wordspan_down() {
        let mut puzzle = test_puzzle_i();
        let entry_address = WordspanAddress::new(0, 4, Orientation::Down, 5);
        puzzle.write_wordspan(entry_address, charvec![FAITH]);
        assert_eq!(puzzle.read_wordspan(entry_address),
                   charvec![FAITH]);
    }

    #[test]
    fn concerning_wordspan_addresses_across() {
        let puzzle = test_puzzle_ii();
        assert_eq!(
            &[WordspanAddress::new(0, 0, Orientation::Across, 5),
              WordspanAddress::new(0, 6, Orientation::Across, 5),
              WordspanAddress::new(1, 0, Orientation::Across, 5),
              WordspanAddress::new(1, 6, Orientation::Across, 5),
              WordspanAddress::new(2, 0, Orientation::Across, 4),
              WordspanAddress::new(2, 5, Orientation::Across, 6)],
            &puzzle.oriented_wordspan_addresses(Orientation::Across)[..6]
        );
    }

    #[test]
    fn concerning_wordspan_addresses_down() {
        let puzzle = test_puzzle_ii();
        assert_eq!(
            &[WordspanAddress::new(0, 0, Orientation::Down, 4),
              WordspanAddress::new(0, 1, Orientation::Down, 6),
              WordspanAddress::new(0, 2, Orientation::Down, 7),
              WordspanAddress::new(0, 3, Orientation::Down, 3),
              WordspanAddress::new(4, 3, Orientation::Down, 3),
              WordspanAddress::new(0, 4, Orientation::Down, 2)],
            &puzzle.oriented_wordspan_addresses(Orientation::Down)[..6]
        );
    }

    #[test]
    fn concerning_is_solved() {
        let lexicon = Lexicon::build(7);
        let puzzles = vec![test_puzzle_i(), test_puzzle_ii()];
        for mut puzzle in puzzles {
            assert!(puzzle.is_solved(&lexicon));
            puzzle.write(0, 0, 'Q');
            assert!(!puzzle.is_solved(&lexicon));
        }
    }

    #[test]
    fn concerning_gathering_cross_requirements() {
        assert_eq!(
            vec![CrossRequirement::new(5, charvec![QUA]),
                 CrossRequirement::new(5, charvec![UNI]),
                 CrossRequirement::new(5, charvec![IDL]),
                 CrossRequirement::new(5, charvec![ZOS])],
            test_puzzle_iii()
                .gather_cross_requirements(
                    WordspanAddress::new(3, 0, Orientation::Across, 4))
        );
    }

    #[test]
    fn concerning_is_full() {
        assert!(test_puzzle_i().is_full());
        assert!(test_puzzle_ii().is_full());
        assert!(!test_puzzle_iii().is_full());
    }
}
<commit_msg>greedy blank look across the horizon towards a solution<commit_after>#![allow(dead_code)]

use std::collections::VecDeque;
use std::iter::FromIterator;

use lexicon::Lexicon;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Orientation {
    Across,
    Down
}

impl Orientation {
    pub fn reverse(&self) -> Self {
        match *self {
            Orientation::Across => Orientation::Down,
            Orientation::Down => Orientation::Across
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Locale {
    row: usize,
    col: usize
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct WordspanAddress {
    start_row: usize,
    start_col: usize,
    orientation: Orientation,
    length: usize
}

impl WordspanAddress {
    pub fn new(start_row: usize, start_col: usize,
               orientation: Orientation, length: usize) -> Self {
        WordspanAddress {
            start_row: start_row,
            start_col: start_col,
            orientation: orientation,
            length: length
        }
    }

    pub fn oriented_new(start_this: usize, start_cross: usize,
                        orientation: Orientation, length: usize) -> Self {
        match orientation {
            Orientation::Across => WordspanAddress::new(
                start_this, start_cross, orientation, length),
            Orientation::Down => WordspanAddress::new(
                start_cross, start_this, orientation, length)
        }
    }

    pub fn encompassed_locales(&self) -> Vec<Locale> {
        (0..self.length).map(|offset| {
            match self.orientation {
                Orientation::Across => Locale {
                    row: self.start_row,
                    col: self.start_col + offset
                },
                Orientation::Down => Locale {
                    row: self.start_row + offset,
                    col: self.start_col
                }
            }
        }).collect()
    }
}

pub const BARRIER: char = '█';

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CrossRequirement {
    length: usize,
    prefix: Vec<char>
}

impl CrossRequirement {
    pub fn new(length: usize, prefix: Vec<char>) -> Self {
        CrossRequirement {
            length: length,
            prefix: prefix,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Puzzle {
    rows: usize,
    cols: usize,
    backing: Vec<char>
}

impl Puzzle {
    pub fn read(&self, row_index: usize, col_index: usize) -> char {
        self.backing[self.cols*row_index + col_index]
    }

    pub fn oriented_read(&self, orientation: Orientation,
                         this: usize, cross: usize) -> char {
        match orientation {
            Orientation::Across => self.read(this, cross),
            Orientation::Down => self.read(cross, this)
        }
    }

    pub fn write(&mut self, row_index: usize, col_index: usize,
                 letter: char) {
        self.backing[self.cols*row_index + col_index] = letter;
    }

    // XXX: returning a Vec<_> implies an allocation, but we can't return a
    // slice because the Down case isn't contiguous. Can we return a
    // Cow<[char]>? Profile and decide later
    pub fn read_wordspan(&self, address: WordspanAddress) -> Vec<char> {
        let start_square = self.cols*address.start_row + address.start_col;
        match address.orientation {
            Orientation::Across => {
                self.backing[start_square..start_square+address.length].to_vec()
            },
            Orientation::Down => {
                (0..address.length).map(|r| {
                    self.backing[start_square + self.cols*r]
                }).collect()
            }
        }
    }

    pub fn write_wordspan(&mut self, address: WordspanAddress, word: Vec<char>) {
        let start_square = self.cols*address.start_row + address.start_col;
        let mut offset = 0;
        for character in word {
            self.backing[start_square + offset] = character;
            offset += match address.orientation {
                Orientation::Across => 1,
                Orientation::Down => self.cols
            }
        }
    }

    pub fn oriented_wordspan_addresses(&self, orientation: Orientation)
                                       -> Vec<WordspanAddress> {
        let mut addresses = Vec::new();
        let (this_dimension, cross_dimension) = match orientation {
            Orientation::Across => (self.rows, self.cols),
            Orientation::Down => (self.cols, self.rows)
        };
        for beam in 0..this_dimension {
            let mut open_word_from: Option<usize> = None;
            for crossbeam in 0..cross_dimension {
                match open_word_from {
                    None => {
                        if self.oriented_read(orientation,
                                              beam, crossbeam) == BARRIER {
                            continue;
                        } else {
                            open_word_from = Some(crossbeam);
                        }
                    },
                    Some(open_from) => {
                        if self.oriented_read(orientation,
                                              beam, crossbeam) == BARRIER {
                            let address = WordspanAddress::oriented_new(
                                beam, open_from, orientation,
                                crossbeam-open_from
                            );
                            addresses.push(address);
                            open_word_from = None;
                        } else {
                            continue;
                        }
                    }
                }
            }
            // close off word closed by edge of puzzle rather than barrier
            if let Some(open_from) = open_word_from {
                let address = WordspanAddress::oriented_new(
                    beam, open_from, orientation,
                    cross_dimension-open_from
                );
                addresses.push(address);
            }
        }
        addresses
    }

    pub fn wordspan_addresses(&self) -> Vec<WordspanAddress> {
        let mut addresses = self.oriented_wordspan_addresses(Orientation::Across);
        addresses.extend(self.oriented_wordspan_addresses(Orientation::Down));
        addresses
    }

    pub fn is_solved(&self, lexicon: &Lexicon) -> bool {
        for address in self.wordspan_addresses() {
            let word = self.read_wordspan(address);
            if !lexicon.contains(&word) {
                return false;
            }
        }
        true
    }

    pub fn gather_cross_requirements(&self, address: WordspanAddress)
                                     -> Vec<CrossRequirement> {
        let mut cross_requirements = Vec::new();
        let mut our_locales = VecDeque::from_iter(
            address.encompassed_locales().into_iter());
        for cross_address in self.oriented_wordspan_addresses(
                address.orientation.reverse()) {
            if cross_address.encompassed_locales().contains(&our_locales[0]) {
                our_locales.pop_front();
                let requirement = CrossRequirement {
                    length: cross_address.length,
                    prefix: self.read_wordspan(cross_address).into_iter()
                        .take_while(|c| *c != ' ').collect()
                };
                cross_requirements.push(requirement);
            }
        }
        cross_requirements
    }

    pub fn is_full(&self) -> bool {
        self.backing.iter().all(|c| *c != ' ')
    }

    fn first_blank_across_address(&self) -> Option<WordspanAddress> {
        self.oriented_wordspan_addresses(Orientation::Across).into_iter()
            .filter(|a| { self.read(a.start_row, a.start_col) == ' ' })
            .next()
    }

    pub fn solve(&mut self, lexicon: &Lexicon) -> bool {
        if self.is_full() && self.is_solved(lexicon) {
            return true
        }
        // TODO
        false
    }
}

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

    fn test_puzzle_i() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 5,
            backing: vec![
                'W', 'R', 'I', 'T', 'E',
                'A', 'A', 'R', 'O', 'N',
                'G', 'I', 'A', 'N', 'T',
                'E', 'S', 'T', 'E', 'R',
                'R', 'E', 'E', 'D', 'Y',
            ]
        }
    }

    fn test_puzzle_ii() -> Puzzle {
        Puzzle {
            rows: 7,
            cols: 11,
            backing: vec![
                'S', 'W', 'I', 'F', 'T', '█', 'S', 'T', 'A', 'C', 'K',
                'L', 'A', 'M', 'A', 'S', '█', 'L', 'A', 'M', 'A', 'R',
                'A', 'L', 'A', 'N', '█', 'L', 'E', 'G', 'A', 'T', 'O',
                'B', 'E', 'G', '█', 'L', 'A', 'D', '█', 'D', 'E', 'C',
                '█', 'S', 'E', 'L', 'I', 'M', '█', 'F', 'E', 'R', '█',
                '█', 'A', 'R', 'E', 'S', '█', 'P', 'I', 'U', 'S', '█',
                '█', '█', 'Y', 'I', 'P', '█', 'L', 'E', 'S', '█', '█',
            ]
        }
    }

    fn test_puzzle_iii() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 4,
            backing: vec![
                'Q', 'U', 'I', 'Z',
                'U', 'N', 'D', 'O',
                'A', 'I', 'L', 'S',
                ' ', ' ', ' ', ' ', // ITEM
                ' ', ' ', ' ', ' ', // LEDA (in case you were wondering)
            ],
        }
    }

    #[test]
    fn concerning_read_wordspan_across() {
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        assert_eq!(test_puzzle_i().read_wordspan(write_address),
                   charvec![WRITE]);
    }

    #[test]
    fn concerning_read_wordspan_down() {
        let raise_address = WordspanAddress::new(0, 1, Orientation::Down, 5);
        assert_eq!(test_puzzle_i().read_wordspan(raise_address),
                   charvec![RAISE]);
    }

    #[test]
    fn concerning_write_wordspan_across() {
        let mut puzzle = test_puzzle_i();
        // in more ways than one
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        puzzle.write_wordspan(write_address, charvec![PLATE]);
        assert_eq!(puzzle.read_wordspan(write_address),
                   charvec![PLATE]);
    }

    #[test]
    fn concerning_write_wordspan_down() {
        let mut puzzle = test_puzzle_i();
        let entry_address = WordspanAddress::new(0, 4, Orientation::Down, 5);
        puzzle.write_wordspan(entry_address, charvec![FAITH]);
        assert_eq!(puzzle.read_wordspan(entry_address),
                   charvec![FAITH]);
    }

    #[test]
    fn concerning_wordspan_addresses_across() {
        let puzzle = test_puzzle_ii();
        assert_eq!(
            &[WordspanAddress::new(0, 0, Orientation::Across, 5),
              WordspanAddress::new(0, 6, Orientation::Across, 5),
              WordspanAddress::new(1, 0, Orientation::Across, 5),
              WordspanAddress::new(1, 6, Orientation::Across, 5),
              WordspanAddress::new(2, 0, Orientation::Across, 4),
              WordspanAddress::new(2, 5, Orientation::Across, 6)],
            &puzzle.oriented_wordspan_addresses(Orientation::Across)[..6]
        );
    }

    #[test]
    fn concerning_wordspan_addresses_down() {
        let puzzle = test_puzzle_ii();
        assert_eq!(
            &[WordspanAddress::new(0, 0, Orientation::Down, 4),
              WordspanAddress::new(0, 1, Orientation::Down, 6),
              WordspanAddress::new(0, 2, Orientation::Down, 7),
              WordspanAddress::new(0, 3, Orientation::Down, 3),
              WordspanAddress::new(4, 3, Orientation::Down, 3),
              WordspanAddress::new(0, 4, Orientation::Down, 2)],
            &puzzle.oriented_wordspan_addresses(Orientation::Down)[..6]
        );
    }

    #[test]
    fn concerning_is_solved() {
        let lexicon = Lexicon::build(7);
        let puzzles = vec![test_puzzle_i(), test_puzzle_ii()];
        for mut puzzle in puzzles {
            assert!(puzzle.is_solved(&lexicon));
            puzzle.write(0, 0, 'Q');
            assert!(!puzzle.is_solved(&lexicon));
        }
    }

    #[test]
    fn concerning_gathering_cross_requirements() {
        assert_eq!(
            vec![CrossRequirement::new(5, charvec![QUA]),
                 CrossRequirement::new(5, charvec![UNI]),
                 CrossRequirement::new(5, charvec![IDL]),
                 CrossRequirement::new(5, charvec![ZOS])],
            test_puzzle_iii()
                .gather_cross_requirements(
                    WordspanAddress::new(3, 0, Orientation::Across, 4))
        );
    }

    #[test]
    fn concerning_is_full() {
        assert!(test_puzzle_i().is_full());
        assert!(test_puzzle_ii().is_full());
        assert!(!test_puzzle_iii().is_full());
    }

    #[test]
    fn concerning_first_blank_across_address() {
        assert_eq!(Some(WordspanAddress::new(3, 0, Orientation::Across, 4)),
                   test_puzzle_iii().first_blank_across_address())
    }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate rustc_serialize;
extern crate capngraph;
extern crate petgraph;

use std::io::{Write, BufWriter};
use std::fs::File;

use capngraph::load_graph;
use docopt::Docopt;
use petgraph::visit::EdgeRef;

const USAGE: &'static str = "
Convert the input packed binary graph to the academy-standard edge-list format.

Usage:
  deconvert <bin> <dest>
  convert (-h | --help)

Options:
  -h --help        Show this screen.
";

#[derive(RustcDecodable)]
struct Args {
    arg_bin: String,
    arg_dest: String
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let graph = load_graph(args.arg_bin.as_str()).unwrap();

    let output = File::create(args.arg_dest).unwrap();
    let mut writer = BufWriter::new(output);

    writeln!(writer, "{} {}", graph.node_count(), graph.edge_count()).unwrap();

    for edge in graph.edge_references() {
        writeln!(writer, "{} {} {}",
                 edge.source().index(),
                 edge.target().index(),
                 f32::from(*edge.weight()))
            .unwrap();
    }
}
<commit_msg>Fixed docstring for `deconvert` binary.<commit_after>extern crate docopt;
extern crate rustc_serialize;
extern crate capngraph;
extern crate petgraph;

use std::io::{Write, BufWriter};
use std::fs::File;

use capngraph::load_graph;
use docopt::Docopt;
use petgraph::visit::EdgeRef;

const USAGE: &'static str = "
Convert the input packed binary graph to the edge-list format.

Usage:
  deconvert <bin> <dest>
  deconvert (-h | --help)

Options:
  -h --help        Show this screen.
";

#[derive(RustcDecodable)]
struct Args {
    arg_bin: String,
    arg_dest: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let graph = load_graph(args.arg_bin.as_str()).unwrap();

    let output = File::create(args.arg_dest).unwrap();
    let mut writer = BufWriter::new(output);

    writeln!(writer, "{} {}", graph.node_count(), graph.edge_count()).unwrap();

    for edge in graph.edge_references() {
        writeln!(writer,
                 "{} {} {}",
                 edge.source().index(),
                 edge.target().index(),
                 f32::from(*edge.weight()))
            .unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate log;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimir;
extern crate rs_es;

use std::collections::HashSet;
use std::collections::HashMap;
use mimirsbrunn::rubber::Rubber;
use mimirsbrunn::objects::{Polygon, MultiPolygon};

pub type AdminsVec = Vec<mimir::Admin>;
pub type StreetsVec = Vec<mimir::Street>;
pub type ParsedPbf = osmpbfreader::OsmPbfReader<std::fs::File>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level>...

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

#[derive(Debug)]
struct AdminMatcher {
    admin_levels: HashSet<u32>,
}
impl AdminMatcher {
    pub fn new(levels: HashSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("boundary").map_or(false, |v| v == "administrative") &&
                rel.tags.get("admin_level").map_or(false, |lvl| {
                    self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                })
            }
            _ => false,
        }
    }
}

struct BoundaryPart {
    nodes: Vec<osmpbfreader::Node>,
}

impl BoundaryPart {
    pub fn new(nodes: Vec<osmpbfreader::Node>) -> BoundaryPart {
        BoundaryPart { nodes: nodes }
    }
    pub fn first(&self) -> i64 {
        self.nodes.first().unwrap().id
    }
    pub fn last(&self) -> i64 {
        self.nodes.last().unwrap().id
    }
}

fn get_nodes(way: &osmpbfreader::Way,
             objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
             -> Vec<osmpbfreader::Node> {
    way.nodes
       .iter()
       .filter_map(|node_id| objects.get(&osmpbfreader::OsmId::Node(*node_id)))
       .filter_map(|node_obj| if let &osmpbfreader::OsmObj::Node(ref node) = node_obj {
           Some(node.clone())
       } else {
           None
       })
       .collect()
}

fn build_boundary(relation: &osmpbfreader::Relation,
                  objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
                  -> Option<MultiPolygon> {
    let mut boundary_parts: Vec<BoundaryPart> =
        relation.refs
                .iter()
                .filter(|rf| rf.role == "outer" || rf.role == "" || rf.role == "enclave")
                .filter_map(|refe| {
                    objects.get(&refe.member).or_else(|| {
                        warn!("missing element for relation {}", relation.id);
                        None
                    })
                })
                .filter_map(|way_obj| if let &osmpbfreader::OsmObj::Way(ref way) = way_obj {
                    Some(way)
                } else {
                    None
                })
                .map(|way| get_nodes(&way, objects))
                .filter(|nodes| nodes.len() > 1)
                .map(|nodes| BoundaryPart::new(nodes))
                .collect();
    let mut multipoly = MultiPolygon { polygons: Vec::new() };
    // we want to try build a polygon for a least each way
    while !boundary_parts.is_empty() {
        let mut current = -1;
        let mut first = 0;
        let mut nb_try = 0;

        let mut outer: Vec<osmpbfreader::Node> = Vec::new();
        // we try to close the polygon, if we can't we want to at least have tried one time per
        // way. We could improve that latter by trying to attach the way to both side of the
        // polygon
        let max_try = boundary_parts.len();
        while current != first && nb_try < max_try {
            let mut i = 0;
            while i < boundary_parts.len() {
                if outer.is_empty() {
                    // our polygon is empty, we initialise it with the current way
                    first = boundary_parts[i].first();
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    // this way has been used, we remove it from the pool
                    boundary_parts.remove(i);
                    continue;
                }
                if current == boundary_parts[i].first() {
                    // the start of current way touch the polygon, we add it and remove it from the
                    // pool
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else if current == boundary_parts[i].last() {
                    // the end of the current way touch the polygon, we reverse the way and add it
                    current = boundary_parts[i].first();
                    boundary_parts[i].nodes.reverse();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else {
                    i += 1;
                    // didnt do anything, we want to explore the next way, if we had do something we
                    // will have removed the current way and there will be no need to increment
                }
                if current == first {
                    // our polygon is closed, we create it and add it to the multipolygon
                    let polygon = Polygon::new(outer.iter()
                                                    .map(|n| {
                                                        mimir::Coord {
                                                            lat: n.lat,
                                                            lon: n.lon,
                                                        }
                                                    })
                                                    .collect());
                    multipoly.polygons.push(polygon);
                    break;
                }
            }
            nb_try += 1;
        }
    }
    debug!("polygon for relation {};{}", relation.id, multipoly.to_wkt());
    if multipoly.polygons.is_empty() {
        None
    } else {
        Some(multipoly)
    }
}

fn parse_osm_pbf(path: &String) -> ParsedPbf {
    let path = std::path::Path::new(&path);
    match std::fs::File::open(&path) {
        Err(e) => panic!("failed to parse file {:?} because: {}", &path, e),
        Ok(r) => osmpbfreader::OsmPbfReader::new(r)
    }
}

fn administrative_regions(pbf: &mut ParsedPbf, levels: HashSet<u32>) -> AdminsVec {
    let mut administrative_regions = AdminsVec::new();
    let matcher = AdminMatcher::new(levels);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_admin(o)).unwrap();
    // load administratives regions
    for (_, obj) in &objects {
        if !matcher.is_admin(&obj) {
            continue;
        }
        if let &osmpbfreader::OsmObj::Relation(ref relation) = obj {
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            // admininstrative region without coordinates
            let coord_centre = relation.refs
                                       .iter()
                                       .find(|rf| rf.role == "admin_centre")
                                       .and_then(|r| {
                                           objects.get(&r.member).and_then(|value| {
                                               match value {
                                                   &osmpbfreader::OsmObj::Node(ref node) => {
                                                       Some(mimir::Coord {
                                                           lat: node.lat,
                                                           lon: node.lon,
                                                       })
                                                   }
                                                   _ => None,
                                               }
                                           })
                                       });

            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val.trim_left_matches('0')),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let boundary = build_boundary(&relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: coord_centre,
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    return administrative_regions;
}

fn streets(pbf: &mut ParsedPbf) -> StreetsVec {

    let is_valid_street = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Way(ref way) => {
                way.tags.get("highway").map_or(false, |x: &String| !x.is_empty()) &&
                way.tags.get("name").map_or(false, |x: &String| !x.is_empty())
            }
            _ => false,
        }
    };

    let mut streets = StreetsVec::new();

    if let Result::Ok(ref objects) = osmpbfreader::get_objs_and_deps(pbf, is_valid_street) {
        for (osm_id, obj) in objects {
            if let &osmpbfreader::OsmObj::Way(ref way) = obj {
                if let &osmpbfreader::OsmId::Way(ref way_id) = osm_id {
                    if let Some(ref way_name) = way.tags.get("name") {
                        let street = mimirsbrunn::Street {
                            id: way_id.to_string(),
                            street_name: way_name.to_string(),
                            name: way_name.to_string(),
                            weight: 1,
                            administrative_region: None,
                        };
                        streets.push(street);
                    };
                };
            };
        }
    };

    streets
}

fn index_osm(es_cnx_string: &str, admins: &AdminsVec, streets: &StreetsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    rubber.create_index();
    match rubber.clean_db_by_doc_type(&["admin", "street"]) {
        Err(e) => panic!("failed to clean data by document type: {}", e),
        Ok(nb) => info!("clean data by document type : {}", nb),
    }
    info!("Add data in elasticsearch db.");
    match rubber.bulk_index(admins.iter()) {
       Err(e) => panic!("failed to index admins of osm because: {}", e),
       Ok(nb) => info!("Nb of indexed adminstrative regions: {}", nb),
    }

    match rubber.bulk_index(streets.iter()) {
       Err(e) => panic!("failed to index streets of osm because: {}", e),
       Ok(nb) => info!("Nb of indexed streets: {}", nb),
    }
}

fn main() {
    mimir::logger_init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());

    let levels = args.flag_level.iter().cloned().collect();
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);
    let admins = administrative_regions(&mut parsed_pbf, levels);
    let streets = streets(&mut parsed_pbf);
    index_osm(&args.flag_connection_string, &admins, &streets);
}
<commit_msg>fix after code reveiw<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate log;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimir;
extern crate rs_es;

use std::collections::HashSet;
use std::collections::HashMap;
use mimirsbrunn::rubber::Rubber;
use mimirsbrunn::objects::{Polygon, MultiPolygon};

pub type AdminsVec = Vec<mimir::Admin>;
pub type StreetsVec = Vec<mimir::Street>;
pub type ParsedPbf = osmpbfreader::OsmPbfReader<std::fs::File>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level>...

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

#[derive(Debug)]
struct AdminMatcher {
    admin_levels: HashSet<u32>,
}
impl AdminMatcher {
    pub fn new(levels: HashSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("boundary").map_or(false, |v| v == "administrative") &&
                rel.tags.get("admin_level").map_or(false, |lvl| {
                    self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                })
            }
            _ => false,
        }
    }
}

struct BoundaryPart {
    nodes: Vec<osmpbfreader::Node>,
}

impl BoundaryPart {
    pub fn new(nodes: Vec<osmpbfreader::Node>) -> BoundaryPart {
        BoundaryPart { nodes: nodes }
    }
    pub fn first(&self) -> i64 {
        self.nodes.first().unwrap().id
    }
    pub fn last(&self) -> i64 {
        self.nodes.last().unwrap().id
    }
}

fn get_nodes(way: &osmpbfreader::Way,
             objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
             -> Vec<osmpbfreader::Node> {
    way.nodes
       .iter()
       .filter_map(|node_id| objects.get(&osmpbfreader::OsmId::Node(*node_id)))
       .filter_map(|node_obj| if let &osmpbfreader::OsmObj::Node(ref node) = node_obj {
           Some(node.clone())
       } else {
           None
       })
       .collect()
}

fn build_boundary(relation: &osmpbfreader::Relation,
                  objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
                  -> Option<MultiPolygon> {
    let mut boundary_parts: Vec<BoundaryPart> =
        relation.refs
                .iter()
                .filter(|rf| rf.role == "outer" || rf.role == "" || rf.role == "enclave")
                .filter_map(|refe| {
                    objects.get(&refe.member).or_else(|| {
                        warn!("missing element for relation {}", relation.id);
                        None
                    })
                })
                .filter_map(|way_obj| if let &osmpbfreader::OsmObj::Way(ref way) = way_obj {
                    Some(way)
                } else {
                    None
                })
                .map(|way| get_nodes(&way, objects))
                .filter(|nodes| nodes.len() > 1)
                .map(|nodes| BoundaryPart::new(nodes))
                .collect();
    let mut multipoly = MultiPolygon { polygons: Vec::new() };
    // we want to try build a polygon for a least each way
    while !boundary_parts.is_empty() {
        let mut current = -1;
        let mut first = 0;
        let mut nb_try = 0;

        let mut outer: Vec<osmpbfreader::Node> = Vec::new();
        // we try to close the polygon, if we can't we want to at least have tried one time per
        // way. We could improve that latter by trying to attach the way to both side of the
        // polygon
        let max_try = boundary_parts.len();
        while current != first && nb_try < max_try {
            let mut i = 0;
            while i < boundary_parts.len() {
                if outer.is_empty() {
                    // our polygon is empty, we initialise it with the current way
                    first = boundary_parts[i].first();
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    // this way has been used, we remove it from the pool
                    boundary_parts.remove(i);
                    continue;
                }
                if current == boundary_parts[i].first() {
                    // the start of current way touch the polygon, we add it and remove it from the
                    // pool
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else if current == boundary_parts[i].last() {
                    // the end of the current way touch the polygon, we reverse the way and add it
                    current = boundary_parts[i].first();
                    boundary_parts[i].nodes.reverse();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else {
                    i += 1;
                    // didnt do anything, we want to explore the next way, if we had do something we
                    // will have removed the current way and there will be no need to increment
                }
                if current == first {
                    // our polygon is closed, we create it and add it to the multipolygon
                    let polygon = Polygon::new(outer.iter()
                                                    .map(|n| {
                                                        mimir::Coord {
                                                            lat: n.lat,
                                                            lon: n.lon,
                                                        }
                                                    })
                                                    .collect());
                    multipoly.polygons.push(polygon);
                    break;
                }
            }
            nb_try += 1;
        }
    }
    debug!("polygon for relation {};{}", relation.id, multipoly.to_wkt());
    if multipoly.polygons.is_empty() {
        None
    } else {
        Some(multipoly)
    }
}

fn parse_osm_pbf(path: &String) -> ParsedPbf {
    let path = std::path::Path::new(&path);
    osmpbfreader::OsmPbfReader::new(std::fs::File::open(&path).unwrap())
}

fn administrative_regions(pbf: &mut ParsedPbf, levels: HashSet<u32>) -> AdminsVec {
    let mut administrative_regions = AdminsVec::new();
    let matcher = AdminMatcher::new(levels);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_admin(o)).unwrap();
    // load administratives regions
    for (_, obj) in &objects {
        if !matcher.is_admin(&obj) {
            continue;
        }
        if let &osmpbfreader::OsmObj::Relation(ref relation) = obj {
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            // admininstrative region without coordinates
            let coord_centre = relation.refs
                                       .iter()
                                       .find(|rf| rf.role == "admin_centre")
                                       .and_then(|r| {
                                           objects.get(&r.member).and_then(|value| {
                                               match value {
                                                   &osmpbfreader::OsmObj::Node(ref node) => {
                                                       Some(mimir::Coord {
                                                           lat: node.lat,
                                                           lon: node.lon,
                                                       })
                                                   }
                                                   _ => None,
                                               }
                                           })
                                       });

            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val.trim_left_matches('0')),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let boundary = build_boundary(&relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: coord_centre,
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    return administrative_regions;
}

fn streets(pbf: &mut ParsedPbf) -> StreetsVec {

    let is_valid_street = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Way(ref way) => {
                way.tags.get("highway").map_or(false, |x: &String| !x.is_empty()) &&
                way.tags.get("name").map_or(false, |x: &String| !x.is_empty())
            }
            _ => false,
        }
    };

    osmpbfreader::get_objs_and_deps(pbf, is_valid_street)
        .unwrap()
        .iter()
        .filter_map(|(ref osm_id, ref obj)| {
            if let &&osmpbfreader::OsmObj::Way(ref way) = obj {
                if let &&osmpbfreader::OsmId::Way(ref way_id) = osm_id {
                    way.tags.get("name").and_then(|way_name| {
                        Some(mimirsbrunn::Street {
                            id: way_id.to_string(),
                            street_name: way_name.to_string(),
                            name: way_name.to_string(),
                            weight: 1,
                            administrative_region: None,
                        })
                    })
                } else {
                    None
                }
            } else {
                None
            }
        })
        .collect()
}

fn index_osm(es_cnx_string: &str, admins: &AdminsVec, streets: &StreetsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    rubber.create_index();
    match rubber.clean_db_by_doc_type(&["admin", "street"]) {
        Err(e) => panic!("failed to clean data by document type: {}", e),
        Ok(nb) => info!("clean data by document type : {}", nb),
    }
    info!("Add data in elasticsearch db.");
    match rubber.bulk_index(admins.iter()) {
        Err(e) => panic!("failed to index admins of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed adminstrative regions: {}", nb),
    }

    match rubber.bulk_index(streets.iter()) {
        Err(e) => panic!("failed to index streets of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed streets: {}", nb),
    }
}

fn main() {
    mimir::logger_init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());

    let levels = args.flag_level.iter().cloned().collect();
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);
    let admins = administrative_regions(&mut parsed_pbf, levels);
    let streets = streets(&mut parsed_pbf);
    index_osm(&args.flag_connection_string, &admins, &streets);
}
<|endoftext|>


<commit_before>//! Test script for monitoring MIDI input.
//!
//! The test operates on two levels:
//!
//! 1. All MIDI events are printed to the console.
//! 2. NoteOn/NoteOff events are used to trigger an ADSR.
//!
//! The ADSR gates an oscillator, so that triggering notes can also be heard
//! through the default audio out, and usage of note events can be tested.

extern crate oxcable;

#[cfg(not(test))]
mod wrapper {
    use oxcable::adsr;
    use oxcable::io::midi::MidiIn;
    use oxcable::types::{AudioDevice, MessageReceiver, MidiDevice, MidiMessage,
            Time, Sample};

    pub struct WrappedAdsr {
        pub midi: MidiIn,
        pub adsr: adsr::Adsr
    }
    impl AudioDevice for WrappedAdsr {
        fn num_inputs(&self) -> usize {
            self.adsr.num_inputs()
        }

        fn num_outputs(&self) -> usize {
            self.adsr.num_outputs()
        }

        fn tick(&mut self, t: Time, inputs: &[Sample], outputs: &mut[Sample]) {
            for event in self.midi.get_events(t) {
                println!("{:?}", event);
                match event.payload {
                    MidiMessage::NoteOn(_,_) =>
                        self.adsr.handle_message(adsr::NoteDown),
                    MidiMessage::NoteOff(_,_) =>
                        self.adsr.handle_message(adsr::NoteUp),
                    _ => ()
                }
            }
            self.adsr.tick(t, inputs, outputs);
        }
    }
}

#[cfg(not(test))]
fn main() {
    use oxcable::adsr::Adsr;
    use oxcable::chain::{DeviceChain, Tick};
    use oxcable::io::audio::AudioEngine;
    use oxcable::io::midi::MidiEngine;
    use oxcable::oscillator::{self, Oscillator};

    println!("Initializing signal chain...");
    let audio_engine = AudioEngine::with_buffer_size(256).unwrap();
    let midi_engine = MidiEngine::open().unwrap();

    let mut chain = DeviceChain::from(
        Oscillator::new(oscillator::Saw(oscillator::PolyBlep)).freq(220.0)
    ).into(
        wrapper::WrappedAdsr {
            midi: midi_engine.choose_input().unwrap(),
            adsr: Adsr::default(1)
        }
    ).into(
        audio_engine.default_output(1).unwrap()
    );

    println!("Playing. Press Enter to quit...");
    chain.tick_until_enter();
    println!("Done!");
}
<commit_msg>Update test_midi to remove ADSR<commit_after>//! Test script for monitoring MIDI input.
//!
//! The test operates on two levels:
//!
//! 1. All MIDI events are printed to the console.
//! 2. NoteOn/NoteOff events are used to gate the signal.

extern crate oxcable;

#[cfg(not(test))]
mod gate {
    use oxcable::io::midi::MidiIn;
    use oxcable::types::{AudioDevice, MidiDevice, MidiMessage, Time, Sample};

    pub struct Gate {
        pub midi: MidiIn,
        pub enabled: bool,
    }
    impl Gate {
        pub fn new(midi: MidiIn) -> Self {
            Gate {
                midi: midi,
                enabled: false
            }
        }
    }
    impl AudioDevice for Gate {
        fn num_inputs(&self) -> usize { 1 }
        fn num_outputs(&self) -> usize { 1 }
        fn tick(&mut self, t: Time, inputs: &[Sample], outputs: &mut[Sample]) {
            for event in self.midi.get_events(t) {
                println!("{:?}", event);
                match event.payload {
                    MidiMessage::NoteOn(_,_) => self.enabled = true,
                    MidiMessage::NoteOff(_,_) => self.enabled = false,
                    _ => ()
                }
            }
            outputs[0] = if self.enabled { inputs[0] } else { 0.0 };
        }
    }
}

#[cfg(not(test))]
fn main() {
    use oxcable::chain::{DeviceChain, Tick};
    use oxcable::io::audio::AudioEngine;
    use oxcable::io::midi::MidiEngine;
    use oxcable::oscillator::{self, Oscillator};

    println!("Initializing signal chain...");
    let audio_engine = AudioEngine::with_buffer_size(256).unwrap();
    let midi_engine = MidiEngine::open().unwrap();

    let mut chain = DeviceChain::from(
        Oscillator::new(oscillator::Saw(oscillator::PolyBlep)).freq(220.0)
    ).into(
        gate::Gate::new(midi_engine.choose_input().unwrap())
    ).into(
        audio_engine.default_output(1).unwrap()
    );

    println!("Playing. Press Enter to quit...");
    chain.tick_until_enter();
    println!("Done!");
}
<|endoftext|>


<commit_before>use std::ops::{Index, IndexMut, Mul, Add, Div};

#[macro_use]
extern crate quick_error;

extern crate nalgebra;
use nalgebra::{DMat, DVec};

extern crate image;
use image::{ImageBuffer, Luma, DynamicImage};

extern crate rand;
use rand::{StdRng, Rng, SeedableRng, Closed01};

type FloatType = f64;
type Mat = DMat<FloatType>;

fn horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Mat {
    let mut factor: Mat = DMat::new_zeros(10, 10);
    for col in cols {
        *factor.index_mut((row, col)) = 1.;
    }
    factor
}

fn vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Mat {
    let mut factor: Mat = DMat::new_zeros(10, 10);
    for row in rows {
        *factor.index_mut((row, col)) = 1.;
    }
    factor
}

fn mat_to_image(mat: &Mat) -> DynamicImage {
    let mut image_buffer
        = ImageBuffer::new(mat.ncols() as u32, mat.nrows() as u32);
    for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
        let value = mat.index((y as usize, x as usize));
        let byte = (*value * 255.).round() as u8;
        *pixel = Luma([byte]);
    }
    DynamicImage::ImageLuma8(image_buffer)
}

quick_error! {
    #[derive(Debug)]
    pub enum ImageSaveError {
        Io(err: std::io::Error) {}
        Image(err: image::ImageError) {}
    }
}

fn save_as_png(mat: &Mat, filename: &str) -> Result<(), ImageSaveError> {
    let image = mat_to_image(&mat);
    let path = std::path::Path::new(filename);
    let mut file = try!(std::fs::File::create(&path)
                        .map_err(ImageSaveError::Io));
    image.save(&mut file, image::PNG).map_err(ImageSaveError::Image)
}

fn linear_combination(factors: &[Mat], coefficients: &[FloatType]) -> Mat {
    assert!(0 < factors.len());
    assert_eq!(factors.len(), coefficients.len());
    let nrows = factors[0].nrows();
    let ncols = factors[0].ncols();
    let mut result = DMat::new_zeros(nrows, ncols);
    for (factor, coefficient) in factors.iter().zip(coefficients.iter()) {
        assert_eq!(factor.nrows(), nrows);
        assert_eq!(factor.ncols(), ncols);
        result = result.add(factor.clone().mul(coefficient.clone()));
    }
    // result.div(factors.len() as FloatType)
    result
}

fn random_coefficient<R: Rng>(rng: &mut R) -> FloatType {
    let Closed01(random) = rng.gen::<Closed01<FloatType>>();
    random
}

fn random_coefficients<R: Rng>(rng: &mut R, count: usize) -> DVec<FloatType> {
    let mut coefficients: DVec<FloatType> = DVec::new_zeros(count);
    for i in 0..count {
        coefficients[i] = random_coefficient(rng);
    }
    coefficients
}

fn main() {
    let mut factors: Vec<Mat> = Vec::new();

    factors.push(horizontal_line(9, 0..5));
    for row in (0..9).rev() {
        factors.push(horizontal_line(row, 0..10));
    }

    factors.push(vertical_line(5..10, 0));
    for col in 1..10 {
        factors.push(vertical_line(0..10, col));
    }

    println!("factors:\n");
    for (i, factor) in factors.iter().enumerate() {
        save_as_png(&factor, &format!("factor-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let mut horizontal_evolving: Vec<Mat> = Vec::new();
    for start_col in 0..6 {
        horizontal_evolving.push(horizontal_line(9, start_col..(start_col + 5)));
    }

    println!("short horizontal bar that moves from left to right:\n");
    for (i, factor) in horizontal_evolving.iter().enumerate() {
        save_as_png(&factor, &format!("horizontal-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let mut vertical_evolving: Vec<Mat> = Vec::new();
    for start_row in (0..6).rev() {
        vertical_evolving.push(vertical_line(start_row..(start_row + 5), 0));
    }

    println!("short vertical bar that moves from bottom to top:\n");
    for (i, factor) in vertical_evolving.iter().enumerate() {
        save_as_png(&factor, &format!("vertical-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    // for i in 0..10 {
    //     let combination = random_linear_combination(&factors[..], &mut rng);
    //     save_as_png(&combination, &format!("combination-{}.png", i)[..]).unwrap();
    // }

    let mut iter = horizontal_evolving.iter()
        .zip(vertical_evolving.iter()).enumerate();
    for (step, (horizontal, vertical)) in iter {
        for i in 0..10 {
            // static factors
            let random_coefficients = random_coefficients(&mut rng, factors.len()).div(4.);
            let result = linear_combination(&factors[..], random_coefficients.as_slice());

            // evolving factors
            let horizontal_coefficient = random_coefficient(&mut rng) / 4.;
            let result = result.add(
                horizontal.clone().mul(horizontal_coefficient));

            let vertical_coefficient = random_coefficient(&mut rng) / 4.;
            let result = result.add(
                vertical.clone().mul(vertical_coefficient));

            save_as_png(&result, &format!("test-{}-{}.png", step, i)[..]).unwrap();
        }
    }
}
<commit_msg>remove warning<commit_after>use std::ops::{Index, IndexMut, Mul, Add, Div};

#[macro_use]
extern crate quick_error;

extern crate nalgebra;
use nalgebra::{DMat, DVec};

extern crate image;
use image::{ImageBuffer, Luma, DynamicImage};

extern crate rand;
use rand::{StdRng, Rng, SeedableRng, Closed01};

type FloatType = f64;
type Mat = DMat<FloatType>;

fn horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Mat {
    let mut factor: Mat = DMat::new_zeros(10, 10);
    for col in cols {
        *factor.index_mut((row, col)) = 1.;
    }
    factor
}

fn vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Mat {
    let mut factor: Mat = DMat::new_zeros(10, 10);
    for row in rows {
        *factor.index_mut((row, col)) = 1.;
    }
    factor
}

fn mat_to_image(mat: &Mat) -> DynamicImage {
    let mut image_buffer
        = ImageBuffer::new(mat.ncols() as u32, mat.nrows() as u32);
    for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
        let value = mat.index((y as usize, x as usize));
        let byte = (*value * 255.).round() as u8;
        *pixel = Luma([byte]);
    }
    DynamicImage::ImageLuma8(image_buffer)
}

quick_error! {
    #[derive(Debug)]
    pub enum ImageSaveError {
        Io(err: std::io::Error) {}
        Image(err: image::ImageError) {}
    }
}

fn save_as_png(mat: &Mat, filename: &str) -> Result<(), ImageSaveError> {
    let image = mat_to_image(&mat);
    let path = std::path::Path::new(filename);
    let mut file = try!(std::fs::File::create(&path)
                        .map_err(ImageSaveError::Io));
    image.save(&mut file, image::PNG).map_err(ImageSaveError::Image)
}

fn linear_combination(factors: &[Mat], coefficients: &[FloatType]) -> Mat {
    assert!(0 < factors.len());
    assert_eq!(factors.len(), coefficients.len());
    let nrows = factors[0].nrows();
    let ncols = factors[0].ncols();
    let mut result = DMat::new_zeros(nrows, ncols);
    for (factor, coefficient) in factors.iter().zip(coefficients.iter()) {
        assert_eq!(factor.nrows(), nrows);
        assert_eq!(factor.ncols(), ncols);
        result = result.add(factor.clone().mul(coefficient.clone()));
    }
    // result.div(factors.len() as FloatType)
    result
}

fn random_coefficient<R: Rng>(rng: &mut R) -> FloatType {
    let Closed01(random) = rng.gen::<Closed01<FloatType>>();
    random
}

fn random_coefficients<R: Rng>(rng: &mut R, count: usize) -> DVec<FloatType> {
    let mut coefficients: DVec<FloatType> = DVec::new_zeros(count);
    for i in 0..count {
        coefficients[i] = random_coefficient(rng);
    }
    coefficients
}

fn main() {
    let mut factors: Vec<Mat> = Vec::new();

    factors.push(horizontal_line(9, 0..5));
    for row in (0..9).rev() {
        factors.push(horizontal_line(row, 0..10));
    }

    factors.push(vertical_line(5..10, 0));
    for col in 1..10 {
        factors.push(vertical_line(0..10, col));
    }

    println!("factors:\n");
    for (i, factor) in factors.iter().enumerate() {
        save_as_png(&factor, &format!("factor-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let mut horizontal_evolving: Vec<Mat> = Vec::new();
    for start_col in 0..6 {
        horizontal_evolving.push(horizontal_line(9, start_col..(start_col + 5)));
    }

    println!("short horizontal bar that moves from left to right:\n");
    for (i, factor) in horizontal_evolving.iter().enumerate() {
        save_as_png(&factor, &format!("horizontal-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let mut vertical_evolving: Vec<Mat> = Vec::new();
    for start_row in (0..6).rev() {
        vertical_evolving.push(vertical_line(start_row..(start_row + 5), 0));
    }

    println!("short vertical bar that moves from bottom to top:\n");
    for (i, factor) in vertical_evolving.iter().enumerate() {
        save_as_png(&factor, &format!("vertical-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    // for i in 0..10 {
    //     let combination = random_linear_combination(&factors[..], &mut rng);
    //     save_as_png(&combination, &format!("combination-{}.png", i)[..]).unwrap();
    // }

    let iter = horizontal_evolving.iter()
        .zip(vertical_evolving.iter()).enumerate();
    for (step, (horizontal, vertical)) in iter {
        for i in 0..10 {
            // static factors
            let random_coefficients = random_coefficients(&mut rng, factors.len()).div(4.);
            let result = linear_combination(&factors[..], random_coefficients.as_slice());

            // evolving factors
            let horizontal_coefficient = random_coefficient(&mut rng) / 4.;
            let result = result.add(
                horizontal.clone().mul(horizontal_coefficient));

            let vertical_coefficient = random_coefficient(&mut rng) / 4.;
            let result = result.add(
                vertical.clone().mul(vertical_coefficient));

            save_as_png(&result, &format!("test-{}-{}.png", step, i)[..]).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>struct Book {
    author: ~str,
    title: ~str,
    year: uint,
}

// & means a reference to a Book, no ownership is taken
fn borrow_book(book: &Book) {
    println!("I borrowed {} {} edition", book.title, book.year);
}

// &mut means a mutable reference, meaning the fields of the struct can be
// modified
fn new_edition(book: &mut Book) {
    book.year = 2014;
}

fn main() {
    // an immutable Book
    let geb = Book {
        author: ~"Douglas Hofstadter",
        title: ~"Gödel, Escher, Bach",
        year: 1979,
    };

    // borrow geb, geb can still be used afterwards
    borrow_book(&geb);

    // geb can be borrowed again, and again, and again ...
    borrow_book(&geb);

    // a mutable Book
    let mut mutable_geb = Book {
        author: ~"Douglas Hofstadter",
        title: ~"Gödel, Escher, Bach",
        year: 1979,
    };

    // Error: can't borrow immutable object as mutable
    //new_edition(&mut geb);

    // Ok: borrow a mutable object as mutable
    new_edition(&mut mutable_geb);

    // Ok: mutable objects can be immutably borrowed
    borrow_book(&mutable_geb);

    // when an object is mutably borrowed, the original can't be used
    // until its mutable reference goes out of scope.
    if true {
        let borrowed_geb = &mut mutable_geb;

        // Error: mutable_geb has been mutably borrowed.
        //println!("Can no longer access {}", mutable_geb.title);

        println!("The mutable reference of {} is available",
                 borrowed_geb.title);
        // now borrowed_geb goes out of scope
    }
    println!("Once again, I can access {}", mutable_geb.title);

    // immutable borrows place no restrictions on the original owner
    if true {
        let borrowed_geb = &mutable_geb;
        println!("The original is still accessible: {}",
                 mutable_geb.title);
        println!("and so is the mutable reference: {}",
                 borrowed_geb.title);
    }

    // ref can be used to take references when destructuring
    // Here geb_title and geb_author are references to ~str, i.e. &~str
    // geb_year is a copy of the year field
    let Book {
        author: ref geb_author,
        title: ref geb_title,
        year: geb_year
    } = geb;
}
<commit_msg>Fix typo in #13<commit_after>struct Book {
    author: ~str,
    title: ~str,
    year: uint,
}

// & means a reference to a Book, no ownership is taken
fn borrow_book(book: &Book) {
    println!("I borrowed {} {} edition", book.title, book.year);
}

// &mut means a mutable reference, meaning the fields of the struct can be
// modified
fn new_edition(book: &mut Book) {
    book.year = 2014;
}

fn main() {
    // an immutable Book
    let geb = Book {
        author: ~"Douglas Hofstadter",
        title: ~"Gödel, Escher, Bach",
        year: 1979,
    };

    // borrow geb, geb can still be used afterwards
    borrow_book(&geb);

    // geb can be borrowed again, and again, and again ...
    borrow_book(&geb);

    // a mutable Book
    let mut mutable_geb = Book {
        author: ~"Douglas Hofstadter",
        title: ~"Gödel, Escher, Bach",
        year: 1979,
    };

    // Error: can't borrow immutable object as mutable
    //new_edition(&mut geb);

    // Ok: borrow a mutable object as mutable
    new_edition(&mut mutable_geb);

    // Ok: mutable objects can be immutably borrowed
    borrow_book(&mutable_geb);

    // when an object is mutably borrowed, the original can't be used
    // until its mutable reference goes out of scope.
    if true {
        let borrowed_geb = &mut mutable_geb;

        // Error: mutable_geb has been mutably borrowed.
        //println!("Can no longer access {}", mutable_geb.title);

        println!("The mutable reference of {} is available",
                 borrowed_geb.title);
        // now borrowed_geb goes out of scope
    }
    println!("Once again, I can access {}", mutable_geb.title);

    // immutable borrows place no restrictions on the original owner
    if true {
        let borrowed_geb = &mutable_geb;
        println!("The original is still accessible: {}",
                 mutable_geb.title);
        println!("and so is the immutable reference: {}",
                 borrowed_geb.title);
    }

    // ref can be used to take references when destructuring
    // Here geb_title and geb_author are references to ~str, i.e. &~str
    // geb_year is a copy of the year field
    let Book {
        author: ref geb_author,
        title: ref geb_title,
        year: geb_year
    } = geb;
}
<|endoftext|>


<commit_before>use rustc_ast::{self as ast, MetaItem};
use rustc_middle::ty;
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};

pub(crate) use self::drop_flag_effects::*;
pub use self::framework::{
    fmt, lattice, visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState,
    BorrowckResults, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results,
    ResultsCursor, ResultsRefCursor, ResultsVisitor,
};

use self::move_paths::MoveData;

pub mod drop_flag_effects;
mod framework;
pub mod impls;
pub mod move_paths;

pub(crate) mod indexes {
    pub(crate) use super::{
        impls::borrows::BorrowIndex,
        move_paths::{InitIndex, MoveOutIndex, MovePathIndex},
    };
}

pub struct MoveDataParamEnv<'tcx> {
    pub(crate) move_data: MoveData<'tcx>,
    pub(crate) param_env: ty::ParamEnv<'tcx>,
}

pub(crate) fn has_rustc_mir_with(
    sess: &Session,
    attrs: &[ast::Attribute],
    name: Symbol,
) -> Option<MetaItem> {
    for attr in attrs {
        if sess.check_name(attr, sym::rustc_mir) {
            let items = attr.meta_item_list();
            for item in items.iter().flat_map(|l| l.iter()) {
                match item.meta_item() {
                    Some(mi) if mi.has_name(name) => return Some(mi.clone()),
                    _ => continue,
                }
            }
        }
    }
    None
}
<commit_msg>re-export SwitchIntEdgeEffects<commit_after>use rustc_ast::{self as ast, MetaItem};
use rustc_middle::ty;
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};

pub(crate) use self::drop_flag_effects::*;
pub use self::framework::{
    fmt, lattice, visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState,
    BorrowckResults, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results,
    ResultsCursor, ResultsRefCursor, ResultsVisitor, SwitchIntEdgeEffects,
};

use self::move_paths::MoveData;

pub mod drop_flag_effects;
mod framework;
pub mod impls;
pub mod move_paths;

pub(crate) mod indexes {
    pub(crate) use super::{
        impls::borrows::BorrowIndex,
        move_paths::{InitIndex, MoveOutIndex, MovePathIndex},
    };
}

pub struct MoveDataParamEnv<'tcx> {
    pub(crate) move_data: MoveData<'tcx>,
    pub(crate) param_env: ty::ParamEnv<'tcx>,
}

pub(crate) fn has_rustc_mir_with(
    sess: &Session,
    attrs: &[ast::Attribute],
    name: Symbol,
) -> Option<MetaItem> {
    for attr in attrs {
        if sess.check_name(attr, sym::rustc_mir) {
            let items = attr.meta_item_list();
            for item in items.iter().flat_map(|l| l.iter()) {
                match item.meta_item() {
                    Some(mi) if mi.has_name(name) => return Some(mi.clone()),
                    _ => continue,
                }
            }
        }
    }
    None
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use rand::random;

pub type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World { width: width, height: height, age: 0,
                generation: HashSet::new() }
    }

    pub fn seed(mut self) -> World {
        self.generation = (0..self.width).cartesian_product(0..self.height)
            .filter(|_| random())
            .collect::<HashSet<Point>>();
        self
    }

    pub fn evolve(&mut self) -> &World {
        let mut neighbours_counts = HashMap::new();
        for &(x, y) in self.generation.iter() {
            let neighbours = (-1..2).cartesian_product(-1..2)
                                    .filter(|&(dx, dy)| dx != 0 || dy != 0)
                                    .map(|(dx, dy)| (dx + x, dy + y));
            for n in neighbours {
                let counts = neighbours_counts.entry(n).or_insert(0);
                *counts = *counts + 1;
            }
        }
        self.generation = neighbours_counts.iter()
            .filter(|&(n, c)| if self.generation.contains(n) { *c == 3 || *c == 2 } else { *c == 3 })
            .map(|(n, _)| *n)
            .collect::<HashSet<Point>>();
        self.age += 1;
        self
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        write!(f, "{}", buf)
    }
}
<commit_msg>Store neighbours map to eliminate allocation<commit_after>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use rand::random;

pub type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    neighbours: HashMap<Point, usize>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World { width: width, height: height, age: 0,
                generation: HashSet::with_capacity((width * height) as usize),
                neighbours: HashMap::with_capacity((width * height * 8) as usize) }
    }

    pub fn seed(mut self) -> World {
        self.generation = (0..self.width).cartesian_product(0..self.height)
            .filter(|_| random())
            .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self
    }

    pub fn evolve(&mut self) -> &World {
        self.generation = self.neighbours.iter()
            .filter(|&(n, c)| if self.generation.contains(n) { *c == 3 || *c == 2 } else { *c == 3 })
            .map(|(n, _)| *n)
            .collect::<HashSet<Point>>();
        self.calculate_neighbours();
        self.age += 1;
        self
    }

    fn calculate_neighbours(&mut self) {
        self.neighbours.clear();
        for &(x, y) in self.generation.iter() {
            let neighbours = (-1..2).cartesian_product(-1..2)
                                    .filter(|&(dx, dy)| dx != 0 || dy != 0)
                                    .map(|(dx, dy)| (dx + x, dy + y));
            for n in neighbours {
                let counts = self.neighbours.entry(n).or_insert(0);
                *counts = *counts + 1;
            }
        }
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        write!(f, "{}", buf)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A shareable mutable container for the DOM.

use dom::bindings::trace::JSTraceable;
use js::jsapi::{JSTracer};

use util::task_state;
use util::task_state::{SCRIPT, IN_GC};

use std::cell::{BorrowState, RefCell, Ref, RefMut};

/// A mutable field in the DOM.
///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations, with dynamic checking in debug builds.
pub struct DOMRefCell<T> {
    value: RefCell<T>,
}

// Functionality specific to Servo's `DOMRefCell` type
// ===================================================

impl<T> DOMRefCell<T> {
    /// Return a reference to the contents.
    ///
    /// For use in the layout task only.
    pub unsafe fn borrow_for_layout<'a>(&'a self) -> &'a T {
        debug_assert!(task_state::get().is_layout());
        &*self.value.as_unsafe_cell().get()
    }

    /// Borrow the contents for the purpose of GC tracing.
    ///
    /// This succeeds even if the object is mutably borrowed,
    /// so you have to be careful in trace code!
    pub unsafe fn borrow_for_gc_trace<'a>(&'a self) -> &'a T {
        debug_assert!(task_state::get().contains(SCRIPT | IN_GC));
        &*self.value.as_unsafe_cell().get()
    }

    /// Borrow the contents for the purpose of script deallocation.
    ///
    pub unsafe fn borrow_for_script_deallocation<'a>(&'a self) -> &'a mut T {
        debug_assert!(task_state::get().contains(SCRIPT));
        &mut *self.value.as_unsafe_cell().get()
    }

    /// Is the cell mutably borrowed?
    ///
    /// For safety checks in debug builds only.
    pub fn is_mutably_borrowed(&self) -> bool {
        self.value.borrow_state() == BorrowState::Writing
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        debug_assert!(task_state::get().is_script());
        match self.value.borrow_state() {
            BorrowState::Writing => None,
            _ => Some(self.value.borrow()),
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        debug_assert!(task_state::get().is_script());
        match self.value.borrow_state() {
            BorrowState::Unused => Some(self.value.borrow_mut()),
            _ => None,
        }
    }
}

impl<T: JSTraceable> JSTraceable for DOMRefCell<T> {
    fn trace(&self, trc: *mut JSTracer) {
        (*self).borrow().trace(trc)
    }
}

// Functionality duplicated with `core::cell::RefCell`
// ===================================================
impl<T> DOMRefCell<T> {
    /// Create a new `DOMRefCell` containing `value`.
    pub fn new(value: T) -> DOMRefCell<T> {
        DOMRefCell {
            value: RefCell::new(value),
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    ///
    /// Panics if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => panic!("DOMRefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    ///
    /// Panics if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => panic!("DOMRefCell<T> already borrowed")
        }
    }
}
<commit_msg>auto merge of #5131 : aweinstock314/servo/master, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A shareable mutable container for the DOM.

use dom::bindings::trace::JSTraceable;
use js::jsapi::{JSTracer};

use util::task_state;
use util::task_state::{SCRIPT, IN_GC};

use std::cell::{BorrowState, RefCell, Ref, RefMut};

/// A mutable field in the DOM.
///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations, with dynamic checking in debug builds.
pub struct DOMRefCell<T> {
    value: RefCell<T>,
}

// Functionality specific to Servo's `DOMRefCell` type
// ===================================================

impl<T> DOMRefCell<T> {
    /// Return a reference to the contents.
    ///
    /// For use in the layout task only.
    pub unsafe fn borrow_for_layout<'a>(&'a self) -> &'a T {
        debug_assert!(task_state::get().is_layout());
        &*self.value.as_unsafe_cell().get()
    }

    /// Borrow the contents for the purpose of GC tracing.
    ///
    /// This succeeds even if the object is mutably borrowed,
    /// so you have to be careful in trace code!
    pub unsafe fn borrow_for_gc_trace<'a>(&'a self) -> &'a T {
        debug_assert!(task_state::get().contains(SCRIPT | IN_GC));
        &*self.value.as_unsafe_cell().get()
    }

    /// Borrow the contents for the purpose of script deallocation.
    ///
    pub unsafe fn borrow_for_script_deallocation<'a>(&'a self) -> &'a mut T {
        debug_assert!(task_state::get().contains(SCRIPT));
        &mut *self.value.as_unsafe_cell().get()
    }

    /// Is the cell mutably borrowed?
    ///
    /// For safety checks in debug builds only.
    pub fn is_mutably_borrowed(&self) -> bool {
        self.value.borrow_state() == BorrowState::Writing
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        debug_assert!(task_state::get().is_script());
        match self.value.borrow_state() {
            BorrowState::Writing => None,
            _ => Some(self.value.borrow()),
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        debug_assert!(task_state::get().is_script());
        match self.value.borrow_state() {
            BorrowState::Unused => Some(self.value.borrow_mut()),
            _ => None,
        }
    }
}

impl<T: JSTraceable> JSTraceable for DOMRefCell<T> {
    fn trace(&self, trc: *mut JSTracer) {
        unsafe {
            (*self).borrow_for_gc_trace().trace(trc)
        }
    }
}

// Functionality duplicated with `core::cell::RefCell`
// ===================================================
impl<T> DOMRefCell<T> {
    /// Create a new `DOMRefCell` containing `value`.
    pub fn new(value: T) -> DOMRefCell<T> {
        DOMRefCell {
            value: RefCell::new(value),
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    ///
    /// Panics if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => panic!("DOMRefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    ///
    /// Panics if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => panic!("DOMRefCell<T> already borrowed")
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::io;
use std::fmt;

const TITLE: (u16, u16) = (0x0134, 0x0143);
const CARTRIDGE_TYPE: u16 = 0x0147;
const ROM_SIZE: u16 = 0x0148;
const RAM_SIZE: u16 = 0x0149;

pub struct Cartridge(Vec<u8>);

impl Cartridge {

    /// Load rom file
    pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Cartridge> {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(path)?;
        let _ = file.read_to_end(&mut rom)?;
        Ok(Cartridge(rom))
    }

    /// Read a byte from the rom
    pub fn read_byte(&self, addr: u16) -> u8 {
        self.0[addr as usize]
    }

    /// Read a range of bytes from the rom
    pub fn read_range(&self, addr: (u16, u16)) -> Vec<u8> {
        let mut a: Vec<u8> = Vec::new();
        for x in addr.0..addr.1 {
            a.push(self.0[x as usize])
        }
        a
    }

    /// Read the rom's title
    pub fn read_title(&self) -> String {
        let mut title = String::with_capacity(16);
        for letter in self.read_range(TITLE) {
            if letter == 0 {
                break;
            }
            title.push(letter as char)
        }
        title
    }

}

impl fmt::Debug for Cartridge {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "=== ROM DEBUG ===\n\
            > title game {}\n\
            > cartridge type: {:#x}\n\
            > ROM size: {:#x}\n\
            > RAM size: {:#x}",
            self.read_title(),
            self.read_byte(CARTRIDGE_TYPE),
            self.read_byte(ROM_SIZE),
            self.read_byte(RAM_SIZE))
    }
}
<commit_msg>handle cartridge type<commit_after>use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::io;
use std::fmt;

const TITLE: (u16, u16) = (0x0134, 0x0143);
const CARTRIDGE_TYPE: u16 = 0x0147;
const ROM_SIZE: u16 = 0x0148;
const RAM_SIZE: u16 = 0x0149;

#[derive(Debug)]
pub enum MBC {
    ROM, MBC1,
    MBC2, MBC3,
    MBC4, MBC5
}

pub struct Cartridge(Vec<u8>);

impl Cartridge {

    /// Load rom file
    pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Cartridge> {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(path)?;
        let _ = file.read_to_end(&mut rom)?;
        Ok(Cartridge(rom))
    }

    /// Read a byte from the rom
    pub fn read_byte(&self, addr: u16) -> u8 {
        self.0[addr as usize]
    }

    /// Read a range of bytes from the rom
    pub fn read_range(&self, addr: (u16, u16)) -> Vec<u8> {
        let mut a: Vec<u8> = Vec::new();
        for x in addr.0..addr.1 {
            a.push(self.0[x as usize])
        }
        a
    }

    /// Read the rom's title
    pub fn read_title(&self) -> String {
        let mut title = String::with_capacity(16);
        for letter in self.read_range(TITLE) {
            if letter == 0 {
                break;
            }
            title.push(letter as char)
        }
        title
    }

    /// Read mem type
    pub fn cartridge_type(&self) -> MBC {
        match self.read_byte(CARTRIDGE_TYPE) {
            0x00 | 0x8 | 0x9 => MBC::ROM,
            0x1 | 0x2 | 0x3 => MBC::MBC1,
            0x5 | 0x6 => MBC::MBC2,
            0xF | 0x10 | 0x11 | 0x12 | 0x13 => MBC::MBC3,
            0x15 | 0x16 | 0x17 => MBC::MBC4,
            0x19 | 0x1B | 0x1C | 0x1D | 0x1E => MBC::MBC5,
            _ => unreachable!()
        }
    }

}

impl fmt::Debug for Cartridge {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "=== ROM DEBUG ===\n\
            > title game {}\n\
            > cartridge type: {:?}\n\
            > ROM size: {:#x}\n\
            > RAM size: {:#x}",
            self.read_title(),
            self.cartridge_type(),
            self.read_byte(ROM_SIZE),
            self.read_byte(RAM_SIZE))
    }
}
<|endoftext|>