<commit_before>//use std::sync::Weak;

#[derive(PartialEq, Eq, Debug)]
enum PlayerColor {
    White,
    Black
}

#[allow(dead_code)] // Dead code is allowed, because I want x, y, z even if I don't use it.
struct Point {
    x : i8,
    y : i8,
    z : i8,
    flat_coordinate : i8,
    lines : Vec<i8> // This vector stores the IDs of all lines through it.
}

impl Point {
    // constructor, by convention
    pub fn new(x:i8, y:i8, z:i8) -> Point {
        Point {x:x, y:y, z:z, flat_coordinate:flatten(x, y, z), lines:Vec::new()} //, lines : Vec::new()}
    }
}

struct Line {
    points : [Point; 4]
}

impl Line {
    // constructor, by convention
    pub fn new(x:i8, y:i8, z:i8, dx:i8, dy:i8, dz:i8) -> Line {
        let point1 = Point::new(x, y, z);
        let point2 = Point::new(x+1*dx, y+1*dy, z+1*dz);
        let point3 = Point::new(x+2*dx, y+2*dy, z+2*dz);
        let point4 = Point::new(x+3*dx, y+3*dy, z+3*dz);
        Line { points : [point1, point2, point3, point4]}
    }
}
//
// enum PointState {
//     Piece(PlayerColor),
//     Empty
// }

#[derive(PartialEq, Eq, Debug)]
enum LineState {
    Empty,
    Pure { color: PlayerColor, count: i8 },
    Mixed,
    Win(PlayerColor),
}
//
// struct GameState {
//     points : [PointState; 64],
//     lines  : [LineState; 76]  // something something mutable?
// }

fn flatten(x:i8, y:i8, z:i8) -> i8 {
    return x + 4*y + 16*z
}

// fn expand(index:i8) -> (i8, i8, i8) {
//     return (index % 4, (index / 4) % 4, index / 16)
// }

fn add_ball(line_state : LineState, new_color : PlayerColor) -> LineState {
    match line_state {
        LineState::Empty => LineState::Pure { color : new_color, count : 1},
        LineState::Pure { color : current_color, count : old_count} =>
            if current_color != new_color { LineState::Mixed } else {
                if old_count == 3 {LineState::Win(current_color)}
                else {LineState::Pure {color : current_color, count : old_count+1}}
            },
        LineState::Mixed => LineState::Mixed,
        LineState::Win(_) => panic!("A filled line can't accept any more balls.")
    }
}

fn main() {
    // Initialize a vector of all Points.
    // This has the property, that point_box[i].flat_coordinate = i.
    let mut point_box = Vec::new();
    for z in 0..4 {
        for y in 0..4 {
            for x in 0..4 {
                point_box.push(Point::new(x, y, z));
            }
        }
    }
    // Check if this really produced the right amount of points.
    assert_eq!(point_box.len(), 64);
    let mut i = 0;
    for p in &point_box {
        assert_eq!(p.flat_coordinate, i);
        i += 1;
    }

    // Initialize a vector of all Lines.
    let mut line_box = Vec::new();
    for a in 0..4 {
        for b in 0..4 {
            line_box.push(Line::new(a, b, 0, 0, 0, 1));
            line_box.push(Line::new(0, a, b, 1, 0, 0));
            line_box.push(Line::new(b, 0, a, 0, 1, 0))
        }
        // Diagonals in two spacial directions
        line_box.push(Line::new(a, 0, 0, 0, 1, 1));
        line_box.push(Line::new(0, a, 0, 1, 0, 1));
        line_box.push(Line::new(0, 0, a, 1, 1, 0));
        line_box.push(Line::new(a, 3, 0, 0,-1, 1));
        line_box.push(Line::new(0, a, 3, 1, 0,-1));
        line_box.push(Line::new(3, 0, a,-1, 1, 0));
    }
    // Diagonals in all three directions at once
    line_box.push(Line::new(0, 0, 0, 1, 1, 1));
    line_box.push(Line::new(3, 0, 0,-1, 1, 1));
    line_box.push(Line::new(3, 3, 0,-1,-1, 1));
    line_box.push(Line::new(0, 3, 0, 1,-1, 1));

    // Verify if the line_box has the right length.
    assert_eq!(line_box.len(), 76);

    // Refenence the line ID in the points.
    let mut i = 0;
    for line in line_box {
        for point in line.points.iter() {
            point_box[point.flat_coordinate as usize].lines.push(i);
        }
        i += 1;
    }

    // Do some testing with the LineState Code
    let mut test_state = LineState::Empty;
    test_state = add_ball(test_state, PlayerColor::White);
    println!("{:?}", test_state);
    test_state = add_ball(test_state, PlayerColor::White);
    println!("{:?}", test_state);
    test_state = add_ball(test_state, PlayerColor::White);
    println!("{:?}", test_state);
    test_state = add_ball(test_state, PlayerColor::Black);
    println!("{:?}", test_state);

    // for point in point_box {
    //     println!("{}", point.lines.len());
    // }
}
<commit_msg>randomly place balls<commit_after>//use std::sync::Weak;
extern crate rand;
use rand::{thread_rng, Rng};

#[derive(PartialEq, Eq, Debug, Copy, Clone)]
enum PlayerColor {
    White,
    Black
}

#[allow(dead_code)] // Dead code is allowed, because I want x, y, z even if I don't use it.
#[derive(Debug)]
struct Point {
    x : i8,
    y : i8,
    z : i8,
    flat_coordinate : i8,
    lines : Vec<i8> // This vector stores the IDs of all lines through it.
}

impl Point {
    // constructor, by convention
    pub fn new(x:i8, y:i8, z:i8) -> Point {
        Point {x:x, y:y, z:z, flat_coordinate:flatten(x, y, z), lines:Vec::new()} //, lines : Vec::new()}
    }
}

struct Line {
    points : [Point; 4]
}

impl Line {
    // constructor, by convention
    pub fn new(x:i8, y:i8, z:i8, dx:i8, dy:i8, dz:i8) -> Line {
        let point1 = Point::new(x, y, z);
        let point2 = Point::new(x+1*dx, y+1*dy, z+1*dz);
        let point3 = Point::new(x+2*dx, y+2*dy, z+2*dz);
        let point4 = Point::new(x+3*dx, y+3*dy, z+3*dz);
        Line { points : [point1, point2, point3, point4]}
    }
}

#[derive(PartialEq, Eq, Debug, Copy, Clone)]
enum PointState {
    Piece(PlayerColor),
    Empty
}

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
enum LineState {
    Empty,
    Pure { color: PlayerColor, count: i8 },
    Mixed,
    Win(PlayerColor),
}

struct GameState {
    points : [PointState; 64],
    lines  : [LineState; 76]  // something something mutable?
}

impl GameState {
    pub fn new() -> GameState {
        GameState { points : [PointState::Empty; 64], lines : [LineState::Empty; 76]}
    }
}

fn flatten(x:i8, y:i8, z:i8) -> i8 {
    return x + 4*y + 16*z
}

// fn expand(index:i8) -> (i8, i8, i8) {
//     return (index % 4, (index / 4) % 4, index / 16)
// }

fn add_ball(line_state : LineState, new_color : PlayerColor) -> LineState {
    match line_state {
        LineState::Empty => LineState::Pure { color : new_color, count : 1},
        LineState::Pure { color : current_color, count : old_count} =>
            if current_color != new_color { LineState::Mixed } else {
                if old_count == 3 {LineState::Win(current_color)}
                else {LineState::Pure {color : current_color, count : old_count+1}}
            },
        LineState::Mixed => LineState::Mixed,
        LineState::Win(_) => panic!("A filled line can't accept any more balls.")
    }
}

fn z_value(game_state : &GameState, x : i8, y : i8) -> Option<i8> {
    for z in 0..4 {
        if game_state.points[flatten(x, y, z) as usize] == PointState::Empty {
            return Some(z)
        }
    }
    return None
}

fn legal_moves(game_state : &GameState) -> Vec<(i8, i8)> {
    let mut result = Vec::new();
    for x in 0..4 {
        for y in 0..4 {
            let height = z_value(game_state, x, y);
            match height {
                Some(_) => result.push((x, y)),
                None => ()
            }
        }
    }
    return result;
}

