<commit_before>use core::f64::consts::pi;
use num::cast::*;
use vec::Vec3;

pub trait Angle<T>: Add<self,self>
                  , Sub<self,self>
                  , Mul<T,self>
                  , Div<T,self>
                  , Modulo<T,self>
                  , Neg<self> {
    pure fn to_radians() -> Radians<T>;
    pure fn to_degrees() -> Degrees<T>;
}

pub enum Radians<T> = T;

pub impl<T:Copy Num NumCast> Radians<T>: Angle<T> {
    #[inline(always)] pure fn to_radians() -> Radians<T> { self }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { Degrees(*self * cast(180.0 / pi)) }

    #[inline(always)] pure fn add(rhs: &Radians<T>) -> Radians<T> { self + *rhs }
    #[inline(always)] pure fn sub(rhs: &Radians<T>) -> Radians<T> { self - *rhs }
    #[inline(always)] pure fn mul(rhs: &T)          -> Radians<T> { self * *rhs }
    #[inline(always)] pure fn div(rhs: &T)          -> Radians<T> { self / *rhs }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Radians<T> { self % *rhs }
    #[inline(always)] pure fn neg()                 -> Radians<T> {-self }
}

pub enum Degrees<T> = T;

pub impl<T:Copy Num NumCast> Degrees<T>: Angle<T> {
    #[inline(always)] pure fn to_radians() -> Radians<T> { Radians(*self * cast(pi / 180.0)) }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { self }

    #[inline(always)] pure fn add(rhs: &Degrees<T>) -> Degrees<T> { self + *rhs }
    #[inline(always)] pure fn sub(rhs: &Degrees<T>) -> Degrees<T> { self - *rhs }
    #[inline(always)] pure fn mul(rhs: &T)          -> Degrees<T> { self * *rhs }
    #[inline(always)] pure fn div(rhs: &T)          -> Degrees<T> { self / *rhs }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Degrees<T> { self % *rhs }
    #[inline(always)] pure fn neg()                 -> Degrees<T> {-self }
}

pub struct AxisRotation<T> {
    axis: Vec3<T>,
    theta: Radians<T>,
}

pub struct Euler<T> {
    x: Radians<T>,   // pitch
    y: Radians<T>,   // yaw
    z: Radians<T>,   // roll
}<commit_msg>Fix operator overloads<commit_after>use core::f64::consts::pi;
use num::cast::*;
use vec::Vec3;

pub trait Angle<T>: Add<self,self>
                  , Sub<self,self>
                  , Mul<T,self>
                  , Div<T,self>
                  , Modulo<T,self>
                  , Neg<self> {
    pure fn to_radians() -> Radians<T>;
    pure fn to_degrees() -> Degrees<T>;
}

pub enum Radians<T> = T;

pub impl<T:Copy Num NumCast> Radians<T>: Angle<T> {
    #[inline(always)] pure fn to_radians() -> Radians<T> { self }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { Degrees(*self * cast(180.0 / pi)) }

    #[inline(always)] pure fn add(rhs: &Radians<T>) -> Radians<T> { Radians(*self + **rhs) }
    #[inline(always)] pure fn sub(rhs: &Radians<T>) -> Radians<T> { Radians(*self - **rhs) }
    #[inline(always)] pure fn mul(rhs: &T)          -> Radians<T> { Radians(*self * *rhs) }
    #[inline(always)] pure fn div(rhs: &T)          -> Radians<T> { Radians(*self / *rhs) }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Radians<T> { Radians(*self % *rhs) }
    #[inline(always)] pure fn neg()                 -> Radians<T> { Radians(-*self) }
}

pub enum Degrees<T> = T;

pub impl<T:Copy Num NumCast> Degrees<T>: Angle<T> {
    #[inline(always)] pure fn to_radians() -> Radians<T> { Radians(*self * cast(pi / 180.0)) }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { self }

    #[inline(always)] pure fn add(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self + **rhs) }
    #[inline(always)] pure fn sub(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self - **rhs) }
    #[inline(always)] pure fn mul(rhs: &T)          -> Degrees<T> { Degrees(*self * *rhs) }
    #[inline(always)] pure fn div(rhs: &T)          -> Degrees<T> { Degrees(*self / *rhs) }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Degrees<T> { Degrees(*self % *rhs) }
    #[inline(always)] pure fn neg()                 -> Degrees<T> { Degrees(-*self) }
}

pub struct AxialRotation<T> {
    axis: Vec3<T>,
    theta: Radians<T>,
}

pub struct Euler<T> {
    x: Radians<T>,   // pitch
    y: Radians<T>,   // yaw
    z: Radians<T>,   // roll
}<|endoftext|>


<commit_before>#[macro_use]
extern crate bencher;
extern crate kdtree;
extern crate rand;

use bencher::Bencher;

#[derive(Copy, Clone, PartialEq)]
pub struct Point2WithId {
    dims: [f64; 2],
    pub id: i32,
}

impl Point2WithId {
    pub fn new(id: i32, x: f64, y: f64) -> Point2WithId {
        Point2WithId {
            dims: [x, y],
            id: id,
        }
    }
}

impl kdtree::kdtree::KdtreePointTrait for Point2WithId {
    fn dims(&self) -> &[f64] {
        return &self.dims;
    }
}

#[derive(Copy, Clone, PartialEq)]
pub struct Point3WithId {
    dims: [f64; 3],
    pub id: i32,
}

impl Point3WithId {
    pub fn new(id: i32, x: f64, y: f64, z: f64) -> Point3WithId {
        Point3WithId {
            dims: [x, y, z],
            id: id,
        }
    }
}

impl kdtree::kdtree::KdtreePointTrait for Point3WithId {
    fn dims(&self) -> &[f64] {
        return &self.dims;
    }
}

fn a(b: &mut Bencher) {
    let len = 1000usize;
    let mut points : Vec<Point2WithId> = vec![];
    //let mut kdtree = KdTree::new_with_capacity(3, 16);
    for id in 0..len {
        let x : f64 = rand::random();
        points.push(Point2WithId::new(id as i32, x, x));
        //   points.push(rand_data());
    }

    b.iter(|| {
        let tree = kdtree::kdtree::Kdtree::new(points.clone());
    });
}

fn b(b: &mut Bencher) {
    let len = 1000usize;
    let mut points : Vec<Point3WithId> = vec![];
    //let mut kdtree = KdTree::new_with_capacity(3, 16);

    for i in 0..len {
        points.push(Point3WithId::new(i as i32, rand::random(),rand::random(),rand::random()))

    }

    let tree = kdtree::kdtree::Kdtree::new(points.clone());

    b.iter(||  tree.nearest_search(&points[0]));
}

benchmark_group!(benches, a,b);
benchmark_main!(benches);<commit_msg>renamed benches<commit_after>#[macro_use]
extern crate bencher;
extern crate kdtree;
extern crate rand;

use bencher::Bencher;

#[derive(Copy, Clone, PartialEq)]
pub struct Point2WithId {
    dims: [f64; 2],
    pub id: i32,
}

impl Point2WithId {
    pub fn new(id: i32, x: f64, y: f64) -> Point2WithId {
        Point2WithId {
            dims: [x, y],
            id: id,
        }
    }
}

impl kdtree::kdtree::KdtreePointTrait for Point2WithId {
    fn dims(&self) -> &[f64] {
        return &self.dims;
    }
}

#[derive(Copy, Clone, PartialEq)]
pub struct Point3WithId {
    dims: [f64; 3],
    pub id: i32,
}

impl Point3WithId {
    pub fn new(id: i32, x: f64, y: f64, z: f64) -> Point3WithId {
        Point3WithId {
            dims: [x, y, z],
            id: id,
        }
    }
}

impl kdtree::kdtree::KdtreePointTrait for Point3WithId {
    fn dims(&self) -> &[f64] {
        return &self.dims;
    }
}

fn bench_creating_1000_node_tree(b: &mut Bencher) {
    let len = 1000usize;
    let mut points : Vec<Point2WithId> = vec![];
    //let mut kdtree = KdTree::new_with_capacity(3, 16);
    for id in 0..len {
        let x : f64 = rand::random();
        points.push(Point2WithId::new(id as i32, x, x));
        //   points.push(rand_data());
    }

    b.iter(|| {
        let tree = kdtree::kdtree::Kdtree::new(points.clone());
    });
}

fn bench_single_loop_times_for_1000_node_tree(b: &mut Bencher) {
    let len = 1000usize;
    let mut points : Vec<Point3WithId> = vec![];
    //let mut kdtree = KdTree::new_with_capacity(3, 16);

    for i in 0..len {
        points.push(Point3WithId::new(i as i32, rand::random(),rand::random(),rand::random()))

    }

    let tree = kdtree::kdtree::Kdtree::new(points.clone());

    b.iter(||  tree.nearest_search(&points[0]));
}

benchmark_group!(benches, a,b);
benchmark_main!(benches);<|endoftext|>


<commit_before>use std::collections::HashSet;
use rand::random;
use graphics::*;
use opengl_graphics::{ GlGraphics };
use number_renderer::NumberRenderer;
use settings::Settings;
use tile::{ Tile, TileState };

fn rgb2rgba(c: [f32; 3]) -> [f32; 4] { [c[0], c[1], c[2], 1.0] }

pub struct Board<'a> {
    tiles: Vec<Tile<'a>>,
    score: i32,
    settings: &'a Settings,
}

