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

use shared::*;

fn make_glyph(v: [&'static str; 7]) -> Glyph {
    let width = v[0].len();
    let mut glyph = vec![];
    for _ in 0..width {
        glyph.push(EMPTY_COLUMN);
    }
    for y in 0..v.len() {
        let row = v[y];
        for x in 0..row.len() {
            let c = row.chars().nth(x).unwrap();
            glyph[x][y] = if c == ' ' { 0x00 } else { 0x0F };
        }
    }
    glyph
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn font() -> HashMap<char, Glyph> {
    let mut glyphs = HashMap::new();
    glyphs.insert(' ', make_glyph([
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  " "]));
    glyphs.insert('.', make_glyph([
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  "x"]));
    glyphs.insert('!', make_glyph([
                  " ",
                  "x",
                  "x",
                  "x",
                  "x",
                  " ",
                  "x"]));
    glyphs.insert(',', make_glyph([
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  "x",
                  "x"]));
    glyphs.insert(';', make_glyph([
                  " ",
                  " ",
                  " ",
                  "x",
                  " ",
                  "x",
                  "x"]));
    glyphs.insert(':', make_glyph([
                  " ",
                  " ",
                  "x",
                  " ",
                  " ",
                  "x",
                  " "]));
    glyphs.insert('\'', make_glyph([
                  "x",
                  "x",
                  " ",
                  " ",
                  " ",
                  " ",
                  " "]));
    glyphs.insert('"', make_glyph([
                  "x x",
                  "x x",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('\\', make_glyph([
                  "   ",
                  "x  ",
                  "x  ",
                  " x ",
                  " x ",
                  "  x",
                  "  x"]));
    glyphs.insert('/', make_glyph([
                  "   ",
                  "  x",
                  "  x",
                  " x ",
                  " x ",
                  "x  ",
                  "x  "]));
    glyphs.insert('°', make_glyph([
                  "xxx",
                  "x x",
                  "xxx",
                  "   ",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('#', make_glyph([
                  "     ",
                  " x x ",
                  "xxxxx",
                  " x x ",
                  "xxxxx",
                  " x x ",
                  "     "]));
    glyphs.insert('-', make_glyph([
                  "   ",
                  "   ",
                  "   ",
                  "xxx",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('_', make_glyph([
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "xxx"]));
    glyphs.insert('+', make_glyph([
                  "   ",
                  "   ",
                  " x ",
                  "xxx",
                  " x ",
                  "   ",
                  "   "]));
    glyphs.insert('=', make_glyph([
                  "   ",
                  "   ",
                  "xxx",
                  "   ",
                  "xxx",
                  "   ",
                  "   "]));
    glyphs.insert('(', make_glyph([
                  "  ",
                  " x",
                  "x ",
                  "x ",
                  "x ",
                  "x ",
                  " x"]));
    glyphs.insert(')', make_glyph([
                  "  ",
                  "x ",
                  " x",
                  " x",
                  " x",
                  " x",
                  "x "]));
    glyphs.insert('[', make_glyph([
                  "  ",
                  "xx",
                  "x ",
                  "x ",
                  "x ",
                  "x ",
                  "xx"]));
    glyphs.insert(']', make_glyph([
                  "  ",
                  "xx",
                  " x",
                  " x",
                  " x",
                  " x",
                  "xx"]));
    glyphs.insert('@', make_glyph([
                  " xxx ",
                  "x   x",
                  "x xxx",
                  "x x x",
                  "x xxx",
                  "x    ",
                  " xxxx"]));
    glyphs.insert('0', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  "x xx",
                  "xx x",
                  "x  x",
                  " xx "]));
    glyphs.insert('1', make_glyph([
                  "   ",
                  " x ",
                  "xx ",
                  " x ",
                  " x ",
                  " x ",
                  "xxx"]));
    glyphs.insert('2', make_glyph([
                  "    ",
                  "xxx ",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "xxxx"]));
    glyphs.insert('3', make_glyph([
                  "    ",
                  "xxx ",
                  "   x",
                  " xx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('4', make_glyph([
                  "    ",
                  "   x",
                  "  x ",
                  " x  ",
                  "x  x",
                  "xxxx",
                  "   x"]));
    glyphs.insert('5', make_glyph([
                  "    ",
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('6', make_glyph([
                  "    ",
                  " xxx",
                  "x   ",
                  "xxx ",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('7', make_glyph([
                  "    ",
                  "xxxx",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "x   "]));
    glyphs.insert('8', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  " xx ",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('9', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  " xxx",
                  "   x",
                  "   x",
                  " xx "]));
    glyphs.insert('A', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  "x  x",
                  "xxxx",
                  "x  x",
                  "x  x"]));
    glyphs.insert('B', make_glyph([
                  "    ",
                  "xxx ",
                  "x  x",
                  "xxx ",
                  "x  x",
                  "x  x",
                  "xxx "]));
    glyphs.insert('C', make_glyph([
                  "    ",
                  " xxx",
                  "x   ",
                  "x   ",
                  "x   ",
                  "x   ",
                  " xxx"]));
    glyphs.insert('D', make_glyph([
                  "    ",
                  "xxx ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  "xxx "]));
    glyphs.insert('E', make_glyph([
                  "    ",
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "xxxx"]));
    glyphs.insert('F', make_glyph([
                  "    ",
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "x   "]));
    glyphs.insert('G', make_glyph([
                  "    ",
                  " xxx",
                  "x   ",
                  "x   ",
                  "x xx",
                  "x  x",
                  " xxx"]));
    glyphs.insert('H', make_glyph([
                  "    ",
                  "x  x",
                  "x  x",
                  "xxxx",
                  "x  x",
                  "x  x",
                  "x  x"]));
    glyphs.insert('I', make_glyph([
                  " ",
                  "x",
                  "x",
                  "x",
                  "x",
                  "x",
                  "x"]));
    glyphs.insert('J', make_glyph([
                  "    ",
                  "   x",
                  "   x",
                  "   x",
                  "   x",
                  "x  x",
                  " xx "]));
    glyphs.insert('K', make_glyph([
                  "    ",
                  "x  x",
                  "x x ",
                  "xx  ",
                  "x x ",
                  "x  x",
                  "x  x"]));
    glyphs.insert('L', make_glyph([
                  "   ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "xxx"]));
    glyphs.insert('M', make_glyph([
                  "     ",
                  "x   x",
                  "xx xx",
                  "x x x",
                  "x   x",
                  "x   x",
                  "x   x"]));
    glyphs.insert('N', make_glyph([
                  "    ",
                  "x  x",
                  "xx x",
                  "x xx",
                  "x  x",
                  "x  x",
                  "x  x"]));
    glyphs.insert('O', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('P', make_glyph([
                  "    ",
                  "xxx ",
                  "x  x",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "x   "]));
    glyphs.insert('Q', make_glyph([
                  "     ",
                  " xx  ",
                  "x  x ",
                  "x  x ",
                  "x  x ",
                  "x xx ",
                  " xx x"]));
    glyphs.insert('R', make_glyph([
                  "     ",
                  "xxx  ",
                  "x  x ",
                  "xxx  ",
                  "x  x ",
                  "x  x ",
                  "x  x "]));
    glyphs.insert('S', make_glyph([
                  "    ",
                  " xxx",
                  "x   ",
                  " xx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('T', make_glyph([
                  "     ",
                  "xxxxx",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  "]));
    glyphs.insert('U', make_glyph([
                  "    ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('V', make_glyph([
                  "     ",
                  "x   x",
                  "x   x",
                  "x   x",
                  "x   x",
                  " x x ",
                  "  x  "]));
    glyphs.insert('W', make_glyph([
                  "     ",
                  "x   x",
                  "x   x",
                  "x   x",
                  "x x x",
                  "x x x",
                  " x x "]));
    glyphs.insert('X', make_glyph([
                  "     ",
                  "x   x",
                  " x x ",
                  "  x  ",
                  " x x ",
                  "x   x",
                  "x   x"]));
    glyphs.insert('Y', make_glyph([
                  "     ",
                  "x   x",
                  " x x ",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  "]));
    glyphs.insert('Z', make_glyph([
                  "    ",
                  "xxxx",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "xxxx"]));
    glyphs
}
<commit_msg>Adjust the kerning for R<commit_after>use std::collections::HashMap;

use shared::*;

fn make_glyph(v: [&'static str; 7]) -> Glyph {
    let width = v[0].len();
    let mut glyph = vec![];
    for _ in 0..width {
        glyph.push(EMPTY_COLUMN);
    }
    for y in 0..v.len() {
        let row = v[y];
        for x in 0..row.len() {
            let c = row.chars().nth(x).unwrap();
            glyph[x][y] = if c == ' ' { 0x00 } else { 0x0F };
        }
    }
    glyph
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn font() -> HashMap<char, Glyph> {
    let mut glyphs = HashMap::new();
    glyphs.insert(' ', make_glyph([
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  " "]));
    glyphs.insert('.', make_glyph([
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  "x"]));
    glyphs.insert('!', make_glyph([
                  " ",
                  "x",
                  "x",
                  "x",
                  "x",
                  " ",
                  "x"]));
    glyphs.insert(',', make_glyph([
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  "x",
                  "x"]));
    glyphs.insert(';', make_glyph([
                  " ",
                  " ",
                  " ",
                  "x",
                  " ",
                  "x",
                  "x"]));
    glyphs.insert(':', make_glyph([
                  " ",
                  " ",
                  "x",
                  " ",
                  " ",
                  "x",
                  " "]));
    glyphs.insert('\'', make_glyph([
                  "x",
                  "x",
                  " ",
                  " ",
                  " ",
                  " ",
                  " "]));
    glyphs.insert('"', make_glyph([
                  "x x",
                  "x x",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('\\', make_glyph([
                  "   ",
                  "x  ",
                  "x  ",
                  " x ",
                  " x ",
                  "  x",
                  "  x"]));
    glyphs.insert('/', make_glyph([
                  "   ",
                  "  x",
                  "  x",
                  " x ",
                  " x ",
                  "x  ",
                  "x  "]));
    glyphs.insert('°', make_glyph([
                  "xxx",
                  "x x",
                  "xxx",
                  "   ",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('#', make_glyph([
                  "     ",
                  " x x ",
                  "xxxxx",
                  " x x ",
                  "xxxxx",
                  " x x ",
                  "     "]));
    glyphs.insert('-', make_glyph([
                  "   ",
                  "   ",
                  "   ",
                  "xxx",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('_', make_glyph([
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "xxx"]));
    glyphs.insert('+', make_glyph([
                  "   ",
                  "   ",
                  " x ",
                  "xxx",
                  " x ",
                  "   ",
                  "   "]));
    glyphs.insert('=', make_glyph([
                  "   ",
                  "   ",
                  "xxx",
                  "   ",
                  "xxx",
                  "   ",
                  "   "]));
    glyphs.insert('(', make_glyph([
                  "  ",
                  " x",
                  "x ",
                  "x ",
                  "x ",
                  "x ",
                  " x"]));
    glyphs.insert(')', make_glyph([
                  "  ",
                  "x ",
                  " x",
                  " x",
                  " x",
                  " x",
                  "x "]));
    glyphs.insert('[', make_glyph([
                  "  ",
                  "xx",
                  "x ",
                  "x ",
                  "x ",
                  "x ",
                  "xx"]));
    glyphs.insert(']', make_glyph([
                  "  ",
                  "xx",
                  " x",
                  " x",
                  " x",
                  " x",
                  "xx"]));
    glyphs.insert('@', make_glyph([
                  " xxx ",
                  "x   x",
                  "x xxx",
                  "x x x",
                  "x xxx",
                  "x    ",
                  " xxxx"]));
    glyphs.insert('0', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  "x xx",
                  "xx x",
                  "x  x",
                  " xx "]));
    glyphs.insert('1', make_glyph([
                  "   ",
                  " x ",
                  "xx ",
                  " x ",
                  " x ",
                  " x ",
                  "xxx"]));
    glyphs.insert('2', make_glyph([
                  "    ",
                  "xxx ",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "xxxx"]));
    glyphs.insert('3', make_glyph([
                  "    ",
                  "xxx ",
                  "   x",
                  " xx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('4', make_glyph([
                  "    ",
                  "   x",
                  "  x ",
                  " x  ",
                  "x  x",
                  "xxxx",
                  "   x"]));
    glyphs.insert('5', make_glyph([
                  "    ",
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('6', make_glyph([
                  "    ",
                  " xxx",
                  "x   ",
                  "xxx ",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('7', make_glyph([
                  "    ",
                  "xxxx",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "x   "]));
    glyphs.insert('8', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  " xx ",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('9', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  " xxx",
                  "   x",
                  "   x",
                  " xx "]));
    glyphs.insert('A', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  "x  x",
                  "xxxx",
                  "x  x",
                  "x  x"]));
    glyphs.insert('B', make_glyph([
                  "    ",
                  "xxx ",
                  "x  x",
                  "xxx ",
                  "x  x",
                  "x  x",
                  "xxx "]));
    glyphs.insert('C', make_glyph([
                  "    ",
                  " xxx",
                  "x   ",
                  "x   ",
                  "x   ",
                  "x   ",
                  " xxx"]));
    glyphs.insert('D', make_glyph([
                  "    ",
                  "xxx ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  "xxx "]));
    glyphs.insert('E', make_glyph([
                  "    ",
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "xxxx"]));
    glyphs.insert('F', make_glyph([
                  "    ",
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "x   "]));
    glyphs.insert('G', make_glyph([
                  "    ",
                  " xxx",
                  "x   ",
                  "x   ",
                  "x xx",
                  "x  x",
                  " xxx"]));
    glyphs.insert('H', make_glyph([
                  "    ",
                  "x  x",
                  "x  x",
                  "xxxx",
                  "x  x",
                  "x  x",
                  "x  x"]));
    glyphs.insert('I', make_glyph([
                  " ",
                  "x",
                  "x",
                  "x",
                  "x",
                  "x",
                  "x"]));
    glyphs.insert('J', make_glyph([
                  "    ",
                  "   x",
                  "   x",
                  "   x",
                  "   x",
                  "x  x",
                  " xx "]));
    glyphs.insert('K', make_glyph([
                  "    ",
                  "x  x",
                  "x x ",
                  "xx  ",
                  "x x ",
                  "x  x",
                  "x  x"]));
    glyphs.insert('L', make_glyph([
                  "   ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "xxx"]));
    glyphs.insert('M', make_glyph([
                  "     ",
                  "x   x",
                  "xx xx",
                  "x x x",
                  "x   x",
                  "x   x",
                  "x   x"]));
    glyphs.insert('N', make_glyph([
                  "    ",
                  "x  x",
                  "xx x",
                  "x xx",
                  "x  x",
                  "x  x",
                  "x  x"]));
    glyphs.insert('O', make_glyph([
                  "    ",
                  " xx ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('P', make_glyph([
                  "    ",
                  "xxx ",
                  "x  x",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "x   "]));
    glyphs.insert('Q', make_glyph([
                  "     ",
                  " xx  ",
                  "x  x ",
                  "x  x ",
                  "x  x ",
                  "x xx ",
                  " xx x"]));
    glyphs.insert('R', make_glyph([
                  "    ",
                  "xxx ",
                  "x  x",
                  "xxx ",
                  "x  x",
                  "x  x",
                  "x  x"]));
    glyphs.insert('S', make_glyph([
                  "    ",
                  " xxx",
                  "x   ",
                  " xx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('T', make_glyph([
                  "     ",
                  "xxxxx",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  "]));
    glyphs.insert('U', make_glyph([
                  "    ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('V', make_glyph([
                  "     ",
                  "x   x",
                  "x   x",
                  "x   x",
                  "x   x",
                  " x x ",
                  "  x  "]));
    glyphs.insert('W', make_glyph([
                  "     ",
                  "x   x",
                  "x   x",
                  "x   x",
                  "x x x",
                  "x x x",
                  " x x "]));
    glyphs.insert('X', make_glyph([
                  "     ",
                  "x   x",
                  " x x ",
                  "  x  ",
                  " x x ",
                  "x   x",
                  "x   x"]));
    glyphs.insert('Y', make_glyph([
                  "     ",
                  "x   x",
                  " x x ",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  "]));
    glyphs.insert('Z', make_glyph([
                  "    ",
                  "xxxx",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "xxxx"]));
    glyphs
}
<|endoftext|>


<commit_before>use Pixel;
use world::World;
use piston_window::*;
use car::CarRules;
use camera::Camera;
use cgmath::{Vector3, Vector2};
use cgmath::prelude::*;
use color::*;
use rnd;
use car::Car;
use piston_window::Ellipse;

pub struct Game {
    config: GameConfig,
    world: World,
    window: PistonWindow,
    bot_rules: CarRules,
    camera: Camera,
    state: State,
}

struct State {
    pub turn: Turn,
    pub sprint: bool,
    pub spawn: f64,
    pub ended: bool,
    pub game_speed: f64,
    pub jump_timeout: f64,
    pub rotate_cam: bool,
    pub bullets: i64,
    pub recharge: f64,
}

pub enum Turn { Left, Right, None, }

pub struct GameConfig {
    pub title: &'static str,
    pub screen_size: Pixel,
    pub ups: u64,
    pub max_fps: u64,
    pub tunel_size: [f64; 3],
    pub player_size: [f64; 3],
    pub player_speed: (f64, f64),
    pub player_turn_speed: f64,
    pub bot_size: [(f64, f64); 3],
    pub bot_speed: (f64, f64),
    pub bot_turn_speed: (f64, f64),
    pub divider_size: [f64; 2],
    pub camera_height: f64,
    pub camera_distance: f64,
    pub decor_distance: f64,
    pub sprint_factor: f64,
    pub spawn_time: (f64, f64),
    pub game_sprint: f64,
    pub game_max_speed: f64,
    pub player_jump_v: f64,
    pub player_jump_a: f64,
    pub jump_turn_decrease: f64,
    pub jump_timeout: f64,
    pub mouse_speed: f64,
    pub trueshot_distance: f64,
    pub bullet_stock: i64,
    pub recharge_time: f64,
    pub bullet_len: f64,
    pub bullet_speed: f64,
}

impl Game {
    pub fn new(config: GameConfig) -> Game {
        let mut window: PistonWindow = WindowSettings::new(
            config.title, [config.screen_size.w, config.screen_size.h])
            .exit_on_esc(true).build().unwrap();
        window.set_ups(config.ups);
        window.set_max_fps(config.max_fps);
        window.set_capture_cursor(true);
        let bot_rules = CarRules {
            size: config.bot_size,
            position: [(0., config.tunel_size[0]), (0., 0.), (config.tunel_size[2], config.tunel_size[2])],
            speed: config.bot_speed,
            turn_speed: config.bot_turn_speed,
            color: vec![RED, ORANGE, VIOLET, GREEN, PALE],
            jump_turn_decrease: config.jump_turn_decrease,
        };
        let world = World::new(&config);
        let camera = Game::new_camera(&config, &world.player);
        let state = State {
            turn: Turn::None,
            sprint: false,
            spawn: 0.,
            ended: false,
            game_speed: 0.,
            jump_timeout: 0.,
            rotate_cam: false,
            bullets: config.bullet_stock,
            recharge: 0.,
        };
        Game {
            config: config,
            world: world,
            window: window,
            bot_rules: bot_rules,
            camera: camera,
            state: state,
        }
    }

    fn new_camera(config: &GameConfig, player: &Car) -> Camera {
        Camera::new(config.screen_size.clone(),
        Vector3::new(player.position.x,
                     config.camera_height,
                     player.position.z-config.camera_distance))
    }

    pub fn run(&mut self) {
        while let Some(e) = self.window.next() {
            match e {
                Input::Press(key) => self.press(key),
                Input::Release(key) => self.release(key),
                Input::Render(_) => self.draw(&e),
                Input::Update(args) => self.update(args.dt),
                Input::Move(Motion::MouseRelative(a, b)) => self.mouse_move(a as f64, b as f64),
                _ => {}
            }
            if self.state.ended {
                break;
            }
        }
    }

    fn mouse_move(&mut self, x: f64, y: f64) {
        if self.state.rotate_cam {
            self.camera.rotate(x*self.config.mouse_speed, y*self.config.mouse_speed, self.world.player.position);
        }
    }
    fn press(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => self.state.turn = Turn::Left,
            Button::Keyboard(Key::D) => self.state.turn = Turn::Right,
            Button::Keyboard(Key::W) => self.state.sprint = true,
            Button::Keyboard(Key::Space) => if self.state.jump_timeout <= 0. {
                self.state.jump_timeout = self.config.jump_timeout;
                self.world.player.start_jump();
            },
            Button::Mouse(MouseButton::Right) => {
                self.camera.zoom_in();
                self.state.rotate_cam = true;
            },
            Button::Mouse(MouseButton::Left) => if self.state.rotate_cam && self.state.bullets > 0 {
                let mut pos = self.world.player.position;
                pos.y += self.world.player.size.y;
                let mut d = Vector3::new(0., 0., self.config.trueshot_distance + self.config.camera_distance);
                d = self.camera.c * d.magnitude2() / d.dot(self.camera.c);
                d = self.camera.eye + d - pos;
                d = d * self.config.bullet_speed / d.magnitude();
                self.world.add_bullet(pos, d, self.config.bullet_len);
                self.state.bullets -= 1;
                if self.state.bullets <= 0 {
                    self.state.recharge = self.config.recharge_time;
                }
            },
            _ => (),
        }
    }
    fn release(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => if let Turn::Left = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::D) => if let Turn::Right = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::W) => self.state.sprint = false,
            Button::Mouse(MouseButton::Right) => {
                self.state.rotate_cam = false;
                self.camera = Game::new_camera(&self.config, &self.world.player);
            },
            _ => (),
        }
    }
    fn draw(&mut self, e: &Input) {
        let lines = self.world.render(&self.camera);
        let jump_bar = [
            0.,
            self.config.screen_size.h as f64 - 20.,
            self.config.screen_size.w as f64/2.*self.state.jump_timeout/self.config.jump_timeout,
            self.config.screen_size.h as f64,
        ];
        let recharge_bar = [
            0.,
            self.config.screen_size.h as f64 - 20.,
            self.config.screen_size.w as f64/2.*self.state.recharge/self.config.recharge_time,
            self.config.screen_size.h as f64,
        ];
        self.window.draw_2d(e, |c, g| {
            clear(BLACK, g);
            for (l, color) in lines {
                line(color, 1., convert(l), c.transform, g);
            }
            rectangle(pale(BLUE, 0.4), jump_bar, c.transform, g);
            rectangle(pale(RED, 0.4), recharge_bar, c.transform, g);
        });

        if self.state.rotate_cam {
            let w = 20.;
            let x = self.config.screen_size.w as f64 /2. - w/2.;
            let y = self.config.screen_size.h as f64 /2. - w/2.;
            self.window.draw_2d(e, |c, g| {
                let e = Ellipse {
                    color: pale(BLACK, 0.),
                    border: Some(ellipse::Border {
                        color: pale(RED, 0.5),
                        radius: 1.,
                    }),
                    resolution: 360,
                };
                e.draw([x, y, w, w], &c.draw_state, c.transform, g);
                rectangle(RED, [x+w/2.-1., y+w/2.-1., 2., 2.], c.transform, g);
            });
        }

    }
    fn update(&mut self, dt: f64) {
        let old = self.world.player.position;
        if self.state.bullets <= 0 {
            self.state.recharge -= dt;
            if self.state.recharge < 0. {
                self.state.bullets = self.config.bullet_stock;
            }
        }
        self.state.jump_timeout -= dt;
        if self.state.game_speed < self.config.game_max_speed {
            self.state.game_speed += dt*self.config.game_sprint;
        }
        if self.state.sprint {
            if self.world.player.speed < self.config.player_speed.1 {
                self.world.player.speed += dt*self.config.sprint_factor;
            }
        } else if self.world.player.speed > self.config.player_speed.0 {
            self.world.player.speed -= dt*self.config.sprint_factor;
        }
        self.state.spawn -= dt;
        if self.state.spawn < 0. {
            self.world.add_bot(&self.bot_rules);
            self.state.spawn += rnd(self.config.spawn_time);
        }
        self.world.player.turn(&self.state.turn, dt);
        self.world.update(dt, self.state.game_speed);
        self.world.validate();
        self.camera.eye += self.world.player.position - old;
        for ref x in &self.world.bots {
            if self.world.player.crash(x) {
                self.state.ended = true;
            }
        }
    }
}

fn convert(x: [Vector2<f64>; 2]) -> [f64; 4] {
    [x[0].x, x[0].y, x[1].x, x[1].y]
}
<commit_msg>Fix bug<commit_after>use Pixel;
use world::World;
use piston_window::*;
use car::CarRules;
use camera::Camera;
use cgmath::{Vector3, Vector2};
use cgmath::prelude::*;
use color::*;
use rnd;
use car::Car;
use piston_window::Ellipse;

pub struct Game {
    config: GameConfig,
    world: World,
    window: PistonWindow,
    bot_rules: CarRules,
    camera: Camera,
    state: State,
}

struct State {
    pub turn: Turn,
    pub sprint: bool,
    pub spawn: f64,
    pub ended: bool,
    pub game_speed: f64,
    pub jump_timeout: f64,
    pub rotate_cam: bool,
    pub bullets: i64,
    pub recharge: f64,
}

pub enum Turn { Left, Right, None, }

pub struct GameConfig {
    pub title: &'static str,
    pub screen_size: Pixel,
    pub ups: u64,
    pub max_fps: u64,
    pub tunel_size: [f64; 3],
    pub player_size: [f64; 3],
    pub player_speed: (f64, f64),
    pub player_turn_speed: f64,
    pub bot_size: [(f64, f64); 3],
    pub bot_speed: (f64, f64),
    pub bot_turn_speed: (f64, f64),
    pub divider_size: [f64; 2],
    pub camera_height: f64,
    pub camera_distance: f64,
    pub decor_distance: f64,
    pub sprint_factor: f64,
    pub spawn_time: (f64, f64),
    pub game_sprint: f64,
    pub game_max_speed: f64,
    pub player_jump_v: f64,
    pub player_jump_a: f64,
    pub jump_turn_decrease: f64,
    pub jump_timeout: f64,
    pub mouse_speed: f64,
    pub trueshot_distance: f64,
    pub bullet_stock: i64,
    pub recharge_time: f64,
    pub bullet_len: f64,
    pub bullet_speed: f64,
}

impl Game {
    pub fn new(config: GameConfig) -> Game {
        let mut window: PistonWindow = WindowSettings::new(
            config.title, [config.screen_size.w, config.screen_size.h])
            .exit_on_esc(true).build().unwrap();
        window.set_ups(config.ups);
        window.set_max_fps(config.max_fps);
        window.set_capture_cursor(true);
        let bot_rules = CarRules {
            size: config.bot_size,
            position: [(0., config.tunel_size[0]), (0., 0.), (config.tunel_size[2], config.tunel_size[2])],
            speed: config.bot_speed,
            turn_speed: config.bot_turn_speed,
            color: vec![RED, ORANGE, VIOLET, GREEN, PALE],
            jump_turn_decrease: config.jump_turn_decrease,
        };
        let world = World::new(&config);
        let camera = Game::new_camera(&config, &world.player);
        let state = State {
            turn: Turn::None,
            sprint: false,
            spawn: 0.,
            ended: false,
            game_speed: 0.,
            jump_timeout: 0.,
            rotate_cam: false,
            bullets: config.bullet_stock,
            recharge: 0.,
        };
        Game {
            config: config,
            world: world,
            window: window,
            bot_rules: bot_rules,
            camera: camera,
            state: state,
        }
    }

    fn new_camera(config: &GameConfig, player: &Car) -> Camera {
        Camera::new(config.screen_size.clone(),
        Vector3::new(player.position.x,
                     config.camera_height + player.position.y,
                     player.position.z-config.camera_distance))
    }

    pub fn run(&mut self) {
        while let Some(e) = self.window.next() {
            match e {
                Input::Press(key) => self.press(key),
                Input::Release(key) => self.release(key),
                Input::Render(_) => self.draw(&e),
                Input::Update(args) => self.update(args.dt),
                Input::Move(Motion::MouseRelative(a, b)) => self.mouse_move(a as f64, b as f64),
                _ => {}
            }
            if self.state.ended {
                break;
            }
        }
    }

    fn mouse_move(&mut self, x: f64, y: f64) {
        if self.state.rotate_cam {
            self.camera.rotate(x*self.config.mouse_speed, y*self.config.mouse_speed, self.world.player.position);
        }
    }
    fn press(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => self.state.turn = Turn::Left,
            Button::Keyboard(Key::D) => self.state.turn = Turn::Right,
            Button::Keyboard(Key::W) => self.state.sprint = true,
            Button::Keyboard(Key::Space) => if self.state.jump_timeout <= 0. {
                self.state.jump_timeout = self.config.jump_timeout;
                self.world.player.start_jump();
            },
            Button::Mouse(MouseButton::Right) => {
                self.camera.zoom_in();
                self.state.rotate_cam = true;
            },
            Button::Mouse(MouseButton::Left) => if self.state.rotate_cam && self.state.bullets > 0 {
                let mut pos = self.world.player.position;
                pos.y += self.world.player.size.y;
                let mut d = Vector3::new(0., 0., self.config.trueshot_distance + self.config.camera_distance);
                d = self.camera.c * d.magnitude2() / d.dot(self.camera.c);
                d = self.camera.eye + d - pos;
                d = d * self.config.bullet_speed / d.magnitude();
                self.world.add_bullet(pos, d, self.config.bullet_len);
                self.state.bullets -= 1;
                if self.state.bullets <= 0 {
                    self.state.recharge = self.config.recharge_time;
                }
            },
            _ => (),
        }
    }
    fn release(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => if let Turn::Left = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::D) => if let Turn::Right = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::W) => self.state.sprint = false,
            Button::Mouse(MouseButton::Right) => {
                self.state.rotate_cam = false;
                self.camera = Game::new_camera(&self.config, &self.world.player);
            },
            _ => (),
        }
    }
    fn draw(&mut self, e: &Input) {
        let lines = self.world.render(&self.camera);
        let jump_bar = [
            0.,
            self.config.screen_size.h as f64 - 20.,
            self.config.screen_size.w as f64/2.*self.state.jump_timeout/self.config.jump_timeout,
            self.config.screen_size.h as f64,
        ];
        let recharge_bar = [
            0.,
            self.config.screen_size.h as f64 - 20.,
            self.config.screen_size.w as f64/2.*self.state.recharge/self.config.recharge_time,
            self.config.screen_size.h as f64,
        ];
        self.window.draw_2d(e, |c, g| {
            clear(BLACK, g);
            for (l, color) in lines {
                line(color, 1., convert(l), c.transform, g);
            }
            rectangle(pale(BLUE, 0.4), jump_bar, c.transform, g);
            rectangle(pale(RED, 0.4), recharge_bar, c.transform, g);
        });

        if self.state.rotate_cam {
            let w = 20.;
            let x = self.config.screen_size.w as f64 /2. - w/2.;
            let y = self.config.screen_size.h as f64 /2. - w/2.;
            self.window.draw_2d(e, |c, g| {
                let e = Ellipse {
                    color: pale(BLACK, 0.),
                    border: Some(ellipse::Border {
                        color: pale(RED, 0.5),
                        radius: 1.,
                    }),
                    resolution: 360,
                };
                e.draw([x, y, w, w], &c.draw_state, c.transform, g);
                rectangle(RED, [x+w/2.-1., y+w/2.-1., 2., 2.], c.transform, g);
            });
        }

    }
    fn update(&mut self, dt: f64) {
        let old = self.world.player.position;
        if self.state.bullets <= 0 {
            self.state.recharge -= dt;
            if self.state.recharge < 0. {
                self.state.bullets = self.config.bullet_stock;
            }
        }
        self.state.jump_timeout -= dt;
        if self.state.game_speed < self.config.game_max_speed {
            self.state.game_speed += dt*self.config.game_sprint;
        }
        if self.state.sprint {
            if self.world.player.speed < self.config.player_speed.1 {
                self.world.player.speed += dt*self.config.sprint_factor;
            }
        } else if self.world.player.speed > self.config.player_speed.0 {
            self.world.player.speed -= dt*self.config.sprint_factor;
        }
        self.state.spawn -= dt;
        if self.state.spawn < 0. {
            self.world.add_bot(&self.bot_rules);
            self.state.spawn += rnd(self.config.spawn_time);
        }
        self.world.player.turn(&self.state.turn, dt);
        self.world.update(dt, self.state.game_speed);
        self.world.validate();
        self.camera.eye += self.world.player.position - old;
        for ref x in &self.world.bots {
            if self.world.player.crash(x) {
                self.state.ended = true;
            }
        }
    }
}

fn convert(x: [Vector2<f64>; 2]) -> [f64; 4] {
    [x[0].x, x[0].y, x[1].x, x[1].y]
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul, Div, Neg};
use std::cmp::{Ordering};
use num::{Zero, One};
use num::traits::{Num};
use image::{Primitive, GenericImage, Pixel};
use {Anchor};

/// 2D geometric vector.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V2<T>(pub T, pub T);

impl<T: Eq> Eq for V2<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn add(self, rhs: V2<U>) -> V2<V> {
        V2(self.0 + rhs.0, self.1 + rhs.1)
    }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn sub(self, rhs: V2<U>) -> V2<V> {
        V2(self.0 - rhs.0, self.1 - rhs.1)
    }
}

impl<T: Neg<Output=U>, U> Neg<> for V2<T> {
    type Output = V2<U>;
    fn neg(self) -> V2<U> {
        V2(-self.0, -self.1)
    }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V2<T> {
    type Output = V2<V>;
    fn mul(self, rhs: U) -> V2<V> {
        V2(self.0 * rhs, self.1 * rhs)
    }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V2<T> {
    type Output = V2<V>;
    fn div(self, rhs: U) -> V2<V> {
        V2(self.0 / rhs, self.1 / rhs)
    }
}

impl<T> V2<T> {
    pub fn to_array(self) -> [T; 2] {
        [self.0, self.1]
    }
}

impl<T> V2<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V2<U> {
        V2(f(self.0), f(self.1))
    }
}

impl<T: Num> V2<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V2<T>) -> V2<T> {
        V2(self.0 * rhs.0, self.1 * rhs.1)
    }

    /// Componentwise division.
    pub fn div(self, rhs: V2<T>) -> V2<T> {
        V2(self.0 / rhs.0, self.1 / rhs.1)
    }

    /// Dot product.
    pub fn dot(self, rhs: V2<T>) -> T {
        self.0 * rhs.0 + self.1 * rhs.1
    }
}

impl<T: Ord+Copy> Ord for V2<T> {
    fn cmp(&self, other: &V2<T>) -> Ordering {
        (self.0, self.1).cmp(&(other.0, other.1))
    }
}

/// 3D geometric vector
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V3<T>(pub T, pub T, pub T);

impl<T: Eq> Eq for V3<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn add(self, rhs: V3<U>) -> V3<V> {
        V3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
    }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn sub(self, rhs: V3<U>) -> V3<V> {
        V3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
    }
}

impl<T: Neg<Output=U>, U> Neg<> for V3<T> {
    type Output = V3<U>;
    fn neg(self) -> V3<U> {
        V3(-self.0, -self.1, -self.2)
    }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V3<T> {
    type Output = V3<V>;
    fn mul(self, rhs: U) -> V3<V> {
        V3(self.0 * rhs, self.1 * rhs, self.2 * rhs)
    }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V3<T> {
    type Output = V3<V>;
    fn div(self, rhs: U) -> V3<V> {
        V3(self.0 / rhs, self.1 / rhs, self.2 / rhs)
    }
}

impl<T> V3<T> {
    pub fn to_array(self) -> [T; 3] {
        [self.0, self.1, self.2]
    }
}

impl<T> V3<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V3<U> {
        V3(f(self.0), f(self.1), f(self.2))
    }
}

impl<T: Num> V3<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V3<T>) -> V3<T> {
        V3(self.0 * rhs.0, self.1 * rhs.1, self.2 * rhs.2)
    }

    /// Componentwise division.
    pub fn div(self, rhs: V3<T>) -> V3<T> {
        V3(self.0 / rhs.0, self.1 / rhs.1, self.2 / rhs.2)
    }

    /// Dot product.
    pub fn dot(self, rhs: V3<T>) -> T {
        self.0 * rhs.0 + self.1 * rhs.1 + self.2 * rhs.2
    }
}

impl<T: Ord+Copy> Ord for V3<T> {
    fn cmp(&self, other: &V3<T>) -> Ordering {
        (self.0, self.1, self.2).cmp(&(other.0, other.1, other.2))
    }
}

/// A rectangle type consisting of position and size vectors.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct Rect<T>(pub V2<T>, pub V2<T>);

impl<T: Eq> Eq for Rect<T> { }

impl<T: Num+Copy+PartialOrd> Rect<T> {
    pub fn area(&self) -> T {
        (self.1).0 * (self.1).1
    }

    pub fn mn(&self) -> V2<T> {
        self.0
    }
    pub fn mx(&self) -> V2<T> {
        self.0 + self.1
    }
    pub fn dim(&self) -> V2<T> {
        self.1
    }

    pub fn point(&self, anchor: Anchor) -> V2<T> {
        let one: T = One::one();
        let two = one + one;
        //let two: T = One::one() + One::one();
        match anchor {
            Anchor::TopLeft => self.mn(),
            Anchor::TopRight => V2((self.0).0 + (self.1).0, (self.0).1),
            Anchor::BottomLeft => V2((self.0).0, (self.0).1 + (self.1).1),
            Anchor::BottomRight => self.mx(),
            Anchor::Top => V2((self.0).0 + (self.1).0 / two, (self.0).1),
            Anchor::Left => V2((self.0).0, (self.0).1 + (self.1).1 / two),
            Anchor::Right => V2((self.0).0 + (self.1).0, (self.0).1 + (self.1).1 / two),
            Anchor::Bottom => V2((self.0).0 + (self.1).0 / two, (self.0).1 + (self.1).1),
            Anchor::Center => V2((self.0).0 + (self.1).0 / two, (self.0).1 + (self.1).1 / two)
        }
    }

    /// Grow the rectangle to enclose point p.
    pub fn grow(&mut self, p: V2<T>) {
        let (mn, mx) = (self.mn(), self.mx());

        if p.0 < mn.0 {
            (self.1).0 = (self.1).0 + mn.0 - p.0;
            (self.0).0 = p.0;
        }

        if p.1 < mn.1 {
            (self.1).1 = (self.1).1 + mn.1 - p.1;
            (self.0).1 = p.1;
        }

        if p.0 > mx.0 { (self.1).0 = p.0 - mn.0; }

        if p.1 > mx.1 { (self.1).1 = p.1 - mn.1; }
    }

    pub fn intersects(&self, rhs: &Rect<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let (rmn, rmx) = (rhs.mn(), rhs.mx());

        !(mx.0 <= rmn.0 || mn.0 >= rmx.0 ||
          mx.1 <= rmn.1 || mn.1 >= rmx.1)
    }

    pub fn contains(&self, p: &V2<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        p.0 >= mn.0 && p.1 >= mn.1 && p.0 < mx.0 && p.1 < mx.1
    }

    pub fn edge_contains(&self, p: &V2<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let one = One::one();
        p.0 == mn.0 || p.1 == mn.1 || p.0 == mx.0 - one || p.1 == mx.1 - one
    }

    /// Return an iterator for all the points in the rectangle.
    pub fn iter(&self) -> RectIter<T> {
        RectIter {
            x: (self.0).0,
            y: (self.0).1,
            x0: (self.0).0,
            x1: (self.0).0 + (self.1).0,
            y1: (self.0).1 + (self.1).1,
        }
    }
}

impl<T: Add<U, Output=T> + Clone, U> Add<V2<U>> for Rect<T> {
    type Output = Rect<T>;
    fn add(self, rhs: V2<U>) -> Rect<T> {
        Rect(self.0 + rhs, self.1.clone())
    }
}

pub trait IterTiles<T> {
    /// Return an iterator of subtiles within self
    fn tiles(&self, tile_dim: V2<T>) -> TileIter<T>;
}

impl<T: Num+PartialOrd+Copy> IterTiles<T> for Rect<T> {
    fn tiles(&self, tile_dim: V2<T>) -> TileIter<T> {
        TileIter::new(*self, tile_dim)
    }
}

impl<I, P, T> IterTiles<u32> for I
    where I: GenericImage<Pixel=P>,
          P: Pixel<Subpixel=T>,
          T: Primitive
{
    fn tiles(&self, tile_dim: V2<u32>) -> TileIter<u32> {
        let (w, h) = self.dimensions();
        TileIter::new(Rect(V2(0, 0), V2(w, h)), tile_dim)
    }
}

/// Iterator for the integer points within a rectangle.
pub struct RectIter<T> {
    x: T,
    y: T,
    x0: T,
    x1: T,
    y1: T,
}

impl<T: Num+PartialOrd+Copy> Iterator for RectIter<T> {
    type Item = V2<T>;

    fn next(&mut self) -> Option<V2<T>> {
        if self.y >= self.y1 { return None; }
        let ret = Some(V2(self.x, self.y));
        self.x = self.x + One::one();
        if self.x >= self.x1 {
            self.x = self.x0;
            self.y = self.y + One::one();
        }
        ret
    }
}

/// Iterator for packed left-to-right top-to-bottom subrectangles
pub struct TileIter<T> {
    base: Rect<T>,
    tile_w: T,
    tile_h: T,
    x: T,
    y: T,
}

impl<T: Num+PartialOrd+Copy> TileIter<T> {
    pub fn new(base: Rect<T>, dim: V2<T>) -> TileIter<T> {
        assert!(dim.0 > Zero::zero() && dim.1 > Zero::zero());
        TileIter {
            base: base,
            tile_w: dim.0,
            tile_h: dim.1,
            x: Zero::zero(),
            y: Zero::zero()
        }
    }
}

impl<T: Num+PartialOrd+Copy> Iterator for TileIter<T> {
    type Item = Rect<T>;

    fn next(&mut self) -> Option<Rect<T>> {
        if self.tile_w > self.base.dim().0 { return None; }

        if (self.x + One::one()) * self.tile_w > self.base.dim().0 {
            self.y = self.y + One::one();
            self.x = Zero::zero();
        }

        if (self.y + One::one()) * self.tile_h > self.base.dim().1 {
            return None;
        }

        let ret = Rect(V2(self.x * self.tile_w, self.y * self.tile_h),
                       V2(self.tile_w, self.tile_h));
        self.x = self.x + One::one();
        Some(ret)
    }
}
<commit_msg>Sub op for Rect<commit_after>use std::ops::{Add, Sub, Mul, Div, Neg};
use std::cmp::{Ordering};
use num::{Zero, One};
use num::traits::{Num};
use image::{Primitive, GenericImage, Pixel};
use {Anchor};

/// 2D geometric vector.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V2<T>(pub T, pub T);

impl<T: Eq> Eq for V2<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn add(self, rhs: V2<U>) -> V2<V> {
        V2(self.0 + rhs.0, self.1 + rhs.1)
    }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn sub(self, rhs: V2<U>) -> V2<V> {
        V2(self.0 - rhs.0, self.1 - rhs.1)
    }
}

impl<T: Neg<Output=U>, U> Neg<> for V2<T> {
    type Output = V2<U>;
    fn neg(self) -> V2<U> {
        V2(-self.0, -self.1)
    }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V2<T> {
    type Output = V2<V>;
    fn mul(self, rhs: U) -> V2<V> {
        V2(self.0 * rhs, self.1 * rhs)
    }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V2<T> {
    type Output = V2<V>;
    fn div(self, rhs: U) -> V2<V> {
        V2(self.0 / rhs, self.1 / rhs)
    }
}

impl<T> V2<T> {
    pub fn to_array(self) -> [T; 2] {
        [self.0, self.1]
    }
}

impl<T> V2<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V2<U> {
        V2(f(self.0), f(self.1))
    }
}

impl<T: Num> V2<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V2<T>) -> V2<T> {
        V2(self.0 * rhs.0, self.1 * rhs.1)
    }

    /// Componentwise division.
    pub fn div(self, rhs: V2<T>) -> V2<T> {
        V2(self.0 / rhs.0, self.1 / rhs.1)
    }

    /// Dot product.
    pub fn dot(self, rhs: V2<T>) -> T {
        self.0 * rhs.0 + self.1 * rhs.1
    }
}

impl<T: Ord+Copy> Ord for V2<T> {
    fn cmp(&self, other: &V2<T>) -> Ordering {
        (self.0, self.1).cmp(&(other.0, other.1))
    }
}

/// 3D geometric vector
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V3<T>(pub T, pub T, pub T);

impl<T: Eq> Eq for V3<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn add(self, rhs: V3<U>) -> V3<V> {
        V3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
    }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn sub(self, rhs: V3<U>) -> V3<V> {
        V3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
    }
}

impl<T: Neg<Output=U>, U> Neg<> for V3<T> {
    type Output = V3<U>;
    fn neg(self) -> V3<U> {
        V3(-self.0, -self.1, -self.2)
    }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V3<T> {
    type Output = V3<V>;
    fn mul(self, rhs: U) -> V3<V> {
        V3(self.0 * rhs, self.1 * rhs, self.2 * rhs)
    }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V3<T> {
    type Output = V3<V>;
    fn div(self, rhs: U) -> V3<V> {
        V3(self.0 / rhs, self.1 / rhs, self.2 / rhs)
    }
}

impl<T> V3<T> {
    pub fn to_array(self) -> [T; 3] {
        [self.0, self.1, self.2]
    }
}

impl<T> V3<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V3<U> {
        V3(f(self.0), f(self.1), f(self.2))
    }
}

impl<T: Num> V3<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V3<T>) -> V3<T> {
        V3(self.0 * rhs.0, self.1 * rhs.1, self.2 * rhs.2)
    }

    /// Componentwise division.
    pub fn div(self, rhs: V3<T>) -> V3<T> {
        V3(self.0 / rhs.0, self.1 / rhs.1, self.2 / rhs.2)
    }

    /// Dot product.
    pub fn dot(self, rhs: V3<T>) -> T {
        self.0 * rhs.0 + self.1 * rhs.1 + self.2 * rhs.2
    }
}

impl<T: Ord+Copy> Ord for V3<T> {
    fn cmp(&self, other: &V3<T>) -> Ordering {
        (self.0, self.1, self.2).cmp(&(other.0, other.1, other.2))
    }
}

/// A rectangle type consisting of position and size vectors.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct Rect<T>(pub V2<T>, pub V2<T>);

impl<T: Eq> Eq for Rect<T> { }

impl<T: Num+Copy+PartialOrd> Rect<T> {
    pub fn area(&self) -> T {
        (self.1).0 * (self.1).1
    }

    pub fn mn(&self) -> V2<T> {
        self.0
    }
    pub fn mx(&self) -> V2<T> {
        self.0 + self.1
    }
    pub fn dim(&self) -> V2<T> {
        self.1
    }

    pub fn point(&self, anchor: Anchor) -> V2<T> {
        let one: T = One::one();
        let two = one + one;
        //let two: T = One::one() + One::one();
        match anchor {
            Anchor::TopLeft => self.mn(),
            Anchor::TopRight => V2((self.0).0 + (self.1).0, (self.0).1),
            Anchor::BottomLeft => V2((self.0).0, (self.0).1 + (self.1).1),
            Anchor::BottomRight => self.mx(),
            Anchor::Top => V2((self.0).0 + (self.1).0 / two, (self.0).1),
            Anchor::Left => V2((self.0).0, (self.0).1 + (self.1).1 / two),
            Anchor::Right => V2((self.0).0 + (self.1).0, (self.0).1 + (self.1).1 / two),
            Anchor::Bottom => V2((self.0).0 + (self.1).0 / two, (self.0).1 + (self.1).1),
            Anchor::Center => V2((self.0).0 + (self.1).0 / two, (self.0).1 + (self.1).1 / two)
        }
    }

    /// Grow the rectangle to enclose point p.
    pub fn grow(&mut self, p: V2<T>) {
        let (mn, mx) = (self.mn(), self.mx());

        if p.0 < mn.0 {
            (self.1).0 = (self.1).0 + mn.0 - p.0;
            (self.0).0 = p.0;
        }

        if p.1 < mn.1 {
            (self.1).1 = (self.1).1 + mn.1 - p.1;
            (self.0).1 = p.1;
        }

        if p.0 > mx.0 { (self.1).0 = p.0 - mn.0; }

        if p.1 > mx.1 { (self.1).1 = p.1 - mn.1; }
    }

    pub fn intersects(&self, rhs: &Rect<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let (rmn, rmx) = (rhs.mn(), rhs.mx());

        !(mx.0 <= rmn.0 || mn.0 >= rmx.0 ||
          mx.1 <= rmn.1 || mn.1 >= rmx.1)
    }

    pub fn contains(&self, p: &V2<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        p.0 >= mn.0 && p.1 >= mn.1 && p.0 < mx.0 && p.1 < mx.1
    }

    pub fn edge_contains(&self, p: &V2<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let one = One::one();
        p.0 == mn.0 || p.1 == mn.1 || p.0 == mx.0 - one || p.1 == mx.1 - one
    }

    /// Return an iterator for all the points in the rectangle.
    pub fn iter(&self) -> RectIter<T> {
        RectIter {
            x: (self.0).0,
            y: (self.0).1,
            x0: (self.0).0,
            x1: (self.0).0 + (self.1).0,
            y1: (self.0).1 + (self.1).1,
        }
    }
}

impl<T: Add<U, Output=T> + Clone, U> Add<V2<U>> for Rect<T> {
    type Output = Rect<T>;
    fn add(self, rhs: V2<U>) -> Rect<T> {
        Rect(self.0 + rhs, self.1.clone())
    }
}

impl<T: Sub<U, Output=T> + Clone, U> Sub<V2<U>> for Rect<T> {
    type Output = Rect<T>;
    fn sub(self, rhs: V2<U>) -> Rect<T> {
        Rect(self.0 - rhs, self.1.clone())
    }
}

pub trait IterTiles<T> {
    /// Return an iterator of subtiles within self
    fn tiles(&self, tile_dim: V2<T>) -> TileIter<T>;
}

impl<T: Num+PartialOrd+Copy> IterTiles<T> for Rect<T> {
    fn tiles(&self, tile_dim: V2<T>) -> TileIter<T> {
        TileIter::new(*self, tile_dim)
    }
}

impl<I, P, T> IterTiles<u32> for I
    where I: GenericImage<Pixel=P>,
          P: Pixel<Subpixel=T>,
          T: Primitive
{
    fn tiles(&self, tile_dim: V2<u32>) -> TileIter<u32> {
        let (w, h) = self.dimensions();
        TileIter::new(Rect(V2(0, 0), V2(w, h)), tile_dim)
    }
}

/// Iterator for the integer points within a rectangle.
pub struct RectIter<T> {
    x: T,
    y: T,
    x0: T,
    x1: T,
    y1: T,
}

impl<T: Num+PartialOrd+Copy> Iterator for RectIter<T> {
    type Item = V2<T>;

    fn next(&mut self) -> Option<V2<T>> {
        if self.y >= self.y1 { return None; }
        let ret = Some(V2(self.x, self.y));
        self.x = self.x + One::one();
        if self.x >= self.x1 {
            self.x = self.x0;
            self.y = self.y + One::one();
        }
        ret
    }
}

/// Iterator for packed left-to-right top-to-bottom subrectangles
pub struct TileIter<T> {
    base: Rect<T>,
    tile_w: T,
    tile_h: T,
    x: T,
    y: T,
}

impl<T: Num+PartialOrd+Copy> TileIter<T> {
    pub fn new(base: Rect<T>, dim: V2<T>) -> TileIter<T> {
        assert!(dim.0 > Zero::zero() && dim.1 > Zero::zero());
        TileIter {
            base: base,
            tile_w: dim.0,
            tile_h: dim.1,
            x: Zero::zero(),
            y: Zero::zero()
        }
    }
}

impl<T: Num+PartialOrd+Copy> Iterator for TileIter<T> {
    type Item = Rect<T>;

    fn next(&mut self) -> Option<Rect<T>> {
        if self.tile_w > self.base.dim().0 { return None; }

        if (self.x + One::one()) * self.tile_w > self.base.dim().0 {
            self.y = self.y + One::one();
            self.x = Zero::zero();
        }

        if (self.y + One::one()) * self.tile_h > self.base.dim().1 {
            return None;
        }

        let ret = Rect(V2(self.x * self.tile_w, self.y * self.tile_h),
                       V2(self.tile_w, self.tile_h));
        self.x = self.x + One::one();
        Some(ret)
    }
}
<|endoftext|>


<commit_before>//! GC heap allocator.

use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::{fmt, mem, ptr};
use bit_vec::BitVec;

// What does this do? You'll never guess!
type HeapId<'a> = PhantomData<::std::cell::Cell<&'a mut ()>>;

/// Total number of Pair objects that can be allocated in a Heap at once.
///
/// XXX BOGUS: At present, this is number is carefully selected (with insider
/// knowledge of both `size_of::<PairStorage>()` on my platform and the `Box`
/// allocator's behavior) so that a HeapStorage object fits in a page and thus
/// the assertions below about HEAP_STORAGE_ALIGN pass.
pub const HEAP_SIZE: usize = 125;

/// We rely on all bits to the right of this bit being 0 in addresses of
/// HeapStorage instances.
const HEAP_STORAGE_ALIGN: usize = 0x1000;

// The heap is (for now) just a big array of Pairs
struct HeapStorage<'a> {
    mark_bits: BitVec,
    mark_entry_point: unsafe fn(*mut ()),
    freelist: *mut PairStorage<'a>,
    objects: [PairStorage<'a>; HEAP_SIZE]
}

impl<'a> HeapStorage<'a> {
    unsafe fn new() -> Box<HeapStorage<'a>> {
        let mut storage = Box::new(HeapStorage {
            mark_bits: BitVec::from_elem(HEAP_SIZE, false),
            mark_entry_point: mark_entry_point::<PairStorage>,
            freelist: ptr::null_mut(),
            objects: mem::uninitialized()
        });

        // These assertions will likely fail on 32-bit platforms or if someone
        // is somehow using a custom Box allocator. If either one fails, this
        // GC will not work.
        assert_eq!(&mut *storage as *mut HeapStorage<'a> as usize & (HEAP_STORAGE_ALIGN - 1), 0);
        assert!(mem::size_of::<HeapStorage<'a>>() <= HEAP_STORAGE_ALIGN);

        for i in 0 .. HEAP_SIZE {
            let p = &mut storage.objects[i] as *mut PairStorage<'a>;
            storage.add_to_free_list(p);
        }
        storage
    }

    unsafe fn add_to_free_list(&mut self, p: *mut PairStorage<'a>) {
        let listp = p as *mut *mut PairStorage<'a>;
        *listp = self.freelist;
        assert_eq!(*listp, self.freelist);
        self.freelist = p;
    }

    unsafe fn try_alloc(&mut self) -> Option<*mut PairStorage<'a>> {
        let p = self.freelist;
        if p.is_null() {
            None
        } else {
            let listp = p as *mut *mut PairStorage<'a>;
            self.freelist = *listp;
            Some(p)
        }
    }

    unsafe fn sweep(&mut self) {
        self.freelist = ptr::null_mut();
        for i in 0 .. HEAP_SIZE {
            let p = &mut self.objects[i] as *mut PairStorage<'a>;
            if !self.mark_bits[i] {
                self.add_to_free_list(p);
            }
        }
    }
}

pub struct Heap<'a> {
    id: HeapId<'a>,
    storage: Box<HeapStorage<'a>>,
    pins: RefCell<HashMap<*mut (), usize>>
}

/// Create a heap, pass it to a callback, then destroy the heap.
///
/// The heap's lifetime is directly tied to this function call, for safety. (So
/// the API is a little wonky --- but how many heaps were you planning on
/// creating?)
pub fn with_heap<F, O>(f: F) -> O
    where F: for<'a> FnOnce(&mut Heap<'a>) -> O
{
    f(&mut Heap::new())
}

/// Trait implemented by all types that can be stored directly in the GC heap:
/// the `Storage` types associated with any `HeapInline` or `HeapRef` type.
///
/// XXX maybe this should not be its own trait - fold into HeapInline?
///
pub unsafe trait Mark<'a> {
    unsafe fn mark(ptr: *mut Self);
}

/// Non-inlined function that serves as an entry point to marking. This is used
/// for marking root set entries.
unsafe fn mark_entry_point<'a, T: Mark<'a>>(addr: *mut ()) {
    Mark::mark(addr as *mut T);
}

/// Trait implemented by all types that can be stored in fields of structs (or,
/// eventually, elements of GCVecs) that are stored in the GC heap.
pub unsafe trait HeapInline<'a> {
    /// The type of the value when it is physically stored in the heap.
    type Storage;

    /// Extract the value from the heap. Do not under any circumstances call
    /// this.  It is for macro-generated code to call; it is impossible for
    /// ordinary users to call this safely, because `ptr` must be a direct,
    /// unwrapped reference to a value stored in the GC heap, which ordinary
    /// users cannot obtain.
    ///
    /// This turns any raw pointers in the `Storage` value into safe
    /// references, so while it's a dangerous function, the result of a correct
    /// call can be safely handed out to user code.
    ///
    unsafe fn from_heap(heap: &Heap<'a>, ptr: &Self::Storage) -> Self;

    /// Convert the value to the form it should have in the heap.
    /// This is for macro-generated code to call.
    fn to_heap(self) -> Self::Storage;
}

impl<'a> Heap<'a> {
    fn new() -> Heap<'a> {
        Heap {
            id: PhantomData,
            storage: unsafe { HeapStorage::new() },
            pins: RefCell::new(HashMap::new())
        }
    }

    /// Add the object `*p` to the root set, protecting it from GC.
    ///
    /// An object that has been pinned *n* times stays in the root set
    /// until it has been unpinned *n* times.
    ///
    /// (Unsafe because if the argument is garbage, a later GC will
    /// crash. Called only from `impl PinnedRef`.)
    unsafe fn pin<T: Mark<'a>>(&self, p: *mut T) {
        let p = p as *mut ();
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p).or_insert(0);
        *entry += 1;
    }

    /// Unpin an object (see `pin`).
    ///
    /// (Unsafe because unpinning an object that other code is still using
    /// causes dangling pointers. Called only from `impl PinnedRef`.)
    unsafe fn unpin<T: Mark<'a>>(&self, p: *mut T) {
        let p = p as *mut ();
        let mut pins = self.pins.borrow_mut();
        if {
            let entry = pins.entry(p as *mut ()).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        } {
            pins.remove(&p);
        }
    }

    pub fn try_alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Option<Pair<'a>> {
        unsafe {
            self.storage.try_alloc()
                .or_else(|| {
                    self.gc();
                    self.storage.try_alloc()
                })
                .map(move |p| {
                    *p = PairStorage {
                        head: pair.0.to_heap(),
                        tail: pair.1.to_heap()
                    };
                    Pair(PinnedRef::new(self, p))
                })
        }
    }

    unsafe fn find_header<T>(_ptr: *const T) -> *mut HeapStorage<'a> {
        let storage_addr = _ptr as usize & !(HEAP_STORAGE_ALIGN - 1);
        storage_addr as *mut HeapStorage<'a>
    }

    unsafe fn find_mark_bit<T>(_ptr: *const T) -> (*mut BitVec, usize) {
        assert_eq!(mem::size_of::<T>(), mem::size_of::<PairStorage<'a>>());
        let storage = Heap::find_header(_ptr);
        let objects_addr = &mut (*storage).objects[0] as *mut PairStorage<'a> as usize;
        let index = (_ptr as usize - objects_addr) / mem::size_of::<PairStorage<'a>>();
        (&mut (*storage).mark_bits as *mut BitVec, index)
    }

    pub unsafe fn get_mark_bit<T>(_ptr: *const T) -> bool {
        let (bits, index) = Heap::find_mark_bit(_ptr);
        (*bits)[index]
    }

    pub unsafe fn set_mark_bit<T>(_ptr: *const T) {
        let (bits, index) = Heap::find_mark_bit(_ptr);
        (*bits).set(index, true);
    }

    pub fn alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Pair<'a> {
        self.try_alloc(pair).expect("out of memory (gc did not collect anything)")
    }

    pub fn alloc_null(&mut self) -> Pair<'a> {
        self.alloc((Value::Null, Value::Null))
    }

    unsafe fn mark(ptr: *mut ()) {
        let storage = Heap::find_header(ptr);
        let mark_fn = (*storage).mark_entry_point;
        mark_fn(ptr);
    }

    unsafe fn gc(&mut self) {
        // mark phase
        self.storage.mark_bits.clear();
        for (&p, _) in self.pins.borrow().iter() {
            Heap::mark(p);
        }

        // sweep phase
        self.storage.sweep();
    }

    #[cfg(test)]
    pub fn force_gc(&mut self) {
        unsafe { self.gc(); }
    }
}

pub struct PinnedRef<'a, T: Mark<'a>> {
    ptr: *mut T,
    heap: *const Heap<'a>,
    heap_id: HeapId<'a>
}

impl<'a, T: Mark<'a>> PinnedRef<'a, T> {
    /// Pin an object, returning a new `PinnedRef` that will unpin it when
    /// dropped. Unsafe because if `p` is not a pointer to a live allocation of
    /// type `T` --- and a complete allocation, not a sub-object of one --- then
    /// later unsafe code will explode.
    unsafe fn new(heap: &Heap<'a>, p: *mut T) -> PinnedRef<'a, T> {
        heap.pin(p);
        PinnedRef {
            ptr: p,
            heap: heap as *const Heap<'a>,
            heap_id: heap.id
        }
    }
}

impl<'a, T: Mark<'a>> Drop for PinnedRef<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (*self.heap).unpin(self.ptr);
        }
    }
}

impl<'a, T: Mark<'a>> Clone for PinnedRef<'a, T> {
    fn clone(&self) -> PinnedRef<'a, T> {
        let &PinnedRef { ptr, heap, heap_id } = self;
        unsafe {
            (*heap).pin(ptr);
        }
        PinnedRef {
            ptr: ptr,
            heap: heap,
            heap_id: heap_id
        }
    }
}

impl<'a, T: Mark<'a>> fmt::Debug for PinnedRef<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PinnedRef {{ ptr: {:p} }}", self.ptr)
    }
}

impl<'a, T: Mark<'a>> PartialEq for PinnedRef<'a, T> {
    fn eq(&self, other: &PinnedRef<'a, T>) -> bool {
        self.ptr == other.ptr
    }
}

impl<'a, T: Mark<'a>> Eq for PinnedRef<'a, T> {}

pub trait GCRef {
    #[cfg(test)]
    fn address(&self) -> usize;
}

unsafe impl<'a, T: Copy + 'static> Mark<'a> for T {
    unsafe fn mark(_ptr: *mut T) {}
}

unsafe impl<'a, T: Copy + 'static> HeapInline<'a> for T {
    type Storage = Self;

    fn to_heap(self) -> T { self }

    unsafe fn from_heap(_heap: &Heap<'a>, v: &T) -> T { *v }
}

// === Pair, the reference type

gc_ref_type! {
    pub struct Pair / PairStorage<'a> {
        head / set_head: Value<'a>,
        tail / set_tail: Value<'a>
    }
}

// === Values (a heap-inline enum)

use std::rc::Rc;

// Values inside the heap (GC heap-to-heap cross-references) (private)
enum ValueStorage<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),
    Pair(*mut PairStorage<'a>)
}

unsafe impl<'a> Mark<'a> for ValueStorage<'a> {
    unsafe fn mark(ptr: *mut ValueStorage<'a>) {
        match *ptr {
            ValueStorage::Pair(p) => Mark::mark(p),
            _ => {}
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),  // <-- equality is by value
    Pair(Pair<'a>)  // <-- equality is by pointer
}

unsafe impl<'a> HeapInline<'a> for Value<'a> {
    type Storage = ValueStorage<'a>;

    fn to_heap(self) -> ValueStorage<'a> {
        match self {
            Value::Null => ValueStorage::Null,
            Value::Int(n) => ValueStorage::Int(n),
            Value::Str(rcstr) => ValueStorage::Str(rcstr),
            Value::Pair(pair) => ValueStorage::Pair(HeapInline::<'a>::to_heap(pair))
        }
    }

    unsafe fn from_heap(heap: &Heap<'a>, v: &ValueStorage<'a>) -> Value<'a> {
        match v {
            &ValueStorage::Null => Value::Null,
            &ValueStorage::Int(n) => Value::Int(n),
            &ValueStorage::Str(ref rcstr) => Value::Str(rcstr.clone()),
            &ValueStorage::Pair(ref ptr) => Value::Pair(HeapInline::<'a>::from_heap(heap, ptr))
        }
    }
}

<commit_msg>Change freelist to be untyped.<commit_after>//! GC heap allocator.

use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::{fmt, mem, ptr};
use bit_vec::BitVec;

// What does this do? You'll never guess!
type HeapId<'a> = PhantomData<::std::cell::Cell<&'a mut ()>>;

/// Total number of Pair objects that can be allocated in a Heap at once.
///
/// XXX BOGUS: At present, this is number is carefully selected (with insider
/// knowledge of both `size_of::<PairStorage>()` on my platform and the `Box`
/// allocator's behavior) so that a HeapStorage object fits in a page and thus
/// the assertions below about HEAP_STORAGE_ALIGN pass.
pub const HEAP_SIZE: usize = 125;

/// We rely on all bits to the right of this bit being 0 in addresses of
/// HeapStorage instances.
const HEAP_STORAGE_ALIGN: usize = 0x1000;

// The heap is (for now) just a big array of Pairs
struct HeapStorage<'a> {
    mark_bits: BitVec,
    mark_entry_point: unsafe fn(*mut ()),
    freelist: *mut (),
    objects: [PairStorage<'a>; HEAP_SIZE]
}

impl<'a> HeapStorage<'a> {
    unsafe fn new() -> Box<HeapStorage<'a>> {
        let mut storage = Box::new(HeapStorage {
            mark_bits: BitVec::from_elem(HEAP_SIZE, false),
            mark_entry_point: mark_entry_point::<PairStorage>,
            freelist: ptr::null_mut(),
            objects: mem::uninitialized()
        });

        // These assertions will likely fail on 32-bit platforms or if someone
        // is somehow using a custom Box allocator. If either one fails, this
        // GC will not work.
        assert_eq!(&mut *storage as *mut HeapStorage<'a> as usize & (HEAP_STORAGE_ALIGN - 1), 0);
        assert!(mem::size_of::<HeapStorage<'a>>() <= HEAP_STORAGE_ALIGN);

        for i in 0 .. HEAP_SIZE {
            let p = &mut storage.objects[i] as *mut PairStorage<'a>;
            storage.add_to_free_list(p);
        }
        storage
    }

    unsafe fn add_to_free_list(&mut self, p: *mut PairStorage<'a>) {
        let listp = p as *mut *mut ();
        *listp = self.freelist;
        assert_eq!(*listp, self.freelist);
        self.freelist = p as *mut ();
    }

    unsafe fn try_alloc(&mut self) -> Option<*mut PairStorage<'a>> {
        let p = self.freelist;
        if p.is_null() {
            None
        } else {
            let listp = p as *mut *mut ();
            self.freelist = *listp;
            Some(p as *mut PairStorage<'a>)
        }
    }

    unsafe fn sweep(&mut self) {
        self.freelist = ptr::null_mut();
        for i in 0 .. HEAP_SIZE {
            let p = &mut self.objects[i] as *mut PairStorage<'a>;
            if !self.mark_bits[i] {
                self.add_to_free_list(p);
            }
        }
    }
}

pub struct Heap<'a> {
    id: HeapId<'a>,
    storage: Box<HeapStorage<'a>>,
    pins: RefCell<HashMap<*mut (), usize>>
}

/// Create a heap, pass it to a callback, then destroy the heap.
///
/// The heap's lifetime is directly tied to this function call, for safety. (So
/// the API is a little wonky --- but how many heaps were you planning on
/// creating?)
pub fn with_heap<F, O>(f: F) -> O
    where F: for<'a> FnOnce(&mut Heap<'a>) -> O
{
    f(&mut Heap::new())
}

/// Trait implemented by all types that can be stored directly in the GC heap:
/// the `Storage` types associated with any `HeapInline` or `HeapRef` type.
///
/// XXX maybe this should not be its own trait - fold into HeapInline?
///
pub unsafe trait Mark<'a> {
    unsafe fn mark(ptr: *mut Self);
}

/// Non-inlined function that serves as an entry point to marking. This is used
/// for marking root set entries.
unsafe fn mark_entry_point<'a, T: Mark<'a>>(addr: *mut ()) {
    Mark::mark(addr as *mut T);
}

/// Trait implemented by all types that can be stored in fields of structs (or,
/// eventually, elements of GCVecs) that are stored in the GC heap.
pub unsafe trait HeapInline<'a> {
    /// The type of the value when it is physically stored in the heap.
    type Storage;

    /// Extract the value from the heap. Do not under any circumstances call
    /// this.  It is for macro-generated code to call; it is impossible for
    /// ordinary users to call this safely, because `ptr` must be a direct,
    /// unwrapped reference to a value stored in the GC heap, which ordinary
    /// users cannot obtain.
    ///
    /// This turns any raw pointers in the `Storage` value into safe
    /// references, so while it's a dangerous function, the result of a correct
    /// call can be safely handed out to user code.
    ///
    unsafe fn from_heap(heap: &Heap<'a>, ptr: &Self::Storage) -> Self;

    /// Convert the value to the form it should have in the heap.
    /// This is for macro-generated code to call.
    fn to_heap(self) -> Self::Storage;
}

impl<'a> Heap<'a> {
    fn new() -> Heap<'a> {
        Heap {
            id: PhantomData,
            storage: unsafe { HeapStorage::new() },
            pins: RefCell::new(HashMap::new())
        }
    }

    /// Add the object `*p` to the root set, protecting it from GC.
    ///
    /// An object that has been pinned *n* times stays in the root set
    /// until it has been unpinned *n* times.
    ///
    /// (Unsafe because if the argument is garbage, a later GC will
    /// crash. Called only from `impl PinnedRef`.)
    unsafe fn pin<T: Mark<'a>>(&self, p: *mut T) {
        let p = p as *mut ();
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p).or_insert(0);
        *entry += 1;
    }

    /// Unpin an object (see `pin`).
    ///
    /// (Unsafe because unpinning an object that other code is still using
    /// causes dangling pointers. Called only from `impl PinnedRef`.)
    unsafe fn unpin<T: Mark<'a>>(&self, p: *mut T) {
        let p = p as *mut ();
        let mut pins = self.pins.borrow_mut();
        if {
            let entry = pins.entry(p as *mut ()).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        } {
            pins.remove(&p);
        }
    }

    pub fn try_alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Option<Pair<'a>> {
        unsafe {
            self.storage.try_alloc()
                .or_else(|| {
                    self.gc();
                    self.storage.try_alloc()
                })
                .map(move |p| {
                    *p = PairStorage {
                        head: pair.0.to_heap(),
                        tail: pair.1.to_heap()
                    };
                    Pair(PinnedRef::new(self, p))
                })
        }
    }

    unsafe fn find_header<T>(_ptr: *const T) -> *mut HeapStorage<'a> {
        let storage_addr = _ptr as usize & !(HEAP_STORAGE_ALIGN - 1);
        storage_addr as *mut HeapStorage<'a>
    }

    unsafe fn find_mark_bit<T>(_ptr: *const T) -> (*mut BitVec, usize) {
        assert_eq!(mem::size_of::<T>(), mem::size_of::<PairStorage<'a>>());
        let storage = Heap::find_header(_ptr);
        let objects_addr = &mut (*storage).objects[0] as *mut PairStorage<'a> as usize;
        let index = (_ptr as usize - objects_addr) / mem::size_of::<PairStorage<'a>>();
        (&mut (*storage).mark_bits as *mut BitVec, index)
    }

    pub unsafe fn get_mark_bit<T>(_ptr: *const T) -> bool {
        let (bits, index) = Heap::find_mark_bit(_ptr);
        (*bits)[index]
    }

    pub unsafe fn set_mark_bit<T>(_ptr: *const T) {
        let (bits, index) = Heap::find_mark_bit(_ptr);
        (*bits).set(index, true);
    }

    pub fn alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Pair<'a> {
        self.try_alloc(pair).expect("out of memory (gc did not collect anything)")
    }

    pub fn alloc_null(&mut self) -> Pair<'a> {
        self.alloc((Value::Null, Value::Null))
    }

    unsafe fn mark(ptr: *mut ()) {
        let storage = Heap::find_header(ptr);
        let mark_fn = (*storage).mark_entry_point;
        mark_fn(ptr);
    }

    unsafe fn gc(&mut self) {
        // mark phase
        self.storage.mark_bits.clear();
        for (&p, _) in self.pins.borrow().iter() {
            Heap::mark(p);
        }

        // sweep phase
        self.storage.sweep();
    }

    #[cfg(test)]
    pub fn force_gc(&mut self) {
        unsafe { self.gc(); }
    }
}

pub struct PinnedRef<'a, T: Mark<'a>> {
    ptr: *mut T,
    heap: *const Heap<'a>,
    heap_id: HeapId<'a>
}

impl<'a, T: Mark<'a>> PinnedRef<'a, T> {
    /// Pin an object, returning a new `PinnedRef` that will unpin it when
    /// dropped. Unsafe because if `p` is not a pointer to a live allocation of
    /// type `T` --- and a complete allocation, not a sub-object of one --- then
    /// later unsafe code will explode.
    unsafe fn new(heap: &Heap<'a>, p: *mut T) -> PinnedRef<'a, T> {
        heap.pin(p);
        PinnedRef {
            ptr: p,
            heap: heap as *const Heap<'a>,
            heap_id: heap.id
        }
    }
}

impl<'a, T: Mark<'a>> Drop for PinnedRef<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (*self.heap).unpin(self.ptr);
        }
    }
}