fn main() {
    // Initialize a vector of all Points.
    // This has the property, that point_box[i].flat_coordinate = i.
    let mut point_box = Vec::new();
    for z in 0..4 {
        for y in 0..4 {
            for x in 0..4 {
                point_box.push(Point::new(x, y, z));
            }
        }
    }
    // Check if this really produced the right amount of points.
    assert_eq!(point_box.len(), 64);
    let mut i = 0;
    for p in &point_box {
        assert_eq!(p.flat_coordinate, i);
        i += 1;
    }

    // Initialize a vector of all Lines.
    let mut line_box = Vec::new();
    for a in 0..4 {
        for b in 0..4 {
            line_box.push(Line::new(a, b, 0, 0, 0, 1));
            line_box.push(Line::new(0, a, b, 1, 0, 0));
            line_box.push(Line::new(b, 0, a, 0, 1, 0))
        }
        // Diagonals in two spacial directions
        line_box.push(Line::new(a, 0, 0, 0, 1, 1));
        line_box.push(Line::new(0, a, 0, 1, 0, 1));
        line_box.push(Line::new(0, 0, a, 1, 1, 0));
        line_box.push(Line::new(a, 3, 0, 0,-1, 1));
        line_box.push(Line::new(0, a, 3, 1, 0,-1));
        line_box.push(Line::new(3, 0, a,-1, 1, 0));
    }
    // Diagonals in all three directions at once
    line_box.push(Line::new(0, 0, 0, 1, 1, 1));
    line_box.push(Line::new(3, 0, 0,-1, 1, 1));
    line_box.push(Line::new(3, 3, 0,-1,-1, 1));
    line_box.push(Line::new(0, 3, 0, 1,-1, 1));

    // Verify if the line_box has the right length.
    assert_eq!(line_box.len(), 76);

    // Refenence the line ID in the points.
    let mut i = 0;
    for line in line_box {
        for point in line.points.iter() {
            point_box[point.flat_coordinate as usize].lines.push(i);
        }
        i += 1;
    }

    // Do some testing with the LineState Code
    let mut test_state = LineState::Empty;
    test_state = add_ball(test_state, PlayerColor::White);
    println!("{:?}", test_state);
    test_state = add_ball(test_state, PlayerColor::White);
    println!("{:?}", test_state);
    test_state = add_ball(test_state, PlayerColor::White);
    println!("{:?}", test_state);
    test_state = add_ball(test_state, PlayerColor::Black);
    println!("{:?}", test_state);

    // for point in point_box {
    //     println!("{}", point.lines.len());
    // }

    println!("{:?}", z_value(&GameState::new(), 0, 2));

    fn play_at(state : &mut GameState, x:i8, y:i8, color : PlayerColor) {//-> GameState {
        let z = z_value(&state, x, y);
        let flat_coordinate = match z {
            Some(z) => flatten(x, y, z),
            None => panic!("Added a ball on a forbidden row")
        };
        state.points[flat_coordinate as usize] = PointState::Piece(color);
        //return state; // Here I only return it to hand back ownership to the calling code.
    }

    let mut mystate = GameState::new();
    println!("{:?}", z_value(&mystate, 0, 2));
    {
        let moves = legal_moves(&mystate);
        let position = thread_rng().choose(&moves);
        match position {
            Some(&(x, y)) => play_at(&mut mystate, x, y, PlayerColor::White),
            None => panic!("can't play on that board")
        }
    }
    println!("{:?}", z_value(&mystate, 0, 2));

    let choices = [1, 2, 4, 8, 16, 32];
    let mut rng = thread_rng();
    println!("{:?}", rng.choose(&point_box));
    println!("{:?}", rng.choose(&point_box));
    println!("{:?}", rng.choose(&point_box));
    println!("{:?}", rng.choose(&point_box));
    println!("{:?}", rng.choose(&point_box));
    println!("{:?}", rng.choose(&point_box));
    assert_eq!(rng.choose(&choices[..0]), None);
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate byteorder;

use std::env;
use std::io::Read;
use std::io::Result;
use std::fs::File;
use byteorder::{ByteOrder, LittleEndian};

// Bytecode instructions
const OP_LOAD_U8: u8 = 1; // arity: 2 - (value: u64, dest: u8)
const OP_ADD: u8 = 2; // arity: 3 - (a: u8, b: u8, dest: u8)
const OP_LT: u8 = 3; // arity: 2 - (a: u8, b: u8, dest: u8)
const OP_RETURN: u8 = 4; // arity: 1 - (reg: u8)
const OP_JUMP_TRUE: u8 = 5; // arity

fn interpret(code: &[u8]) -> u64 {
    let mut pc = 0; // "Program counter", the index of the current instruction.
    let mut regs = [0u64; 256]; // Array of 256 zeros.

    loop {
        let op = code[pc];
        pc += 1;
        match op {
            OP_LOAD_U8 => {
                let val = code[pc] as u64;
                pc += 1;
                let dest = code[pc] as usize;
                pc += 1;
                regs[dest] = val;
            },
            OP_ADD => {
                let a = code[pc] as usize;
                pc += 1;
                let b = code[pc] as usize;
                pc += 1;
                let dest = code[pc] as usize;
                pc += 1;
                regs[dest] = regs[a] + regs[b];
            },
            OP_LT => {
                let a = code[pc] as usize;
                pc += 1;
                let b = code[pc] as usize;
                pc += 1;
                let dest = code[pc] as usize;
                pc += 1;
                regs[dest] = (regs[a] < regs[b]) as u64;
            },
            OP_RETURN => {
                let r = code[pc] as usize;
                return regs[r];
            },
            OP_JUMP_TRUE => {
                let r = code[pc] as usize;
                if regs[r] == 1 {
                    pc += 1;
                    let jump_size = LittleEndian::read_i32(&code[pc..pc + 4]);
                    pc += 4;
                    pc = pc.wrapping_add(jump_size as usize);
                } else {
                    pc += 5;
                }
            },
            _ => panic!("Invalid opcode at offset {}", pc)
        }
    }
}

fn read_file(filename: &str) -> Result<Vec<u8>> {
    let mut f = try!(File::open(filename));
    let mut result = vec![];
    try!(f.read_to_end(&mut result));
    Ok(result)
}

fn main() {
    let args: Vec<String> = env::args().collect();

    println!("{:?} args: {:?}", args.len() - 1, &args[1..]);

    let code = [
        OP_LOAD_U8, 73, 0, // load the number 73 into R0.
        OP_LOAD_U8, 68, 1, // load the number 68 into R1.
        OP_ADD, 0, 1, 2, // compute R0 + R1 and store it in R2.
        OP_RETURN, 2
    ];

    // should print 73 + 68, which is 141.
    println!("{}", interpret(&code))
}

#[test]
fn test_op_add() {
    let code = [
        OP_LOAD_U8, 73, 0,
        OP_LOAD_U8, 68, 1,
        OP_ADD, 0, 1, 2,
        OP_RETURN, 2
    ];

    assert_eq!(141, interpret(&code));
}

#[test]
fn test_op_lt() {
    let code1 = [
        OP_LOAD_U8, 73, 0,
        OP_LOAD_U8, 68, 1,
        OP_LT, 0, 1, 2,
        OP_RETURN, 2
    ];

    assert_eq!(0, interpret(&code1));

    let code2 = [
        OP_LOAD_U8, 68, 0,
        OP_LOAD_U8, 73, 1,
        OP_LT, 0, 1, 2,
        OP_RETURN, 2
    ];

    assert_eq!(1, interpret(&code2));
}

#[test]
fn test_loop() {
    let code = [
        // Some bytecode to multiply two numbers.
        OP_LOAD_U8, 6, 0,  // load the number 6 into R0 (`X`, the first number to multiply)
        OP_LOAD_U8, 8, 1,  // load the number 8 into R1 (`Y`, the second number to multiply)
        OP_LOAD_U8, 0, 2,  // load the number 0 into R2 (`i`, the loop counter)
        OP_LOAD_U8, 0, 3,  // load the number 0 into R3 (`acc`, the accumulator)
        OP_LOAD_U8, 1, 4,  // load the number 1 into R4 - it stays there forever

        // for (int i = 0; i < x; i++) {
        //   acc += y;
        // }

        OP_ADD, 1, 3, 3,   // add R1 to R3, store the result in R3
        OP_ADD, 2, 4, 2,   // increment R2 by 1 (because the value in R4 is 1)
        OP_LT, 2, 0, 5,    // is R2 < R0?
        OP_JUMP_TRUE, 5, 0xee, 0xff, 0xff, 0xff, // if so, jump back 18 bytes

        OP_RETURN, 3,      // return contents of R3 (`acc`)
    ];

    assert_eq!(48, interpret(&code));
}
<commit_msg>Add `OP_SUB`, `OP_MULT` and use `i64` instead of `u64`<commit_after>#![allow(dead_code)]
extern crate byteorder;

use std::env;
use std::io::Read;
use std::io::Result;
use std::fs::File;
use byteorder::{ByteOrder, LittleEndian};

// Bytecode instructions
pub const OP_LOAD_U8: u8 = 1; // arity: 2 - (value: u64, dest: u8)
pub const OP_ADD: u8 = 2; // arity: 3 - (a: u8, b: u8, dest: u8)
pub const OP_SUB: u8 = 3; // arity: 3 - (a: u8, b: u8, dest: u8)
pub const OP_MULT: u8 = 4; // arity: 3 - (a: u8, b: u8, dest: u8)
pub const OP_LT: u8 = 5; // arity: 2 - (a: u8, b: u8, dest: u8)
pub const OP_RETURN: u8 = 6; // arity: 1 - (reg: u8)
pub const OP_JUMP_TRUE: u8 = 7; // arity

fn interpret(code: &[u8]) -> i64 {
    let mut pc = 0; // "Program counter", the index of the current instruction.
    let mut regs = [0i64; 256]; // Array of 256 zeros.

    loop {
        let op = code[pc];
        pc += 1;
        match op {
            OP_LOAD_U8 => {
                let val = code[pc] as i64;
                pc += 1;
                let dest = code[pc] as usize;
                pc += 1;
                regs[dest] = val;
            },
            OP_ADD => {
                let a = code[pc] as usize;
                pc += 1;
                let b = code[pc] as usize;
                pc += 1;
                let dest = code[pc] as usize;
                pc += 1;
                regs[dest] = regs[a] + regs[b];
            },
            OP_SUB => {
                let a = code[pc] as usize;
                pc += 1;
                let b = code[pc] as usize;
                pc += 1;
                let dest = code[pc] as usize;
                pc += 1;
                regs[dest] = regs[a] - regs[b];
            },
            OP_MULT => {
                let a = code[pc] as usize;
                pc += 1;
                let b = code[pc] as usize;
                pc += 1;
                let dest = code[pc] as usize;
                pc += 1;
                regs[dest] = regs[a] * regs[b];
            },
            OP_LT => {
                let a = code[pc] as usize;
                pc += 1;
                let b = code[pc] as usize;
                pc += 1;
                let dest = code[pc] as usize;
                pc += 1;
                regs[dest] = (regs[a] < regs[b]) as i64;
            },
            OP_RETURN => {
                let r = code[pc] as usize;
                return regs[r];
            },
            OP_JUMP_TRUE => {
                let r = code[pc] as usize;
                if regs[r] == 1 {
                    pc += 1;
                    let jump_size = LittleEndian::read_i32(&code[pc..pc + 4]);
                    pc += 4;
                    pc = pc.wrapping_add(jump_size as usize);
                } else {
                    pc += 5;
                }
            },
            _ => panic!("Invalid opcode at offset {}", pc)
        }
    }
}

fn read_file(filename: &str) -> Result<Vec<u8>> {
    let mut f = try!(File::open(filename));
    let mut result = vec![];
    try!(f.read_to_end(&mut result));
    Ok(result)
}

fn main() {
    let args: Vec<String> = env::args().collect();

    println!("{:?} args: {:?}", args.len() - 1, &args[1..]);

    let code = [
        OP_LOAD_U8, 73, 0, // load the number 73 into R0.
        OP_LOAD_U8, 68, 1, // load the number 68 into R1.
        OP_ADD, 0, 1, 2, // compute R0 + R1 and store it in R2.
        OP_RETURN, 2
    ];

    // should print 73 + 68, which is 141.
    println!("{}", interpret(&code))
}

#[test]
fn test_op_add() {
    let code = [
        OP_LOAD_U8, 73, 0,
        OP_LOAD_U8, 68, 1,
        OP_ADD, 0, 1, 2,
        OP_RETURN, 2
    ];

    assert_eq!(141, interpret(&code));
}

#[test]
fn test_op_sub() {
    let code1 = [
        OP_LOAD_U8, 10, 0,
        OP_LOAD_U8, 8, 1,
        OP_SUB, 0, 1, 2,
        OP_RETURN, 2
    ];

    assert_eq!(2, interpret(&code1));

    let code2 = [
        OP_LOAD_U8, 8, 0,
        OP_LOAD_U8, 10, 1,
        OP_SUB, 0, 1, 2,
        OP_RETURN, 2
    ];

    assert_eq!(-2, interpret(&code2));
}

#[test]
fn test_op_mult() {
    let code = [
        OP_LOAD_U8, 2, 0,
        OP_LOAD_U8, 4, 1,
        OP_MULT, 0, 1, 2,
        OP_RETURN, 2
    ];

    assert_eq!(8, interpret(&code));
}

#[test]
fn test_op_lt() {
    let code1 = [
        OP_LOAD_U8, 73, 0,
        OP_LOAD_U8, 68, 1,
        OP_LT, 0, 1, 2,
        OP_RETURN, 2
    ];

    assert_eq!(0, interpret(&code1));

    let code2 = [
        OP_LOAD_U8, 68, 0,
        OP_LOAD_U8, 73, 1,
        OP_LT, 0, 1, 2,
        OP_RETURN, 2
    ];

    assert_eq!(1, interpret(&code2));
}

#[test]
fn test_loop() {
    let code = [
        // Some bytecode to multiply two numbers.
        OP_LOAD_U8, 6, 0,  // load the number 6 into R0 (`X`, the first number to multiply)
        OP_LOAD_U8, 8, 1,  // load the number 8 into R1 (`Y`, the second number to multiply)
        OP_LOAD_U8, 0, 2,  // load the number 0 into R2 (`i`, the loop counter)
        OP_LOAD_U8, 0, 3,  // load the number 0 into R3 (`acc`, the accumulator)
        OP_LOAD_U8, 1, 4,  // load the number 1 into R4 - it stays there forever

        // for (int i = 0; i < x; i++) {
        //   acc += y;
        // }

        OP_ADD, 1, 3, 3,   // add R1 to R3, store the result in R3
        OP_ADD, 2, 4, 2,   // increment R2 by 1 (because the value in R4 is 1)
        OP_LT, 2, 0, 5,    // is R2 < R0?
        OP_JUMP_TRUE, 5, 0xee, 0xff, 0xff, 0xff, // if so, jump back 18 bytes

        OP_RETURN, 3,      // return contents of R3 (`acc`)
    ];

    assert_eq!(48, interpret(&code));
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;
use std::fs::File;
use std::io::Read;
use std::hash::Hasher;
use std::path::PathBuf;
use std::collections::HashMap;
use std::collections::BTreeSet;
use std::os::unix::fs::MetadataExt;
use std::collections::hash_map::DefaultHasher;

extern crate env_logger;
#[macro_use]
extern crate log;

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

#[derive(Serialize, Deserialize)]
struct FileEntry {
    size: u64,
    hash: u64,
    files: Vec<String>,
}

fn collect_files(
    dir: &str,
    files: &mut HashMap<u64, Vec<String>>,
    inodes: &mut BTreeSet<(u64, u64)>,
) {
    let entries = match fs::read_dir(dir) {
        Ok(x) => x,
        _ => {
            warn!("{}: invalid directory", dir);
            return;
        }
    };

    for path in entries
        .filter(|x| x.is_ok())
        .map(|x| x.unwrap().path())
        .collect::<Vec<PathBuf>>()
    {
        if let (Some(path_str), Ok(metadata)) =
            (path.to_str(), path.symlink_metadata())
        {
            let ft = metadata.file_type();
            if ft.is_symlink() {
                continue;
            } else if ft.is_file() {
                let inode = metadata.ino();
                let device = metadata.dev();
                if inodes.contains(&(inode, device)) {
                    continue;
                }
                inodes.insert((inode, device));
                match metadata.len() {
                    0 => continue, // Ignore empty files.
                    i => files
                        .entry(i)
                        .or_insert_with(Vec::new)
                        .push(String::from(path_str)),
                };
            } else if ft.is_dir() {
                collect_files(path_str, files, inodes);
            }
        } else {
            warn!("Failed to retrieve metadata for {}", path.to_str().unwrap());
        }
    }
}

fn find_duplicates(
    duplicates: &mut HashMap<u64, Vec<String>>,
    vec: &Vec<String>,
    thorough: bool,
) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(file_entry) {
            let mut hash: u64 = 0;
            let mut hasher = DefaultHasher::new();
            if thorough {
                let mut contents: Vec<u8> = Vec::new();
                if let Ok(_) = file.read_to_end(&mut contents) {
                    hasher.write(&contents[..]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {}", file_entry);
                }
            } else {
                let mut buf: [u8; 1024] = [0; 1024];
                if let Ok(nbytes) = file.read(&mut buf) {
                    hasher.write(&buf[..nbytes as usize]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {} chunk", file_entry);
                }
            }
            if hash != 0 {
                duplicates
                    .entry(hash)
                    .or_insert_with(Vec::new)
                    .push(file_entry.to_string());
            }
        } else {
            warn!("Failed to open file {}", file_entry);
        }
    }
}

fn print_duplicates(
    files: &Vec<String>,
    cluster: i32,
    size: u64,
    hash: u64,
    json_list: &mut Vec<FileEntry>,
    json_output: bool,
) {
    if json_output {
        json_list.push(FileEntry {
            size,
            hash,
            files: files.to_vec(),
        });
    } else {
        println!(
            "{} files in cluster {} (size: {}, digest: {})",
            files.len(),
            cluster,
            size,
            hash
        );
        // for_each becomes stable v1.22.0 onwards. Should uncomment then.
        // files.iter().for_each(|f| println!("{}", f.path));
        for file in files {
            println!("{}", file);
        }
    }
}

fn exhaustive_search(
    content_map: &mut HashMap<Vec<u8>, Vec<String>>,
    files: &Vec<String>,
) {
    for file_name in files {
        if let Ok(mut file) = File::open(file_name) {
            let mut contents: Vec<u8> = Vec::new();
            if let Ok(_) = file.read_to_end(&mut contents) {
                content_map
                    .entry(contents)
                    .or_insert_with(Vec::new)
                    .push(file_name.to_string());
            } else {
                warn!("Failed to read {}", file_name);
            }
        } else {
            warn!("Failed to open {}", file_name);
        }
    }
}

fn main() {
    env_logger::init().unwrap();

    let mut args: Vec<String> = env::args().collect();

    let binary_name = args.remove(0);

    let mut files: HashMap<u64, Vec<String>> = HashMap::new();

    let mut thorough = false;
    let mut exhaustive = false;
    let mut json_output = false;
    let mut print_usage = true;

    {
        let mut inodes: BTreeSet<(u64, u64)> = BTreeSet::new();
        for dir in &args[..] {
            match dir.as_ref() {
                "-t" => {
                    thorough = true;
                    continue;
                }
                "-e" => {
                    thorough = false;
                    exhaustive = false;
                    continue;
                }
                "-j" => {
                    json_output = true;
                    continue;
                }
                _ => {
                    print_usage = false;
                    collect_files(dir, &mut files, &mut inodes);
                }
            }
        }
    }

    if print_usage {
        println!(
            "Usage: {} [-t] [-e] [-j] <dir1> [dir2 [dir3 ...]]",
            binary_name
        );
        ::std::process::exit(0);
    }

    // Get rid of all the single entries.
    files.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    let mut json: Vec<FileEntry> = Vec::new();
    for (key, val) in files {
        let mut duplicates: HashMap<u64, Vec<String>> = HashMap::new();
        find_duplicates(&mut duplicates, &val, thorough);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                if exhaustive {
                    let mut content_map: HashMap<
                        Vec<u8>,
                        Vec<String>,
                    > = HashMap::new();
                    exhaustive_search(&mut content_map, &vec);
                    for (_, v) in content_map {
                        if v.len() >= 2 {
                            print_duplicates(
                                &v,
                                cluster,
                                key,
                                hash,
                                &mut json,
                                json_output,
                            );
                            cluster += 1;
                        }
                    }
                } else {
                    print_duplicates(
                        &vec,
                        cluster,
                        key,
                        hash,
                        &mut json,
                        json_output,
                    );
                    cluster += 1;
                }
            }
        }
    }
    if json_output {
        println!("{}", serde_json::to_string_pretty(&json).unwrap());
    }
}
<commit_msg>Use iterators instead of creating a Vector<commit_after>use std::fs;
use std::env;
use std::fs::File;
use std::io::Read;
use std::hash::Hasher;
use std::path::PathBuf;
use std::collections::HashMap;
use std::collections::BTreeSet;
use std::os::unix::fs::MetadataExt;
use std::collections::hash_map::DefaultHasher;