impl<'a> Board<'a> {
    pub fn new(settings: &'a Settings) -> Board<'a> {
        let mut board = Board {
            tiles: Vec::<Tile>::new(),
            score: 0,
            settings: settings,
        };
        board.generate_tile();
        board.generate_tile();
        board
    }

    pub fn generate_tile(&mut self) {
        if self.tiles.len() == (self.settings.tile_width * self.settings.tile_height) as usize {
            return;
        }

        loop {
            let x = (random::<u32>() % self.settings.tile_width as u32) as i32;
            let y = (random::<u32>() % self.settings.tile_height as u32) as i32;

            if self.get_tile(x, y).is_none() {
                self.tiles.push(Tile::new(self.settings, 2, x, y));
                break;
            }
        }
    }

    pub fn update(&mut self, dt: f64) {
        for tile in self.tiles.iter_mut() {
            tile.update(dt);
        }

        if self.is_locking() {
            return;
        }

        let mut score_to_added = 0;
        let mut tiles_need_removed = HashSet::<usize>::new();
        let mut tiles_need_added = Vec::<Tile>::new();

        for i in 0..self.tiles.len() {
            let tile1 = &self.tiles[i];

            if tile1.status != TileState::TileStatic {
                continue;
            }

            for j in i+1..self.tiles.len() {
                let tile2 = &self.tiles[j];

                if tile2.status != TileState::TileStatic
                  || tile1.tile_x != tile2.tile_x
                  || tile1.tile_y != tile2.tile_y {
                    continue;
                }

                tiles_need_removed.insert(i);
                tiles_need_removed.insert(j);
                tiles_need_added.push(Tile::new_combined(self.settings, tile1.score + tile2.score, tile1.tile_x, tile1.tile_y));
                score_to_added += tile1.score + tile2.score;
                break;
            }
        }

        if tiles_need_removed.len() > 0 {
            let mut tiles = Vec::<Tile>::new();

            for i in 0..self.tiles.len() {
                if !tiles_need_removed.contains(&i) {
                    tiles.push(self.tiles[i].clone());
                }
            }

            // better but unstable:          tiles.append(&mut tiles_need_added);
            while let Some(tile_to_add) = tiles_need_added.pop() {
                tiles.push(tile_to_add);
            }

            self.tiles = tiles;
            self.add_score(score_to_added);
        }
    }

    pub fn render(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut GlGraphics) {
        number_renderer.render(
            self.score as u32,
            self.settings.best_rect[0] + self.settings.best_rect[2] / 2.0,
            self.settings.best_rect[1] + self.settings.best_rect[3] / 2.0,
            self.settings.best_rect[2],
            self.settings.text_light_color, c, gl);

        self.render_board(c, gl);
        self.render_tiles(number_renderer, c, gl);
    }

    pub fn merge_from_bottom_to_top(&mut self) {
        let height = self.settings.tile_height;
        self.merge_col(0, height, 1);
    }

    pub fn merge_from_top_to_bottom(&mut self) {
        let height = self.settings.tile_height;
        self.merge_col(height - 1, -1, -1);
    }

    fn merge_col(&mut self, y_start: i32, y_end: i32, y_step: i32) {
        if self.is_locking() {
            println!("return");
            return;
        }

        let mut need_generate = false;
        let mut steps: Vec<i32> = Vec::with_capacity(self.settings.tile_height as usize);

        let mut next_step = y_start;

        if y_step < 0 {
            while next_step > y_end {
                steps.push(next_step); next_step += y_step
            }
        } else {
            while next_step < y_end {
                steps.push(next_step); next_step += y_step
            }
        }

        loop {
            // move all tiles to right place
            for col in 0 .. self.settings.tile_width {
                // TODO: replace steps by (y_start .. y_end).step_by(y_step) if step_by becomes stable
                for row  in steps.to_vec() {
                    match self.get_mut_tile(col, row) {
                        None => {
                            match self.get_mut_next_tile(col, row, 0, y_step) {
                                Some(ref mut tile) => {
                                    println!("move ({}, {}) to ({}, {})",
                                        tile.tile_x, tile.tile_y, col, row);
                                    need_generate = true;
                                    tile.start_moving(col, row);
                                },
                                _ => {},
                            }
                        },
                        _ => {},
                    }
                }
            }

            let mut did_merged = false;
            for col in 0..self.settings.tile_width {
                let mut found = false;
                let mut sx = 0;
                let mut sy = 0;
                let mut dx = 0;
                let mut dy = 0;
                for row  in steps.to_vec() {
                    match self.get_tile(col, row) {
                        Some(ref d_tile) => {
                            match self.get_next_tile(col, row, 0, y_step) {
                                Some(ref s_tile)
                                if d_tile.score == s_tile.score
                                && self.get_tile_count(d_tile.tile_x, d_tile.tile_y) == 1 => {
                                    found = true;
                                    dx = d_tile.tile_x;
                                    dy = d_tile.tile_y;
                                    sx = s_tile.tile_x;
                                    sy = s_tile.tile_y;
                                    break;
                                },
                                _ => {},
                            }
                        },
                        None => {
                            break;
                        }
                    }
                }

                if found {
                    need_generate = true;
                    did_merged = true;
                    let tile = self.get_mut_tile(sx, sy).unwrap();
                    tile.start_moving(dx, dy);
                    println!("merge ({}, {}) to ({}, {})", sx, sy, dx, dy);
                }
            }

            if !did_merged {
                break;
            }
        }

        if need_generate {
            self.generate_tile();
        }
    }

    pub fn merge_from_left_to_right(&mut self) {
        let width = self.settings.tile_width;
        self.merge_row(width - 1, -1, -1);
    }

    pub fn merge_from_right_to_left(&mut self) {
        let width = self.settings.tile_width;
        self.merge_row(0, width, 1);
    }

    fn merge_row(&mut self, x_start: i32, x_end: i32, x_step: i32) {
        if self.is_locking() {
            return;
        }

        let mut need_generate = false;
        let mut steps: Vec<i32> = Vec::with_capacity(self.settings.tile_width as usize);
        let mut next_step = x_start;

        if x_step < 0 {
            while next_step > x_end {
                steps.push(next_step); next_step += x_step
            }
        } else {
            while next_step < x_end {
                steps.push(next_step); next_step += x_step
            }
        }

        loop {
            // move all tiles to right place
            for row in 0..self.settings.tile_height {
                for col  in steps.to_vec() {
                    match self.get_mut_tile(col, row) {
                        None => {
                            match self.get_mut_next_tile(col, row, x_step, 0) {
                                Some(ref mut tile) => {
                                    println!("move ({}, {}) to ({}, {})", tile.tile_x, tile.tile_y, col, row);
                                    need_generate = true;
                                    tile.start_moving(col, row);
                                },
                                _ => {},
                            }
                        },
                        _ => {},
                    }
                }
            }

            // merge
            let mut did_merged = false;
            for row in 0..self.settings.tile_height {
                let mut found = false;
                let mut sx = 0;
                let mut sy = 0;
                let mut dx = 0;
                let mut dy = 0;
                for col in steps.to_vec() {
                    match self.get_tile(col, row) {
                        Some(ref d_tile) => {
                            match self.get_next_tile(col, row, x_step, 0) {
                                Some(ref s_tile)
                                if d_tile.score == s_tile.score
                                && self.get_tile_count(d_tile.tile_x, d_tile.tile_y) == 1 => {
                                    found = true;
                                    dx = d_tile.tile_x;
                                    dy = d_tile.tile_y;
                                    sx = s_tile.tile_x;
                                    sy = s_tile.tile_y;
                                    break;
                                },
                                _ => {},
                            }
                        },
                        None => {
                            break;
                        }
                    }
                }

                if found {
                    need_generate = true;
                    did_merged = true;
                    let tile = self.get_mut_tile(sx, sy).unwrap();
                    tile.start_moving(dx, dy);
                    println!("merge ({}, {}) to ({}, {})", sx, sy, dx, dy);
                }
            }

            if !did_merged {
                break;
            }
        }

        if need_generate {
            self.generate_tile();
        }
    }

    fn is_locking(&self) -> bool {
        for tile in self.tiles.iter() {
            if tile.status != TileState::TileStatic {
                return true;
            }
        }
        false
    }

    /// Returns next tile right besides (x, y)
    fn get_next_tile<'b>(&'b self, x: i32, y: i32, step_x: i32, step_y: i32) -> Option<&'b Tile<'a>> {
        let mut x = x + step_x;
        let mut y = y + step_y;
        while x >= 0 && x < self.settings.tile_width
        && y >= 0 && y < self.settings.tile_height {
            let tile = self.get_tile(x, y);
            if tile.is_some() {
                return tile;
            }
            x += step_x;
            y += step_y;
        }
        None
    }

    fn get_mut_next_tile<'b>(&'b mut self, x: i32, y: i32, step_x: i32, step_y: i32) -> Option<&'b mut Tile<'a>> {
        let mut x = x + step_x;
        let mut y = y + step_y;
        let mut found = false;
        while x >= 0 && x < self.settings.tile_width
        && y >= 0 && y < self.settings.tile_height {
            let tile = self.get_tile(x, y);

            if tile.is_some() {
                found = true;
                break;
            }
            x += step_x;
            y += step_y;
        }

        if found {
            self.get_mut_tile(x, y)
        } else {
            None
        }
    }

    fn get_tile<'b>(&'b self, x: i32, y: i32) -> Option<&'b Tile<'a>> {
        for tile in self.tiles.iter() {
            if tile.tile_x == x && tile.tile_y == y {
                return Some(tile);
            }
        }

        None
    }

    fn get_mut_tile<'b>(&'b mut self, x: i32, y: i32) -> Option<&'b mut Tile<'a>> {
        for tile in self.tiles.iter_mut() {
            if tile.tile_x == x && tile.tile_y == y {
                return Some(tile);
            }
        }

        None
    }

    fn get_tile_count(&self, x: i32, y: i32) -> i32 {
        let mut count = 0;
        for tile in self.tiles.iter() {
            if tile.tile_x == x && tile.tile_y == y {
                count += 1;
            }
        }

        count
    }

    fn render_board(&self, c: &Context, gl: &mut GlGraphics) {
        Rectangle::new(rgb2rgba(self.settings.label_color))
        .draw(
            [self.settings.board_padding,
            self.settings.board_padding + self.settings.board_offset_y,
            self.settings.board_size[0],
            self.settings.board_size[1]],
            default_draw_state(),
            c.transform,
            gl);

        let mut x = self.settings.board_padding + self.settings.tile_padding;
        let mut y = self.settings.board_padding + self.settings.board_offset_y + self.settings.tile_padding;

        for _ in 0..self.settings.tile_height {
            for _ in 0..self.settings.tile_width {
                Rectangle::new(
                    rgb2rgba(self.settings.tiles_colors[0]))
                    .draw([x, y, self.settings.tile_size, self.settings.tile_size],
                    default_draw_state(),
                    c.transform,
                    gl);

                x += self.settings.tile_padding + self.settings.tile_size;
            }

            x = self.settings.board_padding + self.settings.tile_padding;
            y += self.settings.tile_padding + self.settings.tile_size;
        }
    }

    fn render_tiles(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut GlGraphics) {
        for tile in self.tiles.iter() {
            tile.render(number_renderer, c, gl);
        }
    }

    fn add_score(&mut self, score: i32) {
        self.score += score;
        println!("Score: {}", self.score);
    }
}
<commit_msg>Randomly generate 2 or 4 tile<commit_after>use std::collections::HashSet;
use rand::random;
use graphics::*;
use opengl_graphics::{ GlGraphics };
use number_renderer::NumberRenderer;
use settings::Settings;
use tile::{ Tile, TileState };

fn rgb2rgba(c: [f32; 3]) -> [f32; 4] { [c[0], c[1], c[2], 1.0] }