impl<'a, T: Mark<'a>> Clone for PinnedRef<'a, T> {
    fn clone(&self) -> PinnedRef<'a, T> {
        let &PinnedRef { ptr, heap, heap_id } = self;
        unsafe {
            (*heap).pin(ptr);
        }
        PinnedRef {
            ptr: ptr,
            heap: heap,
            heap_id: heap_id
        }
    }
}

impl<'a, T: Mark<'a>> fmt::Debug for PinnedRef<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PinnedRef {{ ptr: {:p} }}", self.ptr)
    }
}

impl<'a, T: Mark<'a>> PartialEq for PinnedRef<'a, T> {
    fn eq(&self, other: &PinnedRef<'a, T>) -> bool {
        self.ptr == other.ptr
    }
}

impl<'a, T: Mark<'a>> Eq for PinnedRef<'a, T> {}

pub trait GCRef {
    #[cfg(test)]
    fn address(&self) -> usize;
}

unsafe impl<'a, T: Copy + 'static> Mark<'a> for T {
    unsafe fn mark(_ptr: *mut T) {}
}

unsafe impl<'a, T: Copy + 'static> HeapInline<'a> for T {
    type Storage = Self;

    fn to_heap(self) -> T { self }

    unsafe fn from_heap(_heap: &Heap<'a>, v: &T) -> T { *v }
}