extern crate env_logger;
#[macro_use]
extern crate log;

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

#[derive(Serialize, Deserialize)]
struct FileEntry {
    size: u64,
    hash: u64,
    files: Vec<String>,
}

fn collect_files(
    dir: &str,
    files: &mut HashMap<u64, Vec<String>>,
    inodes: &mut BTreeSet<(u64, u64)>,
) {
    let entries = match fs::read_dir(dir) {
        Ok(x) => x,
        _ => {
            warn!("{}: invalid directory", dir);
            return;
        }
    };

    for path in entries
        .filter(|x| x.is_ok())
        .map(|x| x.unwrap().path())
        .collect::<Vec<PathBuf>>()
    {
        if let (Some(path_str), Ok(metadata)) =
            (path.to_str(), path.symlink_metadata())
        {
            let ft = metadata.file_type();
            if ft.is_symlink() {
                continue;
            } else if ft.is_file() {
                let inode = metadata.ino();
                let device = metadata.dev();
                if inodes.contains(&(inode, device)) {
                    continue;
                }
                inodes.insert((inode, device));
                match metadata.len() {
                    0 => continue, // Ignore empty files.
                    i => files
                        .entry(i)
                        .or_insert_with(Vec::new)
                        .push(String::from(path_str)),
                };
            } else if ft.is_dir() {
                collect_files(path_str, files, inodes);
            }
        } else {
            warn!("Failed to retrieve metadata for {}", path.to_str().unwrap());
        }
    }
}

fn find_duplicates(
    duplicates: &mut HashMap<u64, Vec<String>>,
    vec: &Vec<String>,
    thorough: bool,
) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(file_entry) {
            let mut hash: u64 = 0;
            let mut hasher = DefaultHasher::new();
            if thorough {
                let mut contents: Vec<u8> = Vec::new();
                if let Ok(_) = file.read_to_end(&mut contents) {
                    hasher.write(&contents[..]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {}", file_entry);
                }
            } else {
                let mut buf: [u8; 1024] = [0; 1024];
                if let Ok(nbytes) = file.read(&mut buf) {
                    hasher.write(&buf[..nbytes as usize]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {} chunk", file_entry);
                }
            }
            if hash != 0 {
                duplicates
                    .entry(hash)
                    .or_insert_with(Vec::new)
                    .push(file_entry.to_string());
            }
        } else {
            warn!("Failed to open file {}", file_entry);
        }
    }
}