pub struct Board<'a> {
    tiles: Vec<Tile<'a>>,
    score: i32,
    settings: &'a Settings,
}

impl<'a> Board<'a> {
    pub fn new(settings: &'a Settings) -> Board<'a> {
        let mut board = Board {
            tiles: Vec::<Tile>::new(),
            score: 0,
            settings: settings,
        };
        board.generate_tile();
        board.generate_tile();
        board
    }

    pub fn generate_tile(&mut self) {
        if self.tiles.len() == (self.settings.tile_width * self.settings.tile_height) as usize {
            return;
        }

        loop {
            let x = (random::<u32>() % self.settings.tile_width as u32) as i32;
            let y = (random::<u32>() % self.settings.tile_height as u32) as i32;

            if self.get_tile(x, y).is_none() {
                let score = if random::<u32>() % 2 == 0 {
                    2
                } else {
                    4
                };
                self.tiles.push(Tile::new(self.settings, score, x, y));
                break;
            }
        }
    }

    pub fn update(&mut self, dt: f64) {
        for tile in self.tiles.iter_mut() {
            tile.update(dt);
        }

        if self.is_locking() {
            return;
        }

        let mut score_to_added = 0;
        let mut tiles_need_removed = HashSet::<usize>::new();
        let mut tiles_need_added = Vec::<Tile>::new();

        for i in 0..self.tiles.len() {
            let tile1 = &self.tiles[i];

            if tile1.status != TileState::TileStatic {
                continue;
            }

            for j in i+1..self.tiles.len() {
                let tile2 = &self.tiles[j];

                if tile2.status != TileState::TileStatic
                  || tile1.tile_x != tile2.tile_x
                  || tile1.tile_y != tile2.tile_y {
                    continue;
                }

                tiles_need_removed.insert(i);
                tiles_need_removed.insert(j);
                tiles_need_added.push(Tile::new_combined(self.settings, tile1.score + tile2.score, tile1.tile_x, tile1.tile_y));
                score_to_added += tile1.score + tile2.score;
                break;
            }
        }

        if tiles_need_removed.len() > 0 {
            let mut tiles = Vec::<Tile>::new();

            for i in 0..self.tiles.len() {
                if !tiles_need_removed.contains(&i) {
                    tiles.push(self.tiles[i].clone());
                }
            }

            // better but unstable:          tiles.append(&mut tiles_need_added);
            while let Some(tile_to_add) = tiles_need_added.pop() {
                tiles.push(tile_to_add);
            }

            self.tiles = tiles;
            self.add_score(score_to_added);
        }
    }

    pub fn render(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut GlGraphics) {
        number_renderer.render(
            self.score as u32,
            self.settings.best_rect[0] + self.settings.best_rect[2] / 2.0,
            self.settings.best_rect[1] + self.settings.best_rect[3] / 2.0,
            self.settings.best_rect[2],
            self.settings.text_light_color, c, gl);

        self.render_board(c, gl);
        self.render_tiles(number_renderer, c, gl);
    }

    pub fn merge_from_bottom_to_top(&mut self) {
        let height = self.settings.tile_height;
        self.merge_col(0, height, 1);
    }

    pub fn merge_from_top_to_bottom(&mut self) {
        let height = self.settings.tile_height;
        self.merge_col(height - 1, -1, -1);
    }

    fn merge_col(&mut self, y_start: i32, y_end: i32, y_step: i32) {
        if self.is_locking() {
            println!("return");
            return;
        }

        let mut need_generate = false;
        let mut steps: Vec<i32> = Vec::with_capacity(self.settings.tile_height as usize);

        let mut next_step = y_start;

        if y_step < 0 {
            while next_step > y_end {
                steps.push(next_step); next_step += y_step
            }
        } else {
            while next_step < y_end {
                steps.push(next_step); next_step += y_step
            }
        }

        loop {
            // move all tiles to right place
            for col in 0 .. self.settings.tile_width {
                // TODO: replace steps by (y_start .. y_end).step_by(y_step) if step_by becomes stable
                for row  in steps.to_vec() {
                    match self.get_mut_tile(col, row) {
                        None => {
                            match self.get_mut_next_tile(col, row, 0, y_step) {
                                Some(ref mut tile) => {
                                    println!("move ({}, {}) to ({}, {})",
                                        tile.tile_x, tile.tile_y, col, row);
                                    need_generate = true;
                                    tile.start_moving(col, row);
                                },
                                _ => {},
                            }
                        },
                        _ => {},
                    }
                }
            }

            let mut did_merged = false;
            for col in 0..self.settings.tile_width {
                let mut found = false;
                let mut sx = 0;
                let mut sy = 0;
                let mut dx = 0;
                let mut dy = 0;
                for row  in steps.to_vec() {
                    match self.get_tile(col, row) {
                        Some(ref d_tile) => {
                            match self.get_next_tile(col, row, 0, y_step) {
                                Some(ref s_tile)
                                if d_tile.score == s_tile.score
                                && self.get_tile_count(d_tile.tile_x, d_tile.tile_y) == 1 => {
                                    found = true;
                                    dx = d_tile.tile_x;
                                    dy = d_tile.tile_y;
                                    sx = s_tile.tile_x;
                                    sy = s_tile.tile_y;
                                    break;
                                },
                                _ => {},
                            }
                        },
                        None => {
                            break;
                        }
                    }
                }

                if found {
                    need_generate = true;
                    did_merged = true;
                    let tile = self.get_mut_tile(sx, sy).unwrap();
                    tile.start_moving(dx, dy);
                    println!("merge ({}, {}) to ({}, {})", sx, sy, dx, dy);
                }
            }

            if !did_merged {
                break;
            }
        }

        if need_generate {
            self.generate_tile();
        }
    }

    pub fn merge_from_left_to_right(&mut self) {
        let width = self.settings.tile_width;
        self.merge_row(width - 1, -1, -1);
    }

    pub fn merge_from_right_to_left(&mut self) {
        let width = self.settings.tile_width;
        self.merge_row(0, width, 1);
    }

    fn merge_row(&mut self, x_start: i32, x_end: i32, x_step: i32) {
        if self.is_locking() {
            return;
        }

        let mut need_generate = false;
        let mut steps: Vec<i32> = Vec::with_capacity(self.settings.tile_width as usize);
        let mut next_step = x_start;

        if x_step < 0 {
            while next_step > x_end {
                steps.push(next_step); next_step += x_step
            }
        } else {
            while next_step < x_end {
                steps.push(next_step); next_step += x_step
            }
        }

        loop {
            // move all tiles to right place
            for row in 0..self.settings.tile_height {
                for col  in steps.to_vec() {
                    match self.get_mut_tile(col, row) {
                        None => {
                            match self.get_mut_next_tile(col, row, x_step, 0) {
                                Some(ref mut tile) => {
                                    println!("move ({}, {}) to ({}, {})", tile.tile_x, tile.tile_y, col, row);
                                    need_generate = true;
                                    tile.start_moving(col, row);
                                },
                                _ => {},
                            }
                        },
                        _ => {},
                    }
                }
            }

            // merge
            let mut did_merged = false;
            for row in 0..self.settings.tile_height {
                let mut found = false;
                let mut sx = 0;
                let mut sy = 0;
                let mut dx = 0;
                let mut dy = 0;
                for col in steps.to_vec() {
                    match self.get_tile(col, row) {
                        Some(ref d_tile) => {
                            match self.get_next_tile(col, row, x_step, 0) {
                                Some(ref s_tile)
                                if d_tile.score == s_tile.score
                                && self.get_tile_count(d_tile.tile_x, d_tile.tile_y) == 1 => {
                                    found = true;
                                    dx = d_tile.tile_x;
                                    dy = d_tile.tile_y;
                                    sx = s_tile.tile_x;
                                    sy = s_tile.tile_y;
                                    break;
                                },
                                _ => {},
                            }
                        },
                        None => {
                            break;
                        }
                    }
                }

                if found {
                    need_generate = true;
                    did_merged = true;
                    let tile = self.get_mut_tile(sx, sy).unwrap();
                    tile.start_moving(dx, dy);
                    println!("merge ({}, {}) to ({}, {})", sx, sy, dx, dy);
                }
            }

            if !did_merged {
                break;
            }
        }

        if need_generate {
            self.generate_tile();
        }
    }

    fn is_locking(&self) -> bool {
        for tile in self.tiles.iter() {
            if tile.status != TileState::TileStatic {
                return true;
            }
        }
        false
    }

    /// Returns next tile right besides (x, y)
    fn get_next_tile<'b>(&'b self, x: i32, y: i32, step_x: i32, step_y: i32) -> Option<&'b Tile<'a>> {
        let mut x = x + step_x;
        let mut y = y + step_y;
        while x >= 0 && x < self.settings.tile_width
        && y >= 0 && y < self.settings.tile_height {
            let tile = self.get_tile(x, y);
            if tile.is_some() {
                return tile;
            }
            x += step_x;
            y += step_y;
        }
        None
    }

    fn get_mut_next_tile<'b>(&'b mut self, x: i32, y: i32, step_x: i32, step_y: i32) -> Option<&'b mut Tile<'a>> {
        let mut x = x + step_x;
        let mut y = y + step_y;
        let mut found = false;
        while x >= 0 && x < self.settings.tile_width
        && y >= 0 && y < self.settings.tile_height {
            let tile = self.get_tile(x, y);

            if tile.is_some() {
                found = true;
                break;
            }
            x += step_x;
            y += step_y;
        }

        if found {
            self.get_mut_tile(x, y)
        } else {
            None
        }
    }

    fn get_tile<'b>(&'b self, x: i32, y: i32) -> Option<&'b Tile<'a>> {
        for tile in self.tiles.iter() {
            if tile.tile_x == x && tile.tile_y == y {
                return Some(tile);
            }
        }

        None
    }

    fn get_mut_tile<'b>(&'b mut self, x: i32, y: i32) -> Option<&'b mut Tile<'a>> {
        for tile in self.tiles.iter_mut() {
            if tile.tile_x == x && tile.tile_y == y {
                return Some(tile);
            }
        }

        None
    }

    fn get_tile_count(&self, x: i32, y: i32) -> i32 {
        let mut count = 0;
        for tile in self.tiles.iter() {
            if tile.tile_x == x && tile.tile_y == y {
                count += 1;
            }
        }

        count
    }

    fn render_board(&self, c: &Context, gl: &mut GlGraphics) {
        Rectangle::new(rgb2rgba(self.settings.label_color))
        .draw(
            [self.settings.board_padding,
            self.settings.board_padding + self.settings.board_offset_y,
            self.settings.board_size[0],
            self.settings.board_size[1]],
            default_draw_state(),
            c.transform,
            gl);

        let mut x = self.settings.board_padding + self.settings.tile_padding;
        let mut y = self.settings.board_padding + self.settings.board_offset_y + self.settings.tile_padding;

        for _ in 0..self.settings.tile_height {
            for _ in 0..self.settings.tile_width {
                Rectangle::new(
                    rgb2rgba(self.settings.tiles_colors[0]))
                    .draw([x, y, self.settings.tile_size, self.settings.tile_size],
                    default_draw_state(),
                    c.transform,
                    gl);

                x += self.settings.tile_padding + self.settings.tile_size;
            }

            x = self.settings.board_padding + self.settings.tile_padding;
            y += self.settings.tile_padding + self.settings.tile_size;
        }
    }

    fn render_tiles(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut GlGraphics) {
        for tile in self.tiles.iter() {
            tile.render(number_renderer, c, gl);
        }
    }

    fn add_score(&mut self, score: i32) {
        self.score += score;
        println!("Score: {}", self.score);
    }
}
<|endoftext|>