// === Pair, the reference type

gc_ref_type! {
    pub struct Pair / PairStorage<'a> {
        head / set_head: Value<'a>,
        tail / set_tail: Value<'a>
    }
}

// === Values (a heap-inline enum)

use std::rc::Rc;

// Values inside the heap (GC heap-to-heap cross-references) (private)
enum ValueStorage<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),
    Pair(*mut PairStorage<'a>)
}

unsafe impl<'a> Mark<'a> for ValueStorage<'a> {
    unsafe fn mark(ptr: *mut ValueStorage<'a>) {
        match *ptr {
            ValueStorage::Pair(p) => Mark::mark(p),
            _ => {}
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),  // <-- equality is by value
    Pair(Pair<'a>)  // <-- equality is by pointer
}

unsafe impl<'a> HeapInline<'a> for Value<'a> {
    type Storage = ValueStorage<'a>;

    fn to_heap(self) -> ValueStorage<'a> {
        match self {
            Value::Null => ValueStorage::Null,
            Value::Int(n) => ValueStorage::Int(n),
            Value::Str(rcstr) => ValueStorage::Str(rcstr),
            Value::Pair(pair) => ValueStorage::Pair(HeapInline::<'a>::to_heap(pair))
        }
    }

    unsafe fn from_heap(heap: &Heap<'a>, v: &ValueStorage<'a>) -> Value<'a> {
        match v {
            &ValueStorage::Null => Value::Null,
            &ValueStorage::Int(n) => Value::Int(n),
            &ValueStorage::Str(ref rcstr) => Value::Str(rcstr.clone()),
            &ValueStorage::Pair(ref ptr) => Value::Pair(HeapInline::<'a>::from_heap(heap, ptr))
        }
    }
}

<|endoftext|>