fn print_duplicates(
    files: &Vec<String>,
    cluster: i32,
    size: u64,
    hash: u64,
    json_list: &mut Vec<FileEntry>,
    json_output: bool,
) {
    if json_output {
        json_list.push(FileEntry {
            size,
            hash,
            files: files.to_vec(),
        });
    } else {
        println!(
            "{} files in cluster {} (size: {}, digest: {})",
            files.len(),
            cluster,
            size,
            hash
        );
        // for_each becomes stable v1.22.0 onwards. Should uncomment then.
        // files.iter().for_each(|f| println!("{}", f.path));
        for file in files {
            println!("{}", file);
        }
    }
}

fn exhaustive_search(
    content_map: &mut HashMap<Vec<u8>, Vec<String>>,
    files: &Vec<String>,
) {
    for file_name in files {
        if let Ok(mut file) = File::open(file_name) {
            let mut contents: Vec<u8> = Vec::new();
            if let Ok(_) = file.read_to_end(&mut contents) {
                content_map
                    .entry(contents)
                    .or_insert_with(Vec::new)
                    .push(file_name.to_string());
            } else {
                warn!("Failed to read {}", file_name);
            }
        } else {
            warn!("Failed to open {}", file_name);
        }
    }
}

fn main() {
    env_logger::init().unwrap();

    let binary_name = env::args()
        .next()
        .expect("Unable to figure out the binary name");

    let mut files: HashMap<u64, Vec<String>> = HashMap::new();

    let mut thorough = false;
    let mut exhaustive = false;
    let mut json_output = false;
    let mut print_usage = true;

    {
        let mut inodes: BTreeSet<(u64, u64)> = BTreeSet::new();
        for dir in env::args().skip(1) {
            match dir.as_ref() {
                "-t" => {
                    thorough = true;
                    continue;
                }
                "-e" => {
                    thorough = false;
                    exhaustive = false;
                    continue;
                }
                "-j" => {
                    json_output = true;
                    continue;
                }
                _ => {
                    print_usage = false;
                    collect_files(&dir, &mut files, &mut inodes);
                }
            }
        }
    }

    if print_usage {
        println!(
            "Usage: {} [-t] [-e] [-j] <dir1> [dir2 [dir3 ...]]",
            binary_name
        );
        ::std::process::exit(0);
    }

    // Get rid of all the single entries.
    files.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    let mut json: Vec<FileEntry> = Vec::new();
    for (key, val) in files {
        let mut duplicates: HashMap<u64, Vec<String>> = HashMap::new();
        find_duplicates(&mut duplicates, &val, thorough);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                if exhaustive {
                    let mut content_map: HashMap<
                        Vec<u8>,
                        Vec<String>,
                    > = HashMap::new();
                    exhaustive_search(&mut content_map, &vec);
                    for (_, v) in content_map {
                        if v.len() >= 2 {
                            print_duplicates(
                                &v,
                                cluster,
                                key,
                                hash,
                                &mut json,
                                json_output,
                            );
                            cluster += 1;
                        }
                    }
                } else {
                    print_duplicates(
                        &vec,
                        cluster,
                        key,
                        hash,
                        &mut json,
                        json_output,
                    );
                    cluster += 1;
                }
            }
        }
    }
    if json_output {
        println!("{}", serde_json::to_string_pretty(&json).unwrap());
    }
}
<|endoftext|>


<commit_before>use std::f32::{NEG_INFINITY, INFINITY};
use std::cmp::Ordering;
use std::collections::HashMap;

use time;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};
use motion::CENTER_OF_THE_WORLD;
use space::Pinfield;

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0,
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let value = match agent.job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0,
    };
    orientation(agent.team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;

    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personæ(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
        // breadth of scholarship bonus
        if world.agent_to_pinfield_ref(Agent {
                    team: team,
                    job_description: JobDescription::Scholar,
                })
                .to_locales()
                .len() >= 2 {
            valuation += orientation(team) * 0.5
        }
    }

    // ponies and servants want to be in the center of the world's
    // action, maybe??
    let center = Pinfield(CENTER_OF_THE_WORLD);
    // cast to signed to avoid overflow
    let orange_centerism: i8 = world.orange_servants.union(
        world.orange_ponies).intersection(center).pincount() as i8;
    let blue_centerism: i8 = world.blue_servants.union(
        world.blue_ponies).intersection(center).pincount() as i8;
    valuation += (orange_centerism - blue_centerism) as f32 * 0.1;

    valuation
}

fn mmv_lva_heuristic(commit: &Commit) -> f32 {
    // https://chessprogramming.wikispaces.com/MVV-LVA
    match commit.hospitalization {
        Some(patient) => (
            figurine_valuation(patient) - figurine_valuation(commit.patch.star)),
        None => 0.0,
    }
}

fn order_moves(commits: &mut Vec<Commit>) {
    commits.sort_by(|a, b| {
        mmv_lva_heuristic(&b)
            .partial_cmp(&mmv_lva_heuristic(&a))
            .unwrap_or(Ordering::Equal)
    });
}

pub fn α_β_negamax_search(world: WorldState,
                          depth: u8,
                          α: f32,
                          β: f32,
                          déjà_vu_table: &mut HashMap<WorldState, f32>)
                          -> (Option<Commit>, f32) {
    let mut experienced_α = α;
    let team = world.to_move;
    let mut premonitions = world.reckless_lookahead();
    order_moves(&mut premonitions);
    if depth == 0 || premonitions.is_empty() {
        return (None, orientation(team) * score(world))
    };
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let mut value: f32;
        let cached: bool;
        {
            let cached_value_maybe = déjà_vu_table.get(&premonition.tree);
            match cached_value_maybe {
                Some(&cached_value) => {
                    cached = true;
                    value = cached_value;
                }
                None => {
                    cached = false;
                    // XXX fake assignment to work around the compiler's
                    // "possibly uninitialized value" rules
                    value = NEG_INFINITY;
                }
            };
        }

        if !cached {
            let (_, acquired_value) = α_β_negamax_search(premonition.tree,
                                                         depth - 1,
                                                         -β,
                                                         -experienced_α,
                                                         déjà_vu_table);
            value = -acquired_value;
            déjà_vu_table.insert(premonition.tree, value);
        }

        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
        if value > experienced_α {
            experienced_α = value;
        }
        if experienced_α >= β {
            break;
        }
    }

    (optimand, optimum)
}

pub fn potentially_timebound_kickoff(world: &WorldState, depth: u8,
                                     nihilistically: bool,
                                     deadline_maybe: Option<time::Timespec>)
                                     -> Option<Vec<(Commit, f32)>> {
    let mut déjà_vu_table: HashMap<WorldState, f32> = HashMap::new();
    let mut premonitions;
    if nihilistically {
        premonitions = world.reckless_lookahead();
    } else {
        premonitions = world.lookahead();
    }
    order_moves(&mut premonitions);
    let mut forecasts = Vec::new();
    for premonition in premonitions.into_iter() {
        if let Some(deadline) = deadline_maybe {
            if time::get_time() > deadline {
                return None;
            }
        }
        let (_grandchild, mut value) = α_β_negamax_search(premonition.tree,
                                                          depth - 1,
                                                          NEG_INFINITY,
                                                          INFINITY,
                                                          &mut déjà_vu_table);
        value = -value;
        forecasts.push((premonition, value));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    Some(forecasts)
}

pub fn kickoff(world: &WorldState, depth: u8,
               nihilistically: bool) -> Vec<(Commit, f32)> {
    potentially_timebound_kickoff(world, depth, nihilistically, None).unwrap()
}

pub fn iterative_deepening_kickoff(world: &WorldState, timeout: time::Duration,
                                   nihilistically: bool)
                                   -> (Vec<(Commit, f32)>, u8) {
    let deadline = time::get_time() + timeout;
    let mut depth = 1;
    let mut forecasts = potentially_timebound_kickoff(
        world, depth, nihilistically, None).unwrap();
    while let Some(prophecy) = potentially_timebound_kickoff(
            world, depth, nihilistically, Some(deadline)) {
        forecasts = prophecy;
        depth += 1;
    }
    (forecasts, depth)
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use super::{kickoff, score};
    use space::Locale;
    use life::WorldState;
    use identity::Team;

    impl WorldState {
        fn no_castling_at_all(&mut self) {
            self.orange_east_service_eligibility = false;
            self.orange_west_service_eligibility = false;
            self.blue_east_service_eligibility = false;
            self.blue_west_service_eligibility = false;
        }
    }

    #[bench]
    fn benchmark_scoring(b: &mut Bencher) {
        b.iter(|| score(WorldState::new()));
    }

    #[bench]
    fn benchmark_kickoff_depth_1(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 1, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_arbys(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_carefully(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, false));
    }

    #[ignore]
    #[bench]
    fn benchmark_kickoff_depth_3(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 3, true));
    }

    #[test]
    #[allow(float_cmp)]
    fn concerning_fairness_of_the_initial_position() {
        // It's okay to assume this is really 0.0. Floats may be imprecise,
        // but they do have well-defined behavior.
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    fn concerning_servant_ascension_choices() {
        let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w -".to_owned());
        // looking ahead 3 moves allows the Leafline AI to catch the
        // split, whereby transforming into a pony (rather than
        // transitioning into a princess, as would usually be
        // expected) endangers both the blue princess and figurehead
        let (ref best_move, score) = kickoff(&ws, 3, true)[0];
        println!("{:?}", best_move);
        assert!(score > 0.0);
        assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b -");
    }

    #[test]
    fn experimentally_about_kickoff() {
        let mut world = WorldState::new_except_empty();
        // SCENARIO: let's imagine Orange (to move) has separate attacks against
        // Blue's pony and servant, against which Blue has no defense but
        // to run away. We predict that Orange will take the pony, and
        // then Blue will move the servant out of the way.

        // scholar endangers pony
        world.blue_ponies = world.blue_ponies.alight(
            Locale { rank: 0, file: 0 });
        world.orange_scholars = world.orange_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 7, file: 1 });
        world.orange_ponies = world.orange_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Blue has another servant sitting nowhere interesting
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 3, file: 6 });
        world.no_castling_at_all();

        let depth = 2;
        let advisory = kickoff(&world, depth, true);

        // taking the pony is the right thing to do
        assert_eq!(Locale { rank: 0, file: 0 }, advisory[0].0.patch.whither);

        // And, furthermore, the answer should be the same if we face the
        // same situation with the colors reversed
        //
        // XXX this would be tidier and less copy-pastey if I had more
        // general figurine-placing functions that were three rather than
        // two levels of abstraction above twiddling bits on an unsigned
        // int ... oh, well
        let mut negaworld = WorldState::new_except_empty();
        negaworld.to_move = Team::Blue;

        // scholar endangers pony
        negaworld.orange_ponies = negaworld.orange_ponies.alight(
            Locale { rank: 0, file: 0 });
        negaworld.blue_scholars = negaworld.blue_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 7, file: 1 });
        negaworld.blue_ponies = negaworld.blue_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Orange has another servant sitting nowhere interesting
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 3, file: 6 });
        negaworld.to_move = Team::Blue;

        negaworld.no_castling_at_all();

        let negadvisory = kickoff(&negaworld, depth, true);

        // taking the pony is still the right thing to do, even in the
        // negaworld
        assert_eq!(Locale { rank: 0, file: 0 },
                   negadvisory[0].0.patch.whither);
    }

}
<commit_msg>Stop evaluating positions post-ultimate-endangerment<commit_after>use std::f32::{NEG_INFINITY, INFINITY};
use std::cmp::Ordering;
use std::collections::HashMap;