<commit_before>use super::*;
use crate::borrow::Cow::{Borrowed, Owned};
use crate::collections::hash_map::DefaultHasher;
use crate::hash::{Hash, Hasher};
use crate::os::raw::c_char;
use crate::rc::Rc;
use crate::sync::Arc;

#[test]
fn c_to_rust() {
    let data = b"123\0";
    let ptr = data.as_ptr() as *const c_char;
    unsafe {
        assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123");
        assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0");
    }
}

#[test]
fn simple() {
    let s = CString::new("1234").unwrap();
    assert_eq!(s.as_bytes(), b"1234");
    assert_eq!(s.as_bytes_with_nul(), b"1234\0");
}

#[test]
fn build_with_zero1() {
    assert!(CString::new(&b"\0"[..]).is_err());
}
#[test]
fn build_with_zero2() {
    assert!(CString::new(vec![0]).is_err());
}

#[test]
fn build_with_zero3() {
    unsafe {
        let s = CString::from_vec_unchecked(vec![0]);
        assert_eq!(s.as_bytes(), b"\0");
    }
}

#[test]
fn formatted() {
    let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
    assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
}

#[test]
fn borrowed() {
    unsafe {
        let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
        assert_eq!(s.to_bytes(), b"12");
        assert_eq!(s.to_bytes_with_nul(), b"12\0");
    }
}

#[test]
fn to_str() {
    let data = b"123\xE2\x80\xA6\0";
    let ptr = data.as_ptr() as *const c_char;
    unsafe {
        assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
    }
    let data = b"123\xE2\0";
    let ptr = data.as_ptr() as *const c_char;
    unsafe {
        assert!(CStr::from_ptr(ptr).to_str().is_err());
        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
    }
}

#[test]
fn to_owned() {
    let data = b"123\0";
    let ptr = data.as_ptr() as *const c_char;

    let owned = unsafe { CStr::from_ptr(ptr).to_owned() };
    assert_eq!(owned.as_bytes_with_nul(), data);
}

#[test]
fn equal_hash() {
    let data = b"123\xE2\xFA\xA6\0";
    let ptr = data.as_ptr() as *const c_char;
    let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };

    let mut s = DefaultHasher::new();
    cstr.hash(&mut s);
    let cstr_hash = s.finish();
    let mut s = DefaultHasher::new();
    CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s);
    let cstring_hash = s.finish();

    assert_eq!(cstr_hash, cstring_hash);
}

#[test]
fn from_bytes_with_nul() {
    let data = b"123\0";
    let cstr = CStr::from_bytes_with_nul(data);
    assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..]));
    let cstr = CStr::from_bytes_with_nul(data);
    assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..]));

    unsafe {
        let cstr = CStr::from_bytes_with_nul(data);
        let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data);
        assert_eq!(cstr, Ok(cstr_unchecked));
    }
}

#[test]
fn from_bytes_with_nul_unterminated() {
    let data = b"123";
    let cstr = CStr::from_bytes_with_nul(data);
    assert!(cstr.is_err());
}

#[test]
fn from_bytes_with_nul_interior() {
    let data = b"1\023\0";
    let cstr = CStr::from_bytes_with_nul(data);
    assert!(cstr.is_err());
}

#[test]
fn into_boxed() {
    let orig: &[u8] = b"Hello, world!\0";
    let cstr = CStr::from_bytes_with_nul(orig).unwrap();
    let boxed: Box<CStr> = Box::from(cstr);
    let cstring = cstr.to_owned().into_boxed_c_str().into_c_string();
    assert_eq!(cstr, &*boxed);
    assert_eq!(&*boxed, &*cstring);
    assert_eq!(&*cstring, cstr);
}

#[test]
fn boxed_default() {
    let boxed = <Box<CStr>>::default();
    assert_eq!(boxed.to_bytes_with_nul(), &[0]);
}

#[test]
fn test_c_str_clone_into() {
    let mut c_string = CString::new("lorem").unwrap();
    let c_ptr = c_string.as_ptr();
    let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap();
    c_str.clone_into(&mut c_string);
    assert_eq!(c_str, c_string.as_c_str());
    // The exact same size shouldn't have needed to move its allocation
    assert_eq!(c_ptr, c_string.as_ptr());
}

#[test]
fn into_rc() {
    let orig: &[u8] = b"Hello, world!\0";
    let cstr = CStr::from_bytes_with_nul(orig).unwrap();
    let rc: Rc<CStr> = Rc::from(cstr);
    let arc: Arc<CStr> = Arc::from(cstr);

    assert_eq!(&*rc, cstr);
    assert_eq!(&*arc, cstr);

    let rc2: Rc<CStr> = Rc::from(cstr.to_owned());
    let arc2: Arc<CStr> = Arc::from(cstr.to_owned());

    assert_eq!(&*rc2, cstr);
    assert_eq!(&*arc2, cstr);
}

#[test]
fn cstr_const_constructor() {
    const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") };

    assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
}

#[test]
fn cstr_index_from() {
    let original = b"Hello, world!\0";
    let cstr = CStr::from_bytes_with_nul(original).unwrap();
    let result = CStr::from_bytes_with_nul(&original[7..]).unwrap();

    assert_eq!(&cstr[7..], result);
}

#[test]
#[should_panic]
fn cstr_index_from_empty() {
    let original = b"Hello, world!\0";
    let cstr = CStr::from_bytes_with_nul(original).unwrap();
    let _ = &cstr[original.len()..];
}
<commit_msg>ffi::c_str added tests for empty strings<commit_after>use super::*;
use crate::borrow::Cow::{Borrowed, Owned};
use crate::collections::hash_map::DefaultHasher;
use crate::hash::{Hash, Hasher};
use crate::os::raw::c_char;
use crate::rc::Rc;
use crate::sync::Arc;

#[test]
fn c_to_rust() {
    let data = b"123\0";
    let ptr = data.as_ptr() as *const c_char;
    unsafe {
        assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123");
        assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0");
    }
}

#[test]
fn simple() {
    let s = CString::new("1234").unwrap();
    assert_eq!(s.as_bytes(), b"1234");
    assert_eq!(s.as_bytes_with_nul(), b"1234\0");
}

#[test]
fn build_with_zero1() {
    assert!(CString::new(&b"\0"[..]).is_err());
}
#[test]
fn build_with_zero2() {
    assert!(CString::new(vec![0]).is_err());
}

#[test]
fn build_with_zero3() {
    unsafe {
        let s = CString::from_vec_unchecked(vec![0]);
        assert_eq!(s.as_bytes(), b"\0");
    }
}

#[test]
fn formatted() {
    let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
    assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
}

#[test]
fn borrowed() {
    unsafe {
        let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
        assert_eq!(s.to_bytes(), b"12");
        assert_eq!(s.to_bytes_with_nul(), b"12\0");
    }
}

#[test]
fn to_str() {
    let data = b"123\xE2\x80\xA6\0";
    let ptr = data.as_ptr() as *const c_char;
    unsafe {
        assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
    }
    let data = b"123\xE2\0";
    let ptr = data.as_ptr() as *const c_char;
    unsafe {
        assert!(CStr::from_ptr(ptr).to_str().is_err());
        assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
    }
}

#[test]
fn to_owned() {
    let data = b"123\0";
    let ptr = data.as_ptr() as *const c_char;

    let owned = unsafe { CStr::from_ptr(ptr).to_owned() };
    assert_eq!(owned.as_bytes_with_nul(), data);
}

#[test]
fn equal_hash() {
    let data = b"123\xE2\xFA\xA6\0";
    let ptr = data.as_ptr() as *const c_char;
    let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };

    let mut s = DefaultHasher::new();
    cstr.hash(&mut s);
    let cstr_hash = s.finish();
    let mut s = DefaultHasher::new();
    CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s);
    let cstring_hash = s.finish();

    assert_eq!(cstr_hash, cstring_hash);
}

#[test]
fn from_bytes_with_nul() {
    let data = b"123\0";
    let cstr = CStr::from_bytes_with_nul(data);
    assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..]));
    let cstr = CStr::from_bytes_with_nul(data);
    assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..]));

    unsafe {
        let cstr = CStr::from_bytes_with_nul(data);
        let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data);
        assert_eq!(cstr, Ok(cstr_unchecked));
    }
}

#[test]
fn from_bytes_with_nul_unterminated() {
    let data = b"123";
    let cstr = CStr::from_bytes_with_nul(data);
    assert!(cstr.is_err());
}

#[test]
fn from_bytes_with_nul_interior() {
    let data = b"1\023\0";
    let cstr = CStr::from_bytes_with_nul(data);
    assert!(cstr.is_err());
}

#[test]
fn into_boxed() {
    let orig: &[u8] = b"Hello, world!\0";
    let cstr = CStr::from_bytes_with_nul(orig).unwrap();
    let boxed: Box<CStr> = Box::from(cstr);
    let cstring = cstr.to_owned().into_boxed_c_str().into_c_string();
    assert_eq!(cstr, &*boxed);
    assert_eq!(&*boxed, &*cstring);
    assert_eq!(&*cstring, cstr);
}

#[test]
fn boxed_default() {
    let boxed = <Box<CStr>>::default();
    assert_eq!(boxed.to_bytes_with_nul(), &[0]);
}

#[test]
fn test_c_str_clone_into() {
    let mut c_string = CString::new("lorem").unwrap();
    let c_ptr = c_string.as_ptr();
    let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap();
    c_str.clone_into(&mut c_string);
    assert_eq!(c_str, c_string.as_c_str());
    // The exact same size shouldn't have needed to move its allocation
    assert_eq!(c_ptr, c_string.as_ptr());
}