use time;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};
use motion::CENTER_OF_THE_WORLD;
use space::Pinfield;

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0,
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let value = match agent.job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0,
    };
    orientation(agent.team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;

    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personæ(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
        // breadth of scholarship bonus
        if world.agent_to_pinfield_ref(Agent {
                    team: team,
                    job_description: JobDescription::Scholar,
                })
                .to_locales()
                .len() >= 2 {
            valuation += orientation(team) * 0.5
        }
    }

    // ponies and servants want to be in the center of the world's
    // action, maybe??
    let center = Pinfield(CENTER_OF_THE_WORLD);
    // cast to signed to avoid overflow
    let orange_centerism: i8 = world.orange_servants.union(
        world.orange_ponies).intersection(center).pincount() as i8;
    let blue_centerism: i8 = world.blue_servants.union(
        world.blue_ponies).intersection(center).pincount() as i8;
    valuation += (orange_centerism - blue_centerism) as f32 * 0.1;

    valuation
}

fn mmv_lva_heuristic(commit: &Commit) -> f32 {
    // https://chessprogramming.wikispaces.com/MVV-LVA
    match commit.hospitalization {
        Some(patient) => (
            figurine_valuation(patient) - figurine_valuation(commit.patch.star)),
        None => 0.0,
    }
}

fn order_moves(commits: &mut Vec<Commit>) {
    commits.sort_by(|a, b| {
        mmv_lva_heuristic(&b)
            .partial_cmp(&mmv_lva_heuristic(&a))
            .unwrap_or(Ordering::Equal)
    });
}

pub fn α_β_negamax_search(world: WorldState,
                          depth: u8,
                          α: f32,
                          β: f32,
                          déjà_vu_table: &mut HashMap<WorldState, f32>)
                          -> (Option<Commit>, f32) {
    let mut experienced_α = α;
    let team = world.to_move;
    let potential_score = orientation(team) * score(world);
    let mut premonitions = world.reckless_lookahead();
    order_moves(&mut premonitions);
    if depth == 0 || premonitions.is_empty() {
        return (None, potential_score)
    };
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let mut value: f32;
        let cached: bool;
        {
            let cached_value_maybe = déjà_vu_table.get(&premonition.tree);
            match cached_value_maybe {
                Some(&cached_value) => {
                    cached = true;
                    value = cached_value;
                }
                None => {
                    cached = false;
                    // XXX fake assignment to work around the compiler's
                    // "possibly uninitialized value" rules
                    value = NEG_INFINITY;
                }
            };
        }

        if !cached {
            let (_, acquired_value) = α_β_negamax_search(premonition.tree,
                                                         depth - 1,
                                                         -β,
                                                         -experienced_α,
                                                         déjà_vu_table);
            value = -acquired_value;
            déjà_vu_table.insert(premonition.tree, value);
        }

        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
        if value > experienced_α {
            experienced_α = value;
        }
        if experienced_α >= β {
            break;
        }
        if (20000.0 - experienced_α.abs()).abs() < 30.0 {
            break;
        };
    }

    (optimand, optimum)
}

pub fn potentially_timebound_kickoff(world: &WorldState, depth: u8,
                                     nihilistically: bool,
                                     deadline_maybe: Option<time::Timespec>)
                                     -> Option<Vec<(Commit, f32)>> {
    let mut déjà_vu_table: HashMap<WorldState, f32> = HashMap::new();
    let mut premonitions;
    if nihilistically {
        premonitions = world.reckless_lookahead();
    } else {
        premonitions = world.lookahead();
    }
    order_moves(&mut premonitions);
    let mut forecasts = Vec::new();
    for premonition in premonitions.into_iter() {
        if let Some(deadline) = deadline_maybe {
            if time::get_time() > deadline {
                return None;
            }
        }
        let (_grandchild, mut value) = α_β_negamax_search(premonition.tree,
                                                          depth - 1,
                                                          NEG_INFINITY,
                                                          INFINITY,
                                                          &mut déjà_vu_table);
        value = -value;
        forecasts.push((premonition, value));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    Some(forecasts)
}

pub fn kickoff(world: &WorldState, depth: u8,
               nihilistically: bool) -> Vec<(Commit, f32)> {
    potentially_timebound_kickoff(world, depth, nihilistically, None).unwrap()
}

pub fn iterative_deepening_kickoff(world: &WorldState, timeout: time::Duration,
                                   nihilistically: bool)
                                   -> (Vec<(Commit, f32)>, u8) {
    let deadline = time::get_time() + timeout;
    let mut depth = 1;
    let mut forecasts = potentially_timebound_kickoff(
        world, depth, nihilistically, None).unwrap();
    while let Some(prophecy) = potentially_timebound_kickoff(
            world, depth, nihilistically, Some(deadline)) {
        forecasts = prophecy;
        depth += 1;
    }
    (forecasts, depth)
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use time;
    use super::{kickoff, score};
    use space::Locale;
    use life::WorldState;
    use identity::Team;

    impl WorldState {
        fn no_castling_at_all(&mut self) {
            self.orange_east_service_eligibility = false;
            self.orange_west_service_eligibility = false;
            self.blue_east_service_eligibility = false;
            self.blue_west_service_eligibility = false;
        }
    }

    #[bench]
    fn benchmark_scoring(b: &mut Bencher) {
        b.iter(|| score(WorldState::new()));
    }

    #[bench]
    fn benchmark_kickoff_depth_1(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 1, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_arbys(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_carefully(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, false));
    }

    #[ignore]
    #[bench]
    fn benchmark_kickoff_depth_3(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 3, true));
    }

    #[test]
    fn concerning_short_circuiting_upon_finding_mate() {
        let ws = WorldState::reconstruct("7K/r7/1r6/8/8/8/8/7k b -".to_owned());
        let start = time::get_time();
        kickoff(&ws, 30, true);
        let duration = time::get_time() - start;
        assert!(duration.num_seconds() < 20);
    }

    #[test]
    #[allow(float_cmp)]
    fn concerning_fairness_of_the_initial_position() {
        // It's okay to assume this is really 0.0. Floats may be imprecise,
        // but they do have well-defined behavior.
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    fn concerning_servant_ascension_choices() {
        let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w -".to_owned());
        // looking ahead 3 moves allows the Leafline AI to catch the
        // split, whereby transforming into a pony (rather than
        // transitioning into a princess, as would usually be
        // expected) endangers both the blue princess and figurehead
        let (ref best_move, score) = kickoff(&ws, 3, true)[0];
        println!("{:?}", best_move);
        assert!(score > 0.0);
        assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b -");
    }

    #[test]
    fn experimentally_about_kickoff() {
        let mut world = WorldState::new_except_empty();
        // SCENARIO: let's imagine Orange (to move) has separate attacks against
        // Blue's pony and servant, against which Blue has no defense but
        // to run away. We predict that Orange will take the pony, and
        // then Blue will move the servant out of the way.

        // scholar endangers pony
        world.blue_ponies = world.blue_ponies.alight(
            Locale { rank: 0, file: 0 });
        world.orange_scholars = world.orange_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 7, file: 1 });
        world.orange_ponies = world.orange_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Blue has another servant sitting nowhere interesting
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 3, file: 6 });
        world.no_castling_at_all();

        let depth = 2;
        let advisory = kickoff(&world, depth, true);

        // taking the pony is the right thing to do
        assert_eq!(Locale { rank: 0, file: 0 }, advisory[0].0.patch.whither);

        // And, furthermore, the answer should be the same if we face the
        // same situation with the colors reversed
        //
        // XXX this would be tidier and less copy-pastey if I had more
        // general figurine-placing functions that were three rather than
        // two levels of abstraction above twiddling bits on an unsigned
        // int ... oh, well
        let mut negaworld = WorldState::new_except_empty();
        negaworld.to_move = Team::Blue;

        // scholar endangers pony
        negaworld.orange_ponies = negaworld.orange_ponies.alight(
            Locale { rank: 0, file: 0 });
        negaworld.blue_scholars = negaworld.blue_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 7, file: 1 });
        negaworld.blue_ponies = negaworld.blue_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Orange has another servant sitting nowhere interesting
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 3, file: 6 });
        negaworld.to_move = Team::Blue;

        negaworld.no_castling_at_all();

        let negadvisory = kickoff(&negaworld, depth, true);

        // taking the pony is still the right thing to do, even in the
        // negaworld
        assert_eq!(Locale { rank: 0, file: 0 },
                   negadvisory[0].0.patch.whither);
    }

}
<|endoftext|>


<commit_before>
use std::ops::{Index, IndexMut};
use value::Value;
use error::Error;

// top level key that contains everything is __top_level__
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    pub key: Value,
    pub value: Vec<Pair>
}

impl Pair {
    pub fn new<T>(key: T) -> Pair where Value: From<T> {
        Pair {
            key: Value::from(key),
            value: vec![]
        }
    }

    pub fn add<T>(&mut self, val: T) where Value: From<T> {
        self.value.push(Pair::new(val));
    }

    pub fn add_pair(&mut self, p: Pair) {
        self.value.push(p);
    }

    pub fn get(&self, value: Value) -> Result<&Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }

    pub fn get_mut(&mut self, value: Value) -> Result<&mut Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&mut self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }
}

impl<T> Index<T> for Pair where Value: From<T> {
    type Output = Pair;
    fn index(&self, value: T) -> &Pair {
        self.get(value.into()).expect("Did not find value in pair")
    }
}

impl<T> IndexMut<T> for Pair where Value: From<T> {
    fn index_mut(&mut self, value: T) -> &mut Pair {
        self.get_mut(value.into()).expect("Did not find value in pair")
    }
}

<commit_msg>document Pair<commit_after>
use std::ops::{Index, IndexMut};
use value::Value;
use error::Error;

// top level key that contains everything is __top_level__
#[derive(Clone, Debug, PartialEq)]
/// Structure that represents a key-value pair.
pub struct Pair {
    pub key: Value,
    pub value: Vec<Pair>
}

impl Pair {
    /// Creates a new Pair.
    ///
    /// # Examples
    ///
    /// Any type where [`Value`] implements `From` can be supplied:
    ///
    /// ```
    /// # use nccl::pair::Pair;
    /// let p1 = Pair::new("Hello!");
    /// let p2 = Pair::new(true);
    /// // etc
    /// ```
    ///
    /// [`Value`]: ../value/enum.Value.html
    pub fn new<T>(key: T) -> Pair where Value: From<T> {
        Pair {
            key: Value::from(key),
            value: vec![]
        }
    }

    /// Adds a [`Value`] to a Pair. Overwrites values if they exist.
    ///
    /// # Examples
    ///
    /// Any type where [`Value`] implements `From` can be supplied:
    ///
    /// ```
    /// # use nccl::pair::Pair;
    /// let mut p = Pair::new("top");
    /// p.add("hello");
    /// p.add(6.28);
    /// ```
    ///
    /// `add` overwrites values if they exist:
    ///
    /// ```
    /// # use nccl::pair::Pair;
    /// let mut p = Pair::new("top");
    /// p.add("hello");
    /// p["hello"].add("everyone");
    /// p.add("hello");
    ///
    /// assert_eq!(p["hello"], Pair {
    ///     key: "hello".into(),
    ///     value: vec![]
    /// });
    /// ```
    ///
    /// [`Value`]: ../value/enum.Value.html
    pub fn add<T>(&mut self, val: T) where Value: From<T> {
        self.add_pair(Pair::new(val));
    }

    /// Adds a Pair to a Pair. Overwrites values if they exist.
    ///
    /// # Examples
    ///
    /// ```
    /// # use nccl::pair::Pair;
    /// // create a new Pair
    /// let mut p1 = Pair::new("hi");
    ///
    /// // add some stuff to the pair
    /// p1.add("people");
    /// p1.add("friends");
    ///
    /// // we want to say hello some more
    /// let mut p2 = Pair::new("friends");
    ///
    /// // add some friends
    /// p2.add("John");
    /// p2.add("Alex");
    ///
    /// // say hello to our friends
    /// p1.add_pair(p2);
    /// ```
    ///
    /// `add_pair` overwrites values if they exist:
    ///
    /// ```
    /// # use nccl::pair::Pair;
    /// // create a new pair
    /// let mut p1 = Pair::new("happy birthday");
    ///
    /// // we think Ron's birthday is the 3rd...
    /// p1.add("Ron");
    /// p1["Ron"].add("March 3rd");
    ///
    /// // whoops, we were wrong
    /// let mut p2 = Pair::new("Ron");
    /// p2.add("March 2nd");
    ///
    /// // there you go Ron, happy belated birthday
    /// p1.add_pair(p2);
    /// ```
    pub fn add_pair(&mut self, pair: Pair) {
        if !self.value.contains(&pair) {
            self.value.push(pair);
        } else {
            self[pair.key].value = pair.value;
        }
    }

    /// Gets an immutable reference to a Pair in a Pair.
    pub fn get(&self, value: Value) -> Result<&Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }

    /// Gets a mutable reference to a Pair in a Pair.
    ///
    /// # Examples
    ///
    /// ```
    /// # use nccl::pair::Pair;
    /// let mut p = Pair::new("heyo");
    /// p.add("waddup");
    /// p["waddup"].add("my pal");
    ///
    /// // indexing calls get/get_mut under the hood
    /// p.get_mut("waddup".into()).unwrap().add("friend");
    /// // equivalent to
    /// p["waddup"].add("friend");
    /// ```
    pub fn get_mut(&mut self, value: Value) -> Result<&mut Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&mut self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }
}

impl<T> Index<T> for Pair where Value: From<T> {
    type Output = Pair;
    fn index(&self, value: T) -> &Pair {
        self.get(value.into()).expect("Did not find value in pair")
    }
}

impl<T> IndexMut<T> for Pair where Value: From<T> {
    fn index_mut(&mut self, value: T) -> &mut Pair {
        self.get_mut(value.into()).expect("Did not find value in pair")
    }
}

impl Index<Pair> for Pair {
    type Output = Pair;
    fn index(&self, value: Pair) -> &Pair {
        self.get(value.key).expect("Did not find value in pair")
    }
}

impl IndexMut<Pair> for Pair {
    fn index_mut(&mut self, value: Pair) -> &mut Pair {
        self.get_mut(value.key).expect("Did not find value in pair")
    }
}

<|endoftext|>


<commit_before><commit_msg>Rely on Arc From specialization for Vec<[T]> for IVec<commit_after><|endoftext|>


<commit_before>use std::collections::HashSet;

use ecs::*;
use math::Coord;
use grid::{Grid, DynamicGrid};

pub struct SpatialHashCell {
    // sum of opacities of everything in this cell
    opacity: f64,

    // count of solid entities in this cell
    solid: usize,

    entities: EntitySet,
}

pub struct SpatialHashTable {
    grid: DynamicGrid<SpatialHashCell>,
}

impl SpatialHashCell {
    fn new() -> Self {
        SpatialHashCell {
            opacity: 0.0,
            solid: 0,
            entities: EntitySet::new(),
        }
    }

    pub fn opacity(&self) -> f64 {
        self.opacity
    }

    pub fn solid(&self) -> bool {
        self.solid != 0
    }
}

impl Default for SpatialHashCell {
    fn default() -> Self {
        Self::new()
    }
}

impl SpatialHashTable {
    pub fn new() -> Self {
        SpatialHashTable {
            grid: DynamicGrid::new(),
        }
    }

    pub fn get(&self, coord: Coord) -> Option<&SpatialHashCell> {
        self.grid.get(coord)
    }

    pub fn limits_min(&self) -> Coord {
        self.grid.limits_min()
    }

    pub fn limits_max(&self) -> Coord {
        self.grid.limits_max()
    }

    fn get_mut_with_default(&mut self, coord: Coord) -> &mut SpatialHashCell {
        self.grid.get_mut_with_default(coord)
    }

    fn update_insertions(&mut self,
                         ctx: &EcsCtx,
                         insertions: &ActionInsertionTable,
                         insertion_types: &ComponentTypeSet) {

    }

    fn update_removals(&mut self,
                       ctx: &EcsCtx,
                       removals: &ActionRemovalTable,
                       removal_types: &ComponentTypeSet) {

    }

    fn update_removed_entities(&mut self,
                               ctx: &EcsCtx,
                               entities: &HashSet<EntityId>) {

    }

    pub fn update(&mut self, ctx: &EcsCtx, action: &EcsAction) {
        self.update_insertions(ctx,
                               &action.insertions,
                               &action.insertion_types);
        self.update_removals(ctx,
                             &action.removals,
                             &action.removal_types);
        self.update_removed_entities(ctx, &action.removed_entities);
    }
}
<commit_msg>Fleshed out spatial hash implementation<commit_after>use std::collections::HashSet;

use ecs::*;
use math::Coord;
use grid::{Grid, DynamicGrid};

pub struct SpatialHashCell {
    // sum of opacities of everything in this cell
    opacity: f64,

    // count of solid entities in this cell
    solid: usize,

    entities: EntitySet,
}

pub struct SpatialHashTable {
    grid: DynamicGrid<SpatialHashCell>,
}

impl SpatialHashCell {
    fn new() -> Self {
        SpatialHashCell {
            opacity: 0.0,
            solid: 0,
            entities: EntitySet::new(),
        }
    }

    pub fn opacity(&self) -> f64 {
        self.opacity
    }

    pub fn solid(&self) -> bool {
        self.solid != 0
    }
}

impl Default for SpatialHashCell {
    fn default() -> Self {
        Self::new()
    }
}

impl SpatialHashTable {
    pub fn new() -> Self {
        SpatialHashTable {
            grid: DynamicGrid::new(),
        }
    }

    pub fn get(&self, coord: Coord) -> Option<&SpatialHashCell> {
        self.grid.get(coord)
    }

    pub fn limits_min(&self) -> Coord {
        self.grid.limits_min()
    }

    pub fn limits_max(&self) -> Coord {
        self.grid.limits_max()
    }

    fn get_mut_with_default(&mut self, coord: Coord) -> &mut SpatialHashCell {
        self.grid.get_mut_with_default(coord)
    }

    fn change_entity_position(&mut self, entity: EntityRef,
                              current_position: Coord,
                              new_position: Coord) {

    }

    fn add_entity_position(&mut self, entity: EntityRef, position: Coord) {

    }

    fn remove_entity(&mut self, entity: EntityRef, position: Coord) {

    }

    fn remove_solid(&mut self, position: Coord) {

    }

    fn remove_opacity(&mut self, opacity: f64, position: Coord) {

    }

    fn update_insertions(&mut self,
                         ctx: &EcsCtx,
                         insertions: &ActionInsertionTable,
                         insertion_types: &ComponentTypeSet) {
        for (entity_id, new_position) in insertions.position.iter() {
            let entity = ctx.entity(*entity_id);
            if let Some(current_position) = entity.position() {
                // the entity is changing position
                self.change_entity_position(entity, current_position, *new_position);
            } else {
                // the entity is gaining a position
                self.add_entity_position(entity, *new_position);
            }
        }
    }

    fn update_removals(&mut self,
                       ctx: &EcsCtx,
                       removals: &ActionRemovalTable,
                       removal_types: &ComponentTypeSet) {
        for entity_id in removals.solid.iter() {
            if let Some(position) = ctx.position(*entity_id) {
                // removing solid from entity with position
                self.remove_solid(position);
            }
        }

        for entity_id in removals.opacity.iter() {
            let entity = ctx.entity(*entity_id);
            if let Some(position) = entity.position() {
                if let Some(opacity) = entity.opacity() {
                    // removing opacity from entity with position
                    self.remove_opacity(opacity, position);
                }
            }
        }
    }

    fn update_removed_entities(&mut self,
                               ctx: &EcsCtx,
                               entities: &HashSet<EntityId>) {
        for entity_id in entities.iter() {
            let entity = ctx.entity(*entity_id);
            if let Some(position) = entity.position() {
                self.remove_entity(entity, position);
            }
        }
    }

    pub fn update(&mut self, ctx: &EcsCtx, action: &EcsAction) {
        self.update_insertions(ctx,
                               &action.insertions,
                               &action.insertion_types);
        self.update_removals(ctx,
                             &action.removals,
                             &action.removal_types);
        self.update_removed_entities(ctx, &action.removed_entities);
    }
}
<|endoftext|>


<commit_before>//! Reading an OSM XML file.

use std::{fmt, io, str};
use xml::attribute::OwnedAttribute;
use xml::reader::{Error, EventReader, Result, XmlEvent};
use ::elements::{Member, Node, Osm, Relation, Way};