#[test]
fn into_rc() {
    let orig: &[u8] = b"Hello, world!\0";
    let cstr = CStr::from_bytes_with_nul(orig).unwrap();
    let rc: Rc<CStr> = Rc::from(cstr);
    let arc: Arc<CStr> = Arc::from(cstr);

    assert_eq!(&*rc, cstr);
    assert_eq!(&*arc, cstr);

    let rc2: Rc<CStr> = Rc::from(cstr.to_owned());
    let arc2: Arc<CStr> = Arc::from(cstr.to_owned());

    assert_eq!(&*rc2, cstr);
    assert_eq!(&*arc2, cstr);
}

#[test]
fn cstr_const_constructor() {
    const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") };

    assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
}

#[test]
fn cstr_index_from() {
    let original = b"Hello, world!\0";
    let cstr = CStr::from_bytes_with_nul(original).unwrap();
    let result = CStr::from_bytes_with_nul(&original[7..]).unwrap();

    assert_eq!(&cstr[7..], result);
}

#[test]
#[should_panic]
fn cstr_index_from_empty() {
    let original = b"Hello, world!\0";
    let cstr = CStr::from_bytes_with_nul(original).unwrap();
    let _ = &cstr[original.len()..];
}

#[test]
fn c_string_from_empty_string() {
    let original = "";
    let cstring = CString::new(original).unwrap();
    assert_eq!(original.as_bytes(), cstring.as_bytes());
    assert_eq!([b'\0'], cstring.as_bytes_with_nul());
}

#[test]
fn c_str_from_empty_string() {
    let original = b"\0";
    let cstr = CStr::from_bytes_with_nul(original).unwrap();
    assert_eq!([] as [u8; 0], cstr.to_bytes());
    assert_eq!([b'\0'], cstr.to_bytes_with_nul());
}
<|endoftext|>


<commit_before>use std::io::TempDir;
use schema;
use buffer;

#[deriving(Show, Eq, Hash)]
struct Register {
	record: schema::Record,
}