pub fn read_xml<R: io::Read>(source: R) -> Result<Osm> {
    let mut reader = EventReader::new(source);
    while let XmlEvent::ProcessingInstruction{..} = reader.next()? {
    }
    if expect_element(&mut reader, "osm")?.is_none() {
        panic!("Got unexpected end element event");
    }
    read_document(&mut reader)
}

fn read_document<R: io::Read>(reader: &mut EventReader<R>) -> Result<Osm> {
    let mut res = Osm::new();
    loop {
        let (name, attrs) = match reader.next()? {
            XmlEvent::EndDocument => return Ok(res),
            XmlEvent::StartElement{name, attributes, ..} => {
                (name.local_name, attributes)
            }
            ev => return Err(Error::from((&*reader,
                                          format!("expected element, got {:?}",
                                                  ev)))),
        };
        match name.as_ref() {
            "node" => { res.add_node(read_node(attrs, reader)?); },
            "way" => { res.add_way(read_way(attrs, reader)?); },
            "relation" => { res.add_relation(read_relation(attrs, reader)?); },
            _ => { }
        }
    }
}

fn read_node<R: io::Read>(attrs: Vec<OwnedAttribute>,
                          reader: &mut EventReader<R>) -> Result<Node> {
    let (mut id, mut lat, mut lon) = (None, None, None);
    for item in attrs {
        match item.name.local_name.as_ref() {
            "id" => id = Some(item.value),
            "lat" => lat = Some(item.value),
            "lon" => lon = Some(item.value),
            _ => { }
        }
    }
    let id = from_attr(id, reader, "id")?;
    let lat = from_attr(lat, reader, "lat")?;
    let lon = from_attr(lon, reader, "lon")?;
    let mut node = Node::new(id, lat, lon);
    while let Some((name, attrs)) = expect_any_element(reader)? {
        if name == "tag" {
            let (k, v) = read_tag(attrs, reader)?;
            node.insert_tag(k, v);
        }
    }
    Ok(node)
}

fn read_way<R: io::Read>(attrs: Vec<OwnedAttribute>,
                         reader: &mut EventReader<R>) -> Result<Way> {
    let mut id = None;
    for item in attrs {
        match item.name.local_name.as_ref() {
            "id" => id = Some(item.value),
            _ => { }
        }
    }
    let id = from_attr(id, reader, "id")?;
    let mut way = Way::new(id);
    while let Some((name, attrs)) = expect_any_element(reader)? {
        match name.as_ref() {
            "nd" => {
                way.push_node(read_nd(attrs, reader)?);
            }
            "tag" => {
                let (k, v) = read_tag(attrs, reader)?;
                way.insert_tag(k, v)
            }
            _ => { }
        }
    }
    Ok(way)
}

fn read_relation<R: io::Read>(attrs: Vec<OwnedAttribute>,
                              reader: &mut EventReader<R>)
                              -> Result<Relation> {
    let mut id = None;
    for item in attrs {
        match item.name.local_name.as_ref() {
            "id" => id = Some(item.value),
            _ => { }
        }
    }
    let id = from_attr(id, reader, "id")?;
    let mut relation = Relation::new(id);
    while let Some((name, attrs)) = expect_any_element(reader)? {
        match name.as_ref() {
            "member" => {
                relation.push_member(read_member(attrs, reader)?);
            }
            "tag" => {
                let (k, v) = read_tag(attrs, reader)?;
                relation.insert_tag(k, v);
            }
            _ => { }
        }
    }
    Ok(relation)
}

fn read_tag<R: io::Read>(attrs: Vec<OwnedAttribute>,
                         reader: &mut EventReader<R>)
                         -> Result<(String, String)> {
    let (mut k, mut v) = (None, None);
    for item in attrs {
        match item.name.local_name.as_ref() {
            "k" => k = Some(item.value),
            "v" => v = Some(item.value),
            _ => { }
        }
    }
    let k = from_attr(k, reader, "k")?;
    let v = from_attr(v, reader, "v")?;
    Ok((k, v))
}

fn read_nd<R: io::Read>(attrs: Vec<OwnedAttribute>,
                        reader: &mut EventReader<R>) -> Result<i64> {
    let mut id = None;
    for item in attrs {
        match item.name.local_name.as_ref() {
            "ref" => id = Some(item.value),
            _ => { }
        }
    }
    let id = from_attr(id, reader, "ref")?;
    Ok(id)
}

fn read_member<R: io::Read>(attrs: Vec<OwnedAttribute>,
                            reader: &mut EventReader<R>) -> Result<Member> {
    let (mut mtype, mut id, mut role) = (None, None, None);
    for item in attrs {
        match item.name.local_name.as_ref() {
            "type" => mtype = Some(item.value),
            "ref" => id = Some(item.value),
            "role" => role = Some(item.value),
            _ => { }
        }
    }
    let mtype = from_attr(mtype, reader, "type")?;
    let id = from_attr(id, reader, "ref")?;
    let role = from_attr(role, reader, "role")?;
    Ok(Member::new(mtype, id, role))
}

//------------ Helpers -------------------------------------------------------

fn expect_element<R: io::Read>(reader: &mut EventReader<R>, elem: &str)
                               -> Result<Option<Vec<OwnedAttribute>>> {
    match reader.next()? {
        XmlEvent::StartElement{name, attributes, ..} => {
            if name.local_name == elem {
                Ok(Some(attributes))
            }
            else {
                Err(Error::from((&*reader,
                                 format!("expected element '{}'", elem))))
            }
        }
        XmlEvent::EndElement{..} => Ok(None),
        _ => return Err(Error::from((&*reader, "expected element"))),
    }
}

fn expect_any_element<R: io::Read>(reader: &mut EventReader<R>)
                            -> Result<Option<(String, Vec<OwnedAttribute>)>> {
    match reader.next()? {
        XmlEvent::StartElement{name, attributes, ..} => {
            Ok(Some((name.local_name, attributes)))
        }
        XmlEvent::EndElement{..} => Ok(None),
        _ => return Err(Error::from((&*reader, "expected element"))),
    }
}

fn from_attr<R, T>(val: Option<String>, reader: &EventReader<R>,
                   attr: &str) -> Result<T>
            where R: io::Read, T: str::FromStr, T::Err: fmt::Display {
    match val {
        Some(val) => {
            str::FromStr::from_str(&val)
                         .map_err(|err| Error::from((&*reader,
                                                     format!("{}", err))))
        }
        None => {
            Err(Error::from((&*reader,
                             format!("missing '{}' attribute", attr))))
        }
    }
}
<commit_msg>Configure XML parser to ignore white space and comments.<commit_after>//! Reading an OSM XML file.

use std::{fmt, io, str};
use xml::ParserConfig;
use xml::attribute::OwnedAttribute;
use xml::reader::{Error, EventReader, Result, XmlEvent};
use ::elements::{Member, Node, Osm, Relation, Way};

pub fn read_xml<R: io::Read>(source: R) -> Result<Osm> {
    let mut config = ParserConfig::new();
    config.trim_whitespace = true;
    config.ignore_comments = true;
    let mut reader = config.create_reader(source);
    while let XmlEvent::ProcessingInstruction{..} = reader.next()? {
    }
    if expect_element(&mut reader, "osm")?.is_none() {
        panic!("Got unexpected end element event");
    }
    read_document(&mut reader)
}

fn read_document<R: io::Read>(reader: &mut EventReader<R>) -> Result<Osm> {
    let mut res = Osm::new();
    loop {
        let (name, attrs) = match reader.next()? {
            XmlEvent::EndDocument => return Ok(res),
            XmlEvent::StartElement{name, attributes, ..} => {
                (name.local_name, attributes)
            }
            _ => return Err(Error::from((&*reader, "expected element"))),
        };
        match name.as_ref() {
            "node" => { res.add_node(read_node(attrs, reader)?); },
            "way" => { res.add_way(read_way(attrs, reader)?); },
            "relation" => { res.add_relation(read_relation(attrs, reader)?); },
            _ => { }
        }
    }
}

fn read_node<R: io::Read>(attrs: Vec<OwnedAttribute>,
                          reader: &mut EventReader<R>) -> Result<Node> {
    let (mut id, mut lat, mut lon) = (None, None, None);
    for item in attrs {
        match item.name.local_name.as_ref() {
            "id" => id = Some(item.value),
            "lat" => lat = Some(item.value),
            "lon" => lon = Some(item.value),
            _ => { }
        }
    }
    let id = from_attr(id, reader, "id")?;
    let lat = from_attr(lat, reader, "lat")?;
    let lon = from_attr(lon, reader, "lon")?;
    let mut node = Node::new(id, lat, lon);
    while let Some((name, attrs)) = expect_any_element(reader)? {
        if name == "tag" {
            let (k, v) = read_tag(attrs, reader)?;
            node.insert_tag(k, v);
        }
    }
    Ok(node)
}

fn read_way<R: io::Read>(attrs: Vec<OwnedAttribute>,
                         reader: &mut EventReader<R>) -> Result<Way> {
    let mut id = None;
    for item in attrs {
        match item.name.local_name.as_ref() {
            "id" => id = Some(item.value),
            _ => { }
        }
    }
    let id = from_attr(id, reader, "id")?;
    let mut way = Way::new(id);
    while let Some((name, attrs)) = expect_any_element(reader)? {
        match name.as_ref() {
            "nd" => {
                way.push_node(read_nd(attrs, reader)?);
            }
            "tag" => {
                let (k, v) = read_tag(attrs, reader)?;
                way.insert_tag(k, v)
            }
            _ => { }
        }
    }
    Ok(way)
}

fn read_relation<R: io::Read>(attrs: Vec<OwnedAttribute>,
                              reader: &mut EventReader<R>)
                              -> Result<Relation> {
    let mut id = None;
    for item in attrs {
        match item.name.local_name.as_ref() {
            "id" => id = Some(item.value),
            _ => { }
        }
    }
    let id = from_attr(id, reader, "id")?;
    let mut relation = Relation::new(id);
    while let Some((name, attrs)) = expect_any_element(reader)? {
        match name.as_ref() {
            "member" => {
                relation.push_member(read_member(attrs, reader)?);
            }
            "tag" => {
                let (k, v) = read_tag(attrs, reader)?;
                relation.insert_tag(k, v);
            }
            _ => { }
        }
    }
    Ok(relation)
}

fn read_tag<R: io::Read>(attrs: Vec<OwnedAttribute>,
                         reader: &mut EventReader<R>)
                         -> Result<(String, String)> {
    let (mut k, mut v) = (None, None);
    for item in attrs {
        match item.name.local_name.as_ref() {
            "k" => k = Some(item.value),
            "v" => v = Some(item.value),
            _ => { }
        }
    }
    let k = from_attr(k, reader, "k")?;
    let v = from_attr(v, reader, "v")?;
    Ok((k, v))
}