impl Register {
	fn new(rec: schema::Record) -> Register {
		Register {
			record: rec,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str(&self) -> ~str {
		// TODO
		~"TODO"
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan<'a, 'b> {
	relation: schema::Relation,
	segment: &'a mut schema::SPSegment<'b>,
	current: uint,
}

impl<'a, 'b> TableScan<'a, 'b> {
	fn new(rel: schema::Relation, seg: &'a mut schema::SPSegment<'b>) -> TableScan<'a, 'b> {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl<'a, 'b> Operatorish<Vec<Register>> for TableScan<'a, 'b> {
}

impl<'a, 'b> Iterator<Vec<Register>> for TableScan<'a, 'b> {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let tup = self.relation.get(self.segment, self.current);
			let mut res = tup.move_iter().map(|e| Register::new(e)).
				collect::<Vec<Register>>();
			println!("res: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

/*
impl Ord for TableScan {
	fn lt(&self, other: &TableScan) -> bool {
		// TODO
		true
	}
}
*/

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));

	let mut ts = TableScan::new(relation, &mut seg);
	for tuple in ts {
		println!("Got entry {:?}", tuple);
	}

	assert!(false);
}
<commit_msg>Skeleton of Print operator<commit_after>use std::io::TempDir;
use schema;
use buffer;

#[deriving(Show, Eq, Hash)]
struct Register {
	record: schema::Record,
}

impl Register {
	fn new(rec: schema::Record) -> Register {
		Register {
			record: rec,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str(&self) -> ~str {
		// TODO
		~"TODO"
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan<'a, 'b> {
	relation: schema::Relation,
	segment: &'a mut schema::SPSegment<'b>,
	current: uint,
}

impl<'a, 'b> TableScan<'a, 'b> {
	fn new(rel: schema::Relation, seg: &'a mut schema::SPSegment<'b>) -> TableScan<'a, 'b> {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl<'a, 'b> Operatorish<Vec<Register>> for TableScan<'a, 'b> {
}

impl<'a, 'b> Iterator<Vec<Register>> for TableScan<'a, 'b> {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let tup = self.relation.get(self.segment, self.current);
			let mut res = tup.move_iter().map(|e| Register::new(e)).
				collect::<Vec<Register>>();
			println!("res: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<T, V> {
	input: T,
	output: V,
}

impl<T: Operatorish<Vec<Register>>, V: Writer> Print<T, V> {
	fn new(input: T, output: V) -> Print<T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<T: Operatorish<Vec<Register>>, V: Writer> Iterator<()> for Print<T, V> {
	fn next(&mut self) -> Option<()> {
		// TODO
		None
	}
}

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));

	let mut ts = TableScan::new(relation, &mut seg);
	for tuple in ts {
		println!("Got entry {}", tuple);
	}

	assert!(false);
}
<|endoftext|>


<commit_before>use crate::config::*;
use crate::errors::RunError;
use cargo_metadata::{diagnostic::DiagnosticLevel, CargoOpt, Message, MetadataCommand};
use log::{error, info, trace, warn};
use std::collections::HashMap;
use std::env;
use std::path::{Component, Path, PathBuf};
use std::process::{Command, Stdio};
use walkdir::{DirEntry, WalkDir};

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TestBinary {
    path: PathBuf,
    ty: RunType,
    cargo_dir: Option<PathBuf>,
    pkg_name: Option<String>,
    pkg_version: Option<String>,
    pkg_authors: Option<Vec<String>>,
    should_panic: bool,
}

impl TestBinary {
    pub fn new(path: PathBuf, ty: RunType) -> Self {
        Self {
            path,
            ty,
            pkg_name: None,
            pkg_version: None,
            pkg_authors: None,
            cargo_dir: None,
            should_panic: false,
        }
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn run_type(&self) -> RunType {
        self.ty
    }

    pub fn manifest_dir(&self) -> &Option<PathBuf> {
        &self.cargo_dir
    }

    pub fn pkg_name(&self) -> &Option<String> {
        &self.pkg_name
    }

    pub fn pkg_version(&self) -> &Option<String> {
        &self.pkg_version
    }

    pub fn pkg_authors(&self) -> &Option<Vec<String>> {
        &self.pkg_authors
    }

    /// Should be `false` for normal tests and for doctests either `true` or
    /// `false` depending on the test attribute
    pub fn should_panic(&self) -> bool {
        self.should_panic
    }
}

pub fn get_tests(config: &Config) -> Result<Vec<TestBinary>, RunError> {
    let mut result = vec![];
    let manifest = match config.manifest.as_path().to_str() {
        Some(s) => s,
        None => "Cargo.toml",
    };
    let metadata = MetadataCommand::new()
        .manifest_path(manifest)
        .features(CargoOpt::AllFeatures)
        .exec()
        .map_err(|e| RunError::Cargo(e.to_string()))?;

    for ty in &config.run_types {
        let mut cmd = create_command(manifest, config, ty);
        if ty != &RunType::Doctests {
            cmd.stdout(Stdio::piped());
        } else {
            cmd.stdout(Stdio::null());
        }
        if !config.verbose {
            cmd.stderr(Stdio::null());
        }
        trace!("Running command {:?}", cmd);
        let mut child = cmd.spawn().map_err(|e| RunError::Cargo(e.to_string()))?;

        if ty != &RunType::Doctests {
            let mut package_ids = vec![];
            let reader = std::io::BufReader::new(child.stdout.take().unwrap());
            for msg in Message::parse_stream(reader) {
                match msg {
                    Ok(Message::CompilerArtifact(art)) => {
                        if let Some(path) = art.executable {
                            if !art.profile.test && ty == &RunType::Tests {
                                continue;
                            }
                            result.push(TestBinary::new(path, *ty));
                            package_ids.push(art.package_id.clone());
                        }
                    }
                    Ok(Message::CompilerMessage(m)) => match m.message.level {
                        DiagnosticLevel::Error | DiagnosticLevel::Ice => {
                            let _ = child.wait();
                            return Err(RunError::TestCompile(m.message.message));
                        }
                        _ => {}
                    },
                    Err(e) => {
                        error!("Error parsing cargo messages {}", e);
                    }
                    _ => {}
                }
            }
            for (res, package) in result.iter_mut().zip(package_ids.iter()) {
                let package = &metadata[package];
                res.cargo_dir = package.manifest_path.parent().map(|x| x.to_path_buf());
                res.pkg_name = Some(package.name.clone());
                res.pkg_version = Some(package.version.to_string());
                res.pkg_authors = Some(package.authors.clone());
            }
            child.wait().map_err(|e| RunError::Cargo(e.to_string()))?;
        } else {
            // need to wait for compiling to finish before getting doctests
            // also need to wait with output to ensure the stdout buffer doesn't fill up
            let out = child
                .wait_with_output()
                .map_err(|e| RunError::Cargo(e.to_string()))?;
            if !out.status.success() {
                error!("Building doctests failed");
            }
            let walker = WalkDir::new(&config.doctest_dir()).into_iter();
            let dir_entries = walker
                .filter_map(|e| e.ok())
                .filter(|e| match e.metadata() {
                    Ok(ref m) if m.is_file() && m.len() != 0 => true,
                    _ => false,
                })
                .collect::<Vec<_>>();

            let should_panics = get_panic_candidates(&dir_entries, config);
            for dt in &dir_entries {
                trace!("Found doctest binary {}", dt.path().display());
                result.push(TestBinary::new(dt.path().to_path_buf(), *ty));
            }
        }
    }
    Ok(result)
}

fn convert_to_prefix(p: &Path) -> Option<String> {
    p.to_str()
        .map(|s| s.replace(std::path::MAIN_SEPARATOR, "_").replace(".", "_"))
}

fn is_prefix_match(prefix: &str, entry: &Path) -> bool {
    convert_to_prefix(entry)
        .map(|s| prefix.starts_with(&s))
        .unwrap_or(false)
}

/// This returns a map of the string prefixes for the file in the doc test and a list of lines
/// which contain the string `should_panic` it makes no guarantees that all these lines are a
/// doctest attribute showing panic behaviour (but some of them will be)
///
/// Currently all doctest files take the pattern of `{name}_{line}_{number}` where name is the
/// path to the file with directory separators and dots replaced with underscores. Therefore
/// each name could potentially map to many files as `src_some_folder_foo_rs_0_1` could go to
/// `src/some/folder_foo.rs` or `src/some/folder/foo.rs` here we're going to work on a heuristic
/// that any matching file is good because we can't do any better
fn get_panic_candidates(tests: &[DirEntry], config: &Config) -> HashMap<String, Vec<usize>> {
    let mut result = HashMap::new();
    let root = config.root();
    let target = config.target_dir();
    for test in tests {
        let test_name = test.path().components().nth_back(1);
        if let Some(Component::Normal(s)) = test_name {
            let s = s.to_string_lossy();
            let end = match s.rfind("rs") {
                Some(i) => i + 2,
                None => continue,
            };
            let walker = WalkDir::new(&root).into_iter();
            // TODO some walkdir stuff is being reused here and in source_analysis (and source
            // analysis does it a bit wrong) Fix before merging
            for dir_entry in walker
                .filter_entry(|e| {
                    !(e.path().starts_with(&target)
                        || e.path()
                            .iter()
                            .any(|x| x.to_string_lossy().starts_with(".")))
                })
                .filter_map(|e| e.ok())
            {
                let path = dir_entry.path();
                if path.is_file() {
                    if let Some(p) = path_relative_from(path, &root) {
                        if is_prefix_match(&s[..end], &p) {
                            trace!("Assessing {} for `should_panic` doctests", path.display());
                        }
                    }
                }
            }
        } else {
            warn!(
                "Invalid characters in name of doctest {}",
                test.path().display()
            );
        }
    }
    result
}

fn create_command(manifest_path: &str, config: &Config, ty: &RunType) -> Command {
    let mut test_cmd = Command::new("cargo");
    if *ty == RunType::Doctests {
        if let Some(toolchain) = env::var("RUSTUP_TOOLCHAIN")
            .ok()
            .filter(|t| t.starts_with("nightly"))
        {
            test_cmd.args(&[format!("+{}", toolchain).as_str(), "test"]);
        } else {
            test_cmd.args(&["+nightly", "test"]);
        }
    } else {
        if let Ok(toolchain) = env::var("RUSTUP_TOOLCHAIN") {
            test_cmd.arg(format!("+{}", toolchain));
        }
        test_cmd.args(&["test", "--no-run"]);
    }
    test_cmd.args(&["--message-format", "json", "--manifest-path", manifest_path]);
    match ty {
        RunType::Tests => test_cmd.arg("--tests"),
        RunType::Doctests => test_cmd.arg("--doc"),
        RunType::Benchmarks => test_cmd.arg("--benches"),
        RunType::Examples => test_cmd.arg("--examples"),
    };
    init_args(&mut test_cmd, config);
    setup_environment(&mut test_cmd, config);
    test_cmd
}

fn init_args(test_cmd: &mut Command, config: &Config) {
    if config.debug {
        test_cmd.arg("-vvv");
    }
    if config.locked {
        test_cmd.arg("--locked");
    }
    if config.frozen {
        test_cmd.arg("--frozen");
    }
    if let Some(features) = config.features.as_ref() {
        test_cmd.arg("--features");
        test_cmd.arg(features);
    }
    if config.all_features {
        test_cmd.arg("--all-features");
    }
    if config.no_default_features {
        test_cmd.arg("--no-default-features");
    }
    if config.all {
        test_cmd.arg("--workspace");
    }
    if config.release {
        test_cmd.arg("--release");
    }
    config.packages.iter().for_each(|package| {
        test_cmd.arg("--package");
        test_cmd.arg(package);
    });
    config.exclude.iter().for_each(|package| {
        test_cmd.arg("--exclude");
        test_cmd.arg(package);
    });
    if let Some(target) = config.target.as_ref() {
        test_cmd.args(&["--target", target]);
    }
    let args = vec![
        "--target-dir".to_string(),
        format!("{}", config.target_dir().display()),
    ];
    test_cmd.args(args);
    if config.offline {
        test_cmd.arg("--offline");
    }
    for feat in &config.unstable_features {
        test_cmd.arg(format!("-Z{}", feat));
    }
    if !config.varargs.is_empty() {
        let mut args = vec!["--".to_string()];
        args.extend_from_slice(&config.varargs);
        test_cmd.args(args);
    }
}

fn setup_environment(cmd: &mut Command, config: &Config) {
    cmd.env("TARPAULIN", "1");
    let rustflags = "RUSTFLAGS";
    let common_opts = " -C relocation-model=dynamic-no-pic -C link-dead-code -C debuginfo=2 ";
    let mut value = common_opts.to_string();
    if config.release {
        value = format!("{}-C debug-assertions=off ", value);
    }
    if let Ok(vtemp) = env::var(rustflags) {
        value.push_str(vtemp.as_ref());
    }
    cmd.env(rustflags, value);
    // doesn't matter if we don't use it
    let rustdoc = "RUSTDOCFLAGS";
    let mut value = format!(
        "{} --persist-doctests {} -Z unstable-options ",
        common_opts,
        config.doctest_dir().display()
    );
    if let Ok(vtemp) = env::var(rustdoc) {
        if !vtemp.contains("--persist-doctests") {
            value.push_str(vtemp.as_ref());
        }
    }
    trace!("Setting RUSTDOCFLAGS='{}'", value);
    cmd.env(rustdoc, value);
}
<commit_msg>Add analysis of lines (untested)<commit_after>use crate::config::*;
use crate::errors::RunError;
use cargo_metadata::{diagnostic::DiagnosticLevel, CargoOpt, Message, MetadataCommand};
use log::{error, info, trace, warn};
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io;
use std::io::{BufRead, BufReader};
use std::path::{Component, Path, PathBuf};
use std::process::{Command, Stdio};
use walkdir::{DirEntry, WalkDir};

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TestBinary {
    path: PathBuf,
    ty: RunType,
    cargo_dir: Option<PathBuf>,
    pkg_name: Option<String>,
    pkg_version: Option<String>,
    pkg_authors: Option<Vec<String>>,
    should_panic: bool,
}

impl TestBinary {
    pub fn new(path: PathBuf, ty: RunType) -> Self {
        Self {
            path,
            ty,
            pkg_name: None,
            pkg_version: None,
            pkg_authors: None,
            cargo_dir: None,
            should_panic: false,
        }
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn run_type(&self) -> RunType {
        self.ty
    }

    pub fn manifest_dir(&self) -> &Option<PathBuf> {
        &self.cargo_dir
    }

    pub fn pkg_name(&self) -> &Option<String> {
        &self.pkg_name
    }

    pub fn pkg_version(&self) -> &Option<String> {
        &self.pkg_version
    }

    pub fn pkg_authors(&self) -> &Option<Vec<String>> {
        &self.pkg_authors
    }

    /// Should be `false` for normal tests and for doctests either `true` or
    /// `false` depending on the test attribute
    pub fn should_panic(&self) -> bool {
        self.should_panic
    }
}

pub fn get_tests(config: &Config) -> Result<Vec<TestBinary>, RunError> {
    let mut result = vec![];
    let manifest = match config.manifest.as_path().to_str() {
        Some(s) => s,
        None => "Cargo.toml",
    };
    let metadata = MetadataCommand::new()
        .manifest_path(manifest)
        .features(CargoOpt::AllFeatures)
        .exec()
        .map_err(|e| RunError::Cargo(e.to_string()))?;

    for ty in &config.run_types {
        let mut cmd = create_command(manifest, config, ty);
        if ty != &RunType::Doctests {
            cmd.stdout(Stdio::piped());
        } else {
            cmd.stdout(Stdio::null());
        }
        if !config.verbose {
            cmd.stderr(Stdio::null());
        }
        trace!("Running command {:?}", cmd);
        let mut child = cmd.spawn().map_err(|e| RunError::Cargo(e.to_string()))?;

        if ty != &RunType::Doctests {
            let mut package_ids = vec![];
            let reader = std::io::BufReader::new(child.stdout.take().unwrap());
            for msg in Message::parse_stream(reader) {
                match msg {
                    Ok(Message::CompilerArtifact(art)) => {
                        if let Some(path) = art.executable {
                            if !art.profile.test && ty == &RunType::Tests {
                                continue;
                            }
                            result.push(TestBinary::new(path, *ty));
                            package_ids.push(art.package_id.clone());
                        }
                    }
                    Ok(Message::CompilerMessage(m)) => match m.message.level {
                        DiagnosticLevel::Error | DiagnosticLevel::Ice => {
                            let _ = child.wait();
                            return Err(RunError::TestCompile(m.message.message));
                        }
                        _ => {}
                    },
                    Err(e) => {
                        error!("Error parsing cargo messages {}", e);
                    }
                    _ => {}
                }
            }
            for (res, package) in result.iter_mut().zip(package_ids.iter()) {
                let package = &metadata[package];
                res.cargo_dir = package.manifest_path.parent().map(|x| x.to_path_buf());
                res.pkg_name = Some(package.name.clone());
                res.pkg_version = Some(package.version.to_string());
                res.pkg_authors = Some(package.authors.clone());
            }
            child.wait().map_err(|e| RunError::Cargo(e.to_string()))?;
        } else {
            // need to wait for compiling to finish before getting doctests
            // also need to wait with output to ensure the stdout buffer doesn't fill up
            let out = child
                .wait_with_output()
                .map_err(|e| RunError::Cargo(e.to_string()))?;
            if !out.status.success() {
                error!("Building doctests failed");
            }
            let walker = WalkDir::new(&config.doctest_dir()).into_iter();
            let dir_entries = walker
                .filter_map(|e| e.ok())
                .filter(|e| match e.metadata() {
                    Ok(ref m) if m.is_file() && m.len() != 0 => true,
                    _ => false,
                })
                .collect::<Vec<_>>();

            let should_panics = get_panic_candidates(&dir_entries, config);
            for dt in &dir_entries {
                trace!("Found doctest binary {}", dt.path().display());
                result.push(TestBinary::new(dt.path().to_path_buf(), *ty));
            }
        }
    }
    Ok(result)
}

fn convert_to_prefix(p: &Path) -> Option<String> {
    p.to_str()
        .map(|s| s.replace(std::path::MAIN_SEPARATOR, "_").replace(".", "_"))
}

fn is_prefix_match(prefix: &str, entry: &Path) -> bool {
    convert_to_prefix(entry)
        .map(|s| prefix.starts_with(&s))
        .unwrap_or(false)
}

/// This returns a map of the string prefixes for the file in the doc test and a list of lines
/// which contain the string `should_panic` it makes no guarantees that all these lines are a
/// doctest attribute showing panic behaviour (but some of them will be)
///
/// Currently all doctest files take the pattern of `{name}_{line}_{number}` where name is the
/// path to the file with directory separators and dots replaced with underscores. Therefore
/// each name could potentially map to many files as `src_some_folder_foo_rs_0_1` could go to
/// `src/some/folder_foo.rs` or `src/some/folder/foo.rs` here we're going to work on a heuristic
/// that any matching file is good because we can't do any better
fn get_panic_candidates(tests: &[DirEntry], config: &Config) -> HashMap<String, Vec<usize>> {
    let mut result = HashMap::new();
    let root = config.root();
    let target = config.target_dir();
    for test in tests {
        let test_name = test.path().components().nth_back(1);
        if let Some(Component::Normal(s)) = test_name {
            let s = s.to_string_lossy();
            let end = match s.rfind("rs") {
                Some(i) => i + 2,
                None => continue,
            };
            let walker = WalkDir::new(&root).into_iter();
            // TODO some walkdir stuff is being reused here and in source_analysis (and source
            // analysis does it a bit wrong) Fix before merging
            for dir_entry in walker
                .filter_entry(|e| {
                    !(e.path().starts_with(&target)
                        || e.path()
                            .iter()
                            .any(|x| x.to_string_lossy().starts_with(".")))
                })
                .filter_map(|e| e.ok())
            {
                let path = dir_entry.path();
                if path.is_file() {
                    if let Some(p) = path_relative_from(path, &root) {
                        if is_prefix_match(&s[..end], &p) {
                            let prefix = convert_to_prefix(&p).unwrap_or_default();
                            if !result.contains_key(&prefix) {
                                trace!("Assessing {} for `should_panic` doctests", path.display());
                                let lines = find_panics_in_file(path).unwrap_or_default();
                                result.insert(prefix, lines);
                            }
                            break;
                        }
                    }
                }
            }
        } else {
            warn!(
                "Invalid characters in name of doctest {}",
                test.path().display()
            );
        }
    }
    result
}

fn find_panics_in_file(file: &Path) -> io::Result<Vec<usize>> {
    let f = File::open(file)?;
    let reader = BufReader::new(f);
    let lines = reader
        .lines()
        .enumerate()
        .filter(|(_, l)| {
            l.as_ref()
                .map(|x| x.contains("should_panic"))
                .unwrap_or(false)
        })
        .map(|(i, _)| i)
        .collect();
    Ok(lines)
}

fn create_command(manifest_path: &str, config: &Config, ty: &RunType) -> Command {
    let mut test_cmd = Command::new("cargo");
    if *ty == RunType::Doctests {
        if let Some(toolchain) = env::var("RUSTUP_TOOLCHAIN")
            .ok()
            .filter(|t| t.starts_with("nightly"))
        {
            test_cmd.args(&[format!("+{}", toolchain).as_str(), "test"]);
        } else {
            test_cmd.args(&["+nightly", "test"]);
        }
    } else {
        if let Ok(toolchain) = env::var("RUSTUP_TOOLCHAIN") {
            test_cmd.arg(format!("+{}", toolchain));
        }
        test_cmd.args(&["test", "--no-run"]);
    }
    test_cmd.args(&["--message-format", "json", "--manifest-path", manifest_path]);
    match ty {
        RunType::Tests => test_cmd.arg("--tests"),
        RunType::Doctests => test_cmd.arg("--doc"),
        RunType::Benchmarks => test_cmd.arg("--benches"),
        RunType::Examples => test_cmd.arg("--examples"),
    };
    init_args(&mut test_cmd, config);
    setup_environment(&mut test_cmd, config);
    test_cmd
}

fn init_args(test_cmd: &mut Command, config: &Config) {
    if config.debug {
        test_cmd.arg("-vvv");
    }
    if config.locked {
        test_cmd.arg("--locked");
    }
    if config.frozen {
        test_cmd.arg("--frozen");
    }
    if let Some(features) = config.features.as_ref() {
        test_cmd.arg("--features");
        test_cmd.arg(features);
    }
    if config.all_features {
        test_cmd.arg("--all-features");
    }
    if config.no_default_features {
        test_cmd.arg("--no-default-features");
    }
    if config.all {
        test_cmd.arg("--workspace");
    }
    if config.release {
        test_cmd.arg("--release");
    }
    config.packages.iter().for_each(|package| {
        test_cmd.arg("--package");
        test_cmd.arg(package);
    });
    config.exclude.iter().for_each(|package| {
        test_cmd.arg("--exclude");
        test_cmd.arg(package);
    });
    if let Some(target) = config.target.as_ref() {
        test_cmd.args(&["--target", target]);
    }
    let args = vec![
        "--target-dir".to_string(),
        format!("{}", config.target_dir().display()),
    ];
    test_cmd.args(args);
    if config.offline {
        test_cmd.arg("--offline");
    }
    for feat in &config.unstable_features {
        test_cmd.arg(format!("-Z{}", feat));
    }
    if !config.varargs.is_empty() {
        let mut args = vec!["--".to_string()];
        args.extend_from_slice(&config.varargs);
        test_cmd.args(args);
    }
}

fn setup_environment(cmd: &mut Command, config: &Config) {
    cmd.env("TARPAULIN", "1");
    let rustflags = "RUSTFLAGS";
    let common_opts = " -C relocation-model=dynamic-no-pic -C link-dead-code -C debuginfo=2 ";
    let mut value = common_opts.to_string();
    if config.release {
        value = format!("{}-C debug-assertions=off ", value);
    }
    if let Ok(vtemp) = env::var(rustflags) {
        value.push_str(vtemp.as_ref());
    }
    cmd.env(rustflags, value);
    // doesn't matter if we don't use it
    let rustdoc = "RUSTDOCFLAGS";
    let mut value = format!(
        "{} --persist-doctests {} -Z unstable-options ",
        common_opts,
        config.doctest_dir().display()
    );
    if let Ok(vtemp) = env::var(rustdoc) {
        if !vtemp.contains("--persist-doctests") {
            value.push_str(vtemp.as_ref());
        }
    }
    trace!("Setting RUSTDOCFLAGS='{}'", value);
    cmd.env(rustdoc, value);
}
<|endoftext|>


<commit_before>use libc::{c_int, c_void};

/// Set if VM shared between processes.
pub const VM             : c_int = 0x00000100;
/// Set if fs info shared between processes.
pub const FS             : c_int = 0x00000200;
/// Set if open files shared between processes.
pub const FILES          : c_int = 0x00000400;
/// Set if signal handlers shared.
pub const SIGHAND        : c_int = 0x00000800;
/// Set if tracing continues on the child.
pub const PTRACE         : c_int = 0x00002000;
/// Set if the parent wants the child to wake it up on mm_release.
pub const VFORK          : c_int = 0x00004000;
/// Set if we want to have the same parent as the cloner.
pub const PARENT         : c_int = 0x00008000;
/// Set to add to same thread group.
pub const THREAD         : c_int = 0x00010000;
/// Set to create new namespace.
pub const NEWNS          : c_int = 0x00020000;
/// Set to shared SVID SEM_UNDO semantics.
pub const SYSVSEM        : c_int = 0x00040000;
/// Set TLS info.
pub const SETTLS         : c_int = 0x00080000;
/// Store TID in userlevel buffer before MM copy.
pub const PARENT_SETTID  : c_int = 0x00100000;
/// Register exit futex and memory location to clear.
pub const CHILD_CLEARTID : c_int = 0x00200000;
/// Create clone detached.
pub const DETACHED       : c_int = 0x00400000;
/// Set if the tracing process can't force PTRACE on this clone.
pub const UNTRACED       : c_int = 0x00800000;
/// Store TID in userlevel buffer in the child.
pub const CHILD_SETTID   : c_int = 0x01000000;
/// Start in stopped state.
pub const STOPPED        : c_int = 0x02000000;

extern {
    /// Wraps the clone(2) function (glibc/<arch>/clone.S)
    pub fn clone(func: extern fn (arg: *mut c_void) -> c_int,
                 child_stack: *mut c_void,
                 flag: c_int,
                 arg: *mut c_void) -> c_int;
}
<commit_msg>Use full clone(2) signature, prune flags<commit_after>use libc::{c_int, c_void, pid_t};

/// Flags that clone(2) uses. For more verbose descriptions, see the manpage.
///
/// There are some other flags that can be passed, but they're useless for our
/// purposes, so I won't add them here.
mod flags {
    use libc::c_int;

    /// This is how we'll be calling clone for threading purposes.
    pub const COMMON: c_int = VM | FS | FILES | SIGHAND | PARENT | THREAD;

    /// Set if VM shared between processes.
    const VM: c_int = 0x00000100;
    /// Set if fs info shared between processes.
    const FS: c_int = 0x00000200;
    /// Set if open files shared between processes.
    const FILES: c_int = 0x00000400;
    /// Set if signal handlers shared.
    const SIGHAND: c_int = 0x00000800;
    /// Set if we want to have the same parent as the cloner.
    const PARENT: c_int = 0x00008000;
    /// Set to add to same thread group.
    const THREAD: c_int = 0x00010000;
    /// Set to shared SVID SEM_UNDO semantics.
    const SYSVSEM: c_int = 0x00040000;
    /// Set TLS info.
    const SETTLS: c_int = 0x00080000;
    /// Store TID in userlevel buffer before MM copy.
    const PARENT_SETTID: c_int = 0x00100000;
    /// Register exit futex and memory location to clear.
    const CHILD_CLEARTID: c_int = 0x00200000;
    /// Create clone detached.
    const DETACHED: c_int = 0x00400000;
    /// Store TID in userlevel buffer in the child.
    const CHILD_SETTID: c_int = 0x01000000;
}

pub type CloneFunc = extern fn (arg: *mut c_void) -> c_int;

extern "C" {
    /// Wraps the clone(2) function (defined in glibc as
    /// /sysdeps/unix/sysv/linux/ARCH/clone.S)
    ///
    /// int clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
    ///           pid_t *ptid, struct user_desc *tls, pid_t *ctid)
    #[link_name="clone"]
    pub fn clone(func: CloneFunc,
                 child_stack: *mut c_void,
                 flag: c_int,
                 arg: *mut c_void,
                 ptid: *mut pid_t,
                 tls: *mut c_void, // TODO: handle this somehow
                 ctid: *mut pid_t
                 ) -> c_int;
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display};

use crate::mir;
use crate::ty::layout::{self, HasDataLayout, Size};
use rustc_macros::HashStable;

use super::{AllocId, InterpResult};

/// Used by `check_in_alloc` to indicate context of check
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum CheckInAllocMsg {
    MemoryAccessTest,
    NullPointerTest,
    PointerArithmeticTest,
    InboundsTest,
}

impl Display for CheckInAllocMsg {
    /// When this is printed as an error the context looks like this
    /// "{test name} failed: pointer must be in-bounds at offset..."
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", match *self {
            CheckInAllocMsg::MemoryAccessTest => "Memory access",
            CheckInAllocMsg::NullPointerTest => "Null pointer test",
            CheckInAllocMsg::PointerArithmeticTest => "Pointer arithmetic",
            CheckInAllocMsg::InboundsTest => "Inbounds test",
        })
    }
}

////////////////////////////////////////////////////////////////////////////////
// Pointer arithmetic
////////////////////////////////////////////////////////////////////////////////

pub trait PointerArithmetic: layout::HasDataLayout {
    // These are not supposed to be overridden.

    #[inline(always)]
    fn pointer_size(&self) -> Size {
        self.data_layout().pointer_size
    }

    /// Helper function: truncate given value-"overflowed flag" pair to pointer size and
    /// update "overflowed flag" if there was an overflow.
    /// This should be called by all the other methods before returning!
    #[inline]
    fn truncate_to_ptr(&self, (val, over): (u64, bool)) -> (u64, bool) {
        let val = val as u128;
        let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
        ((val % max_ptr_plus_1) as u64, over || val >= max_ptr_plus_1)
    }

    #[inline]
    fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
        let res = val.overflowing_add(i);
        self.truncate_to_ptr(res)
    }

    // Overflow checking only works properly on the range from -u64 to +u64.
    #[inline]
    fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
        // FIXME: is it possible to over/underflow here?
        if i < 0 {
            // Trickery to ensure that i64::min_value() works fine: compute n = -i.
            // This formula only works for true negative values, it overflows for zero!
            let n = u64::max_value() - (i as u64) + 1;
            let res = val.overflowing_sub(n);
            self.truncate_to_ptr(res)
        } else {
            self.overflowing_offset(val, i as u64)
        }
    }

    #[inline]
    fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> {
        let (res, over) = self.overflowing_offset(val, i);
        if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
    }

    #[inline]
    fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
        let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
        if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
    }
}

impl<T: layout::HasDataLayout> PointerArithmetic for T {}

/// `Pointer` is generic over the type that represents a reference to `Allocation`s,
/// thus making it possible for the most convenient representation to be used in
/// each context.
///
/// Defaults to the index based and loosely coupled `AllocId`.
///
/// Pointer is also generic over the `Tag` associated with each pointer,
/// which is used to do provenance tracking during execution.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
         RustcEncodable, RustcDecodable, Hash, HashStable)]
pub struct Pointer<Tag = (), Id = AllocId> {
    pub alloc_id: Id,
    pub offset: Size,
    pub tag: Tag,
}

static_assert_size!(Pointer, 16);

impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for Pointer<Tag, Id> {
    default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}.{:#x}[{:?}]", self.alloc_id, self.offset.bytes(), self.tag)
    }
}
// Specialization for no tag
impl<Id: fmt::Debug> fmt::Debug for Pointer<(), Id> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}.{:#x}", self.alloc_id, self.offset.bytes())
    }
}

/// Produces a `Pointer` which points to the beginning of the `Allocation`.
impl From<AllocId> for Pointer {
    #[inline(always)]
    fn from(alloc_id: AllocId) -> Self {
        Pointer::new(alloc_id, Size::ZERO)
    }
}

impl Pointer<()> {
    #[inline(always)]
    pub fn new(alloc_id: AllocId, offset: Size) -> Self {
        Pointer { alloc_id, offset, tag: () }
    }

    #[inline(always)]
    pub fn with_tag<Tag>(self, tag: Tag) -> Pointer<Tag>
    {
        Pointer::new_with_tag(self.alloc_id, self.offset, tag)
    }
}

impl<'tcx, Tag> Pointer<Tag> {
    #[inline(always)]
    pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
        Pointer { alloc_id, offset, tag }
    }

    #[inline]
    pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
        Ok(Pointer::new_with_tag(
            self.alloc_id,
            Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
            self.tag
        ))
    }

    #[inline]
    pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
    }

    #[inline(always)]
    pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
        self.overflowing_offset(i, cx).0
    }

    #[inline]
    pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
        Ok(Pointer::new_with_tag(
            self.alloc_id,
            Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
            self.tag,
        ))
    }

    #[inline]
    pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
    }

    #[inline(always)]
    pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
        self.overflowing_signed_offset(i128::from(i), cx).0
    }

    #[inline(always)]
    pub fn erase_tag(self) -> Pointer {
        Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
    }

    /// Test if the pointer is "inbounds" of an allocation of the given size.
    /// A pointer is "inbounds" even if its offset is equal to the size; this is
    /// a "one-past-the-end" pointer.
    #[inline(always)]
    pub fn check_inbounds_alloc(
        self,
        allocation_size: Size,
        msg: CheckInAllocMsg,
    ) -> InterpResult<'tcx, ()> {
        if self.offset > allocation_size {
            throw_unsup!(PointerOutOfBounds { ptr: self.erase_tag(), msg, allocation_size })
        } else {
            Ok(())
        }
    }
}
<commit_msg>Rollup merge of #66410 - RalfJung:miri-machine-max, r=oli-obk<commit_after>use std::fmt::{self, Display};
use std::convert::TryFrom;