fn read_nd<R: io::Read>(attrs: Vec<OwnedAttribute>,
                        reader: &mut EventReader<R>) -> Result<i64> {
    let mut id = None;
    for item in attrs {
        match item.name.local_name.as_ref() {
            "ref" => id = Some(item.value),
            _ => { }
        }
    }
    let id = from_attr(id, reader, "ref")?;
    Ok(id)
}

fn read_member<R: io::Read>(attrs: Vec<OwnedAttribute>,
                            reader: &mut EventReader<R>) -> Result<Member> {
    let (mut mtype, mut id, mut role) = (None, None, None);
    for item in attrs {
        match item.name.local_name.as_ref() {
            "type" => mtype = Some(item.value),
            "ref" => id = Some(item.value),
            "role" => role = Some(item.value),
            _ => { }
        }
    }
    let mtype = from_attr(mtype, reader, "type")?;
    let id = from_attr(id, reader, "ref")?;
    let role = from_attr(role, reader, "role")?;
    Ok(Member::new(mtype, id, role))
}

//------------ Helpers -------------------------------------------------------

fn expect_element<R: io::Read>(reader: &mut EventReader<R>, elem: &str)
                               -> Result<Option<Vec<OwnedAttribute>>> {
    match reader.next()? {
        XmlEvent::StartElement{name, attributes, ..} => {
            if name.local_name == elem {
                Ok(Some(attributes))
            }
            else {
                Err(Error::from((&*reader,
                                 format!("expected element '{}'", elem))))
            }
        }
        XmlEvent::EndElement{..} => Ok(None),
        _ => return Err(Error::from((&*reader, "expected element"))),
    }
}

fn expect_any_element<R: io::Read>(reader: &mut EventReader<R>)
                            -> Result<Option<(String, Vec<OwnedAttribute>)>> {
    match reader.next()? {
        XmlEvent::StartElement{name, attributes, ..} => {
            Ok(Some((name.local_name, attributes)))
        }
        XmlEvent::EndElement{..} => Ok(None),
        _ => return Err(Error::from((&*reader, "expected element"))),
    }
}

fn from_attr<R, T>(val: Option<String>, reader: &EventReader<R>,
                   attr: &str) -> Result<T>
            where R: io::Read, T: str::FromStr, T::Err: fmt::Display {
    match val {
        Some(val) => {
            str::FromStr::from_str(&val)
                         .map_err(|err| Error::from((&*reader,
                                                     format!("{}", err))))
        }
        None => {
            Err(Error::from((&*reader,
                             format!("missing '{}' attribute", attr))))
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

use std::io::Reader;

use Result;

/// A 16-bit unsigned integer.
pub type USHORT = u16;

/// A 16-bit signed integer.
pub type SHORT = i16;

/// A 32-bit unsigned integer.
pub type ULONG = u32;

/// A 32-bit signed fixed-point number (16.16).
#[deriving(Default, Eq, PartialEq)]
pub struct Fixed(u32);

/// A date represented in number of seconds since 12:00 midnight, January 1,
/// 1904. The value is represented as a signed 64-bit integer.
pub type LONGDATETIME = i64;

pub const CFF_FORMAT_TAG: [u8, ..4] = [b'O', b'T', b'T', b'O'];

pub const FONT_HEADER_TAG: [u8, ..4] = [b'h', b'e', b'a', b'd'];
pub const FONT_HEADER_VERSION_1_0: Fixed = Fixed(0x00010000);
pub const FONT_HEADER_MAGIC_NUMBER: ULONG = 0x5F0F3CF5;

pub const MAXIMAL_PROFILE_TAG: [u8, ..4] = [b'm', b'a', b'x', b'p'];
pub const MAXIMAL_PROFILE_VERSION_0_5: Fixed = Fixed(0x00005000);

pub trait Table {
    fn read(&mut self, reader: &mut Reader) -> Result<()>;
}

macro_rules! define(
    ($name:ident: $($class:ident $field:ident,)+) => (
        #[deriving(Default)]
        pub struct $name { $(pub $field: $class,)+ }
        implement!($name: $($field as $class,)+)
    )
)

macro_rules! implement(
    ($name:ident: $($field:ident as $class:ident,)+) => (
        impl Table for $name {
            fn read(&mut self, reader: &mut Reader) -> Result<()> {
                $(self.$field = read!(reader as $class);)+
                Ok(())
            }
        }
    )
)

macro_rules! read(
    ($reader:ident as USHORT) => (try!($reader.read_be_u16()));
    ($reader:ident as SHORT) => (try!($reader.read_be_i16()));
    ($reader:ident as ULONG) => (try!($reader.read_be_u32()));
    ($reader:ident as Fixed) => (Fixed(try!($reader.read_be_u32())));
    ($reader:ident as LONGDATETIME) => (try!($reader.read_be_i64()));
)

define!(
    OffsetTable:

    Fixed version,
    USHORT numTables,
    USHORT searchRange,
    USHORT entrySelector,
    USHORT rangeShift,
)

define!(
    TableRecord:

    ULONG tag,
    ULONG checkSum,
    ULONG offset,
    ULONG length,
)

define!(
    FontHeader:

    Fixed version,
    Fixed fontRevision,
    ULONG checkSumAdjustment,
    ULONG magicNumber,
    USHORT flags,
    USHORT unitsPerEm,
    LONGDATETIME created,
    LONGDATETIME modified,
    SHORT xMin,
    SHORT yMin,
    SHORT xMax,
    SHORT yMax,
    USHORT macStyle,
    USHORT lowestRecPPEM,
    SHORT fontDirectionHint,
    SHORT indexToLocFormat,
    SHORT glyphDataFormat,
)

define!(
    MaximumProfile:

    Fixed version,
    USHORT numGlyphs,
)

impl Fixed {
    /// Convert `Fixed` into `f32`.
    #[inline]
    pub fn to_f32(&self) -> f32 {
        use std::num::Float;
        println!("Value: 0x{:x}", self.0);
        ((self.0 as f32) * 0.0000152587890625 * 1000.0).round() / 1000.0
    }
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use spec::{OffsetTable, Table};

    #[test]
    fn offset_table_read() {
        let mut file = ::tests::open("SourceSerifPro-Bold.otf");
        let mut table: OffsetTable = Default::default();

        assert!(table.read(&mut file).is_ok());

        assert_eq!(table.version.0, 0x4f54544f);
        assert_eq!(table.numTables, 12);
        assert_eq!(table.searchRange, 8 * 16);
        assert_eq!(table.entrySelector, 3);
        assert_eq!(table.rangeShift, table.numTables * 16 - table.searchRange);
    }
}
<commit_msg>Removed an accidental println!<commit_after>#![allow(non_snake_case)]

use std::io::Reader;

use Result;

/// A 16-bit unsigned integer.
pub type USHORT = u16;

/// A 16-bit signed integer.
pub type SHORT = i16;

/// A 32-bit unsigned integer.
pub type ULONG = u32;

/// A 32-bit signed fixed-point number (16.16).
#[deriving(Default, Eq, PartialEq)]
pub struct Fixed(u32);

/// A date represented in number of seconds since 12:00 midnight, January 1,
/// 1904. The value is represented as a signed 64-bit integer.
pub type LONGDATETIME = i64;

pub const CFF_FORMAT_TAG: [u8, ..4] = [b'O', b'T', b'T', b'O'];

pub const FONT_HEADER_TAG: [u8, ..4] = [b'h', b'e', b'a', b'd'];
pub const FONT_HEADER_VERSION_1_0: Fixed = Fixed(0x00010000);
pub const FONT_HEADER_MAGIC_NUMBER: ULONG = 0x5F0F3CF5;

pub const MAXIMAL_PROFILE_TAG: [u8, ..4] = [b'm', b'a', b'x', b'p'];
pub const MAXIMAL_PROFILE_VERSION_0_5: Fixed = Fixed(0x00005000);

pub trait Table {
    fn read(&mut self, reader: &mut Reader) -> Result<()>;
}

macro_rules! define(
    ($name:ident: $($class:ident $field:ident,)+) => (
        #[deriving(Default)]
        pub struct $name { $(pub $field: $class,)+ }
        implement!($name: $($field as $class,)+)
    )
)

macro_rules! implement(
    ($name:ident: $($field:ident as $class:ident,)+) => (
        impl Table for $name {
            fn read(&mut self, reader: &mut Reader) -> Result<()> {
                $(self.$field = read!(reader as $class);)+
                Ok(())
            }
        }
    )
)

macro_rules! read(
    ($reader:ident as USHORT) => (try!($reader.read_be_u16()));
    ($reader:ident as SHORT) => (try!($reader.read_be_i16()));
    ($reader:ident as ULONG) => (try!($reader.read_be_u32()));
    ($reader:ident as Fixed) => (Fixed(try!($reader.read_be_u32())));
    ($reader:ident as LONGDATETIME) => (try!($reader.read_be_i64()));
)

define!(
    OffsetTable:

    Fixed version,
    USHORT numTables,
    USHORT searchRange,
    USHORT entrySelector,
    USHORT rangeShift,
)

define!(
    TableRecord:

    ULONG tag,
    ULONG checkSum,
    ULONG offset,
    ULONG length,
)

define!(
    FontHeader:

    Fixed version,
    Fixed fontRevision,
    ULONG checkSumAdjustment,
    ULONG magicNumber,
    USHORT flags,
    USHORT unitsPerEm,
    LONGDATETIME created,
    LONGDATETIME modified,
    SHORT xMin,
    SHORT yMin,
    SHORT xMax,
    SHORT yMax,
    USHORT macStyle,
    USHORT lowestRecPPEM,
    SHORT fontDirectionHint,
    SHORT indexToLocFormat,
    SHORT glyphDataFormat,
)

define!(
    MaximumProfile:

    Fixed version,
    USHORT numGlyphs,
)

impl Fixed {
    /// Convert `Fixed` into `f32`.
    #[inline]
    pub fn to_f32(&self) -> f32 {
        use std::num::Float;
        ((self.0 as f32) * 0.0000152587890625 * 1000.0).round() / 1000.0
    }
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use spec::{OffsetTable, Table};

    #[test]
    fn offset_table_read() {
        let mut file = ::tests::open("SourceSerifPro-Bold.otf");
        let mut table: OffsetTable = Default::default();

        assert!(table.read(&mut file).is_ok());

        assert_eq!(table.version.0, 0x4f54544f);
        assert_eq!(table.numTables, 12);
        assert_eq!(table.searchRange, 8 * 16);
        assert_eq!(table.entrySelector, 3);
        assert_eq!(table.rangeShift, table.numTables * 16 - table.searchRange);
    }
}
<|endoftext|>