use crate::mir;
use crate::ty::layout::{self, HasDataLayout, Size};
use rustc_macros::HashStable;

use super::{AllocId, InterpResult};

/// Used by `check_in_alloc` to indicate context of check
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum CheckInAllocMsg {
    MemoryAccessTest,
    NullPointerTest,
    PointerArithmeticTest,
    InboundsTest,
}

impl Display for CheckInAllocMsg {
    /// When this is printed as an error the context looks like this
    /// "{test name} failed: pointer must be in-bounds at offset..."
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", match *self {
            CheckInAllocMsg::MemoryAccessTest => "Memory access",
            CheckInAllocMsg::NullPointerTest => "Null pointer test",
            CheckInAllocMsg::PointerArithmeticTest => "Pointer arithmetic",
            CheckInAllocMsg::InboundsTest => "Inbounds test",
        })
    }
}

////////////////////////////////////////////////////////////////////////////////
// Pointer arithmetic
////////////////////////////////////////////////////////////////////////////////

pub trait PointerArithmetic: layout::HasDataLayout {
    // These are not supposed to be overridden.

    #[inline(always)]
    fn pointer_size(&self) -> Size {
        self.data_layout().pointer_size
    }

    #[inline]
    fn usize_max(&self) -> u64 {
        let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
        u64::try_from(max_usize_plus_1-1).unwrap()
    }

    #[inline]
    fn isize_max(&self) -> i64 {
        let max_isize_plus_1 = 1u128 << (self.pointer_size().bits()-1);
        i64::try_from(max_isize_plus_1-1).unwrap()
    }

    /// Helper function: truncate given value-"overflowed flag" pair to pointer size and
    /// update "overflowed flag" if there was an overflow.
    /// This should be called by all the other methods before returning!
    #[inline]
    fn truncate_to_ptr(&self, (val, over): (u64, bool)) -> (u64, bool) {
        let val = val as u128;
        let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
        ((val % max_ptr_plus_1) as u64, over || val >= max_ptr_plus_1)
    }

    #[inline]
    fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
        let res = val.overflowing_add(i);
        self.truncate_to_ptr(res)
    }

    // Overflow checking only works properly on the range from -u64 to +u64.
    #[inline]
    fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
        // FIXME: is it possible to over/underflow here?
        if i < 0 {
            // Trickery to ensure that i64::min_value() works fine: compute n = -i.
            // This formula only works for true negative values, it overflows for zero!
            let n = u64::max_value() - (i as u64) + 1;
            let res = val.overflowing_sub(n);
            self.truncate_to_ptr(res)
        } else {
            self.overflowing_offset(val, i as u64)
        }
    }

    #[inline]
    fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> {
        let (res, over) = self.overflowing_offset(val, i);
        if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
    }

    #[inline]
    fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
        let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
        if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
    }
}

impl<T: layout::HasDataLayout> PointerArithmetic for T {}

/// `Pointer` is generic over the type that represents a reference to `Allocation`s,
/// thus making it possible for the most convenient representation to be used in
/// each context.
///
/// Defaults to the index based and loosely coupled `AllocId`.
///
/// Pointer is also generic over the `Tag` associated with each pointer,
/// which is used to do provenance tracking during execution.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
         RustcEncodable, RustcDecodable, Hash, HashStable)]
pub struct Pointer<Tag = (), Id = AllocId> {
    pub alloc_id: Id,
    pub offset: Size,
    pub tag: Tag,
}

static_assert_size!(Pointer, 16);

impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for Pointer<Tag, Id> {
    default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}.{:#x}[{:?}]", self.alloc_id, self.offset.bytes(), self.tag)
    }
}
// Specialization for no tag
impl<Id: fmt::Debug> fmt::Debug for Pointer<(), Id> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}.{:#x}", self.alloc_id, self.offset.bytes())
    }
}

/// Produces a `Pointer` which points to the beginning of the `Allocation`.
impl From<AllocId> for Pointer {
    #[inline(always)]
    fn from(alloc_id: AllocId) -> Self {
        Pointer::new(alloc_id, Size::ZERO)
    }
}

impl Pointer<()> {
    #[inline(always)]
    pub fn new(alloc_id: AllocId, offset: Size) -> Self {
        Pointer { alloc_id, offset, tag: () }
    }

    #[inline(always)]
    pub fn with_tag<Tag>(self, tag: Tag) -> Pointer<Tag>
    {
        Pointer::new_with_tag(self.alloc_id, self.offset, tag)
    }
}

impl<'tcx, Tag> Pointer<Tag> {
    #[inline(always)]
    pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
        Pointer { alloc_id, offset, tag }
    }

    #[inline]
    pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
        Ok(Pointer::new_with_tag(
            self.alloc_id,
            Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
            self.tag
        ))
    }

    #[inline]
    pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
    }

    #[inline(always)]
    pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
        self.overflowing_offset(i, cx).0
    }

    #[inline]
    pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
        Ok(Pointer::new_with_tag(
            self.alloc_id,
            Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
            self.tag,
        ))
    }

    #[inline]
    pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
    }

    #[inline(always)]
    pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
        self.overflowing_signed_offset(i128::from(i), cx).0
    }

    #[inline(always)]
    pub fn erase_tag(self) -> Pointer {
        Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
    }

    /// Test if the pointer is "inbounds" of an allocation of the given size.
    /// A pointer is "inbounds" even if its offset is equal to the size; this is
    /// a "one-past-the-end" pointer.
    #[inline(always)]
    pub fn check_inbounds_alloc(
        self,
        allocation_size: Size,
        msg: CheckInAllocMsg,
    ) -> InterpResult<'tcx, ()> {
        if self.offset > allocation_size {
            throw_unsup!(PointerOutOfBounds { ptr: self.erase_tag(), msg, allocation_size })
        } else {
            Ok(())
        }
    }
}
<|endoftext|>