<commit_before>use graphics::{DrawState, Transformed, rectangle};
use graphics::polygon::Polygon;
use graphics::line::Line;
use graphics::math::{transform_pos, rotate_radians};
use opengl_graphics::GlGraphics;
use piston::input::Key;
use rand::Rng;
use rand::distributions::{Range, IndependentSample, Normal};
use rand::distributions::range::SampleRange;
use std::f64::consts::PI;
use intersect::{lines_intersect, point_in};
use point::Point;

use config::Config;

pub fn to_cartesian(theta: f64, r: f64) -> (f64, f64) {
    return (theta.sin() * r, -theta.cos() * r);
}

fn random<T: SampleRange + PartialOrd>(low: T, high: T, mut rng: &mut Rng) -> T {
    return Range::new(low, high).ind_sample(&mut rng);
}

pub fn wrapped_add(a: f64, b: f64, bound: f64) -> f64 {
    (a + b + bound) % bound
}

#[derive(PartialEq, Debug, Clone)]
pub struct GameObject {
    x: f64,
    y: f64,
    v: f64,
    theta: f64,
}

impl GameObject {
    fn new(x: f64, y: f64, v: f64, theta: f64) -> GameObject {
        GameObject {
            x: x,
            y: y,
            v: v,
            theta: theta,
        }
    }

    pub fn with_go(&self, dt: f64, x_max: f64, y_max: f64) -> GameObject {
        let (dx, dy) = to_cartesian(self.theta, self.v * dt);
        GameObject::new(wrapped_add(self.x, dx, x_max),
                        wrapped_add(self.y, dy, y_max),
                        self.v,
                        self.theta)
    }
}

#[derive(Clone)]
pub struct Spaceship {
    obj: GameObject,
    sprite_theta: f64,
    accel: f64,
    reverse: f64,
    left: f64,
    right: f64,
    firing: bool,
    cooldown: f64,
}

const SPACESHIP_POINTS: [[f64; 2]; 3] = [[5.0, 7.0], [-5.0, 7.0], [0.0, -13.0]];

impl Spaceship {
    pub fn new(config: &Config) -> Spaceship {
        return Spaceship {
            obj: GameObject::new(config.width() / 2.0, config.height() / 2.0, 0.0, 0.0),
            sprite_theta: 0.0,
            accel: 0.0,
            reverse: 0.0,
            left: 0.0,
            right: 0.0,
            firing: false,
            cooldown: 0.0,
        };
    }

    pub fn handle_press(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 1.0,
            Key::Down => self.reverse = 1.0,
            Key::Left => self.left = 0.05,
            Key::Right => self.right = 0.05,
            Key::Space => self.firing = true,
            _ => (),
        }
    }

    pub fn handle_release(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 0.0,
            Key::Down => self.reverse = 0.0,
            Key::Left => self.left = 0.0,
            Key::Right => self.right = 0.0,
            Key::Space => self.firing = false,
            _ => (),
        }
    }

    pub fn draw(&self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        Polygon::new(color).draw(&SPACESHIP_POINTS,
                                 ds,
                                 t.trans(self.obj.x, self.obj.y)
                                     .rot_rad(self.sprite_theta),
                                 gl);
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.obj = self.obj.with_go(dt, x_max, y_max);
    }

    pub fn accelerate(&mut self, dt: f64) {
        let net_accel = (self.accel - self.reverse) * dt * 100.0;
        let (dx, dy) = to_cartesian(self.obj.theta, self.obj.v);
        let (ddx, ddy) = to_cartesian(self.sprite_theta, net_accel);
        let new_dx = dx + ddx;
        let new_dy = dy + ddy;
        self.obj.v = (new_dx * new_dx + new_dy * new_dy).sqrt().min(200.0).max(-200.0);
        self.obj.theta = new_dx.atan2(-new_dy);
    }

    pub fn turn(&mut self, dt: f64) {
        self.sprite_theta += (self.right - self.left) * dt * 100.0;
    }

    pub fn cooldown(&mut self, dt: f64) {
        self.cooldown = (self.cooldown - dt).max(0.0);
    }

    pub fn ready_to_fire(&self) -> bool {
        return self.cooldown == 0.0;
    }

    pub fn is_firing(&self) -> bool {
        return self.firing;
    }

    pub fn fire(&mut self, bullets: &mut Vec<Bullet>) {
        self.cooldown = 0.5;
        bullets.push(Bullet::new(self.obj.x, self.obj.y, self.sprite_theta));
    }

    pub fn edges(&self) -> Vec<[f64; 4]> {
        let rotation_matrix = rotate_radians(self.sprite_theta);
        let points: Vec<[f64; 2]> = SPACESHIP_POINTS.iter()
            .map(|p| transform_pos(rotation_matrix, *p))
            .collect();
        return points.iter()
            .zip(points.iter().cycle().skip(1))
            .map(|(p1, p2)| {
                [p1[0] + self.obj.x, p1[1] + self.obj.y, p2[0] + self.obj.x, p2[1] + self.obj.y]
            })
            .collect();
    }

    pub fn collides<I: Iterator<Item = [f64; 4]>>(&self, edges: I) -> bool {
        let edges_vec: Vec<[f64; 4]> = edges.collect();
        return self.edges()
            .iter()
            .any(|edge| edges_vec.iter().any(|other_edge| lines_intersect(*edge, *other_edge)));
    }
}

#[derive(Clone, Debug)]
pub struct Bullet {
    obj: GameObject,
    distance: f64,
}

impl Bullet {
    fn new(x: f64, y: f64, theta: f64) -> Bullet {
        return Bullet {
            obj: GameObject::new(x, y, 100.0, theta),
            distance: 0.0,
        };
    }

    pub fn draw(&self, color: [f32; 4], t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        rectangle(color, rectangle::square(self.obj.x, self.obj.y, 2.0), t, gl);
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.obj = self.obj.with_go(dt, x_max, y_max);
        self.distance += self.obj.v * dt;
    }

    pub fn is_alive(&self) -> bool {
        return self.distance < 100.0;
    }

    pub fn coords(&self) -> Point {
        return Point::new(self.obj.x, self.obj.y);
    }

    pub fn collides(&self, astroid: &Astroid) -> bool {
        return point_in(self.coords(), astroid.edges().iter().cloned());
    }
}

#[derive(Clone)]
pub struct Astroid {
    obj: GameObject,
    size: i64,
    border: Vec<[f64; 4]>,
}

const ASTROID_LARGE: i64 = 3;

impl Astroid {
    pub fn large_new(config: &Config, mut rng: &mut Rng) -> Astroid {
        return Self::new(ASTROID_LARGE, config, rng);
    }

    fn random_start(max: f64, gap: f64, mut rng: &mut Rng) -> f64 {
        if random(0, 2, rng) == 0 {
            return random(0.0, max / 2.0 - gap, rng);
        } else {
            return random(max / 2.0 + gap, max, rng);
        }
    }

    pub fn new(size: i64, config: &Config, mut rng: &mut Rng) -> Astroid {
        let radius = (size * 5) as f64;
        return Astroid {
            obj: GameObject::new(Astroid::random_start(config.width(),
                                                       config.astroid_gap_distance(),
                                                       &mut rng),
                                 Astroid::random_start(config.height(),
                                                       config.astroid_gap_distance(),
                                                       &mut rng),
                                 random(40.0, 60.0, &mut rng),
                                 random(0.0, 2.0 * PI, &mut rng)),
            size: size,
            border: Astroid::create_border(&mut rng, radius),
        };
    }

    fn exploded(&self, mut rng: &mut Rng) -> Astroid {
        let new_size = self.size - 1;
        let radius = (new_size * 5) as f64;
        let theta_range = Normal::new(0.0, PI / 2.0);
        let d_theta = theta_range.ind_sample(&mut rng);
        let theta = self.obj.theta + d_theta;
        return Astroid {
            obj: GameObject::new(self.obj.x + random(-5.0, 5.0, &mut rng),
                                 self.obj.y + random(-5.0, 5.0, &mut rng),
                                 random(40.0, 60.0, &mut rng),
                                 theta),
            size: new_size,
            border: Astroid::create_border(&mut rng, radius),
        };
    }

    pub fn explode(&self, mut rng: &mut Rng) -> Vec<Astroid> {
        if self.size <= 1 {
            vec![]
        } else {
            vec![self.exploded(rng), self.exploded(rng)]
        }
    }

    pub fn draw(&self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        let line_info = Line::new(color, 0.5);
        for line_points in self.border.iter() {
            line_info.draw(*line_points, ds, t.trans(self.obj.x, self.obj.y), gl);
        }
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.obj = self.obj.with_go(dt, x_max, y_max);
    }

    pub fn create_border(mut rng: &mut Rng, radius: f64) -> Vec<[f64; 4]> {
        let spread = radius / 5.0;
        let point_count = random(8, 12, &mut rng);
        let mut points = Vec::with_capacity(point_count);
        let theta_0 = random(0.0, 2.0 * PI, &mut rng);
        let corner_i_to_theta = |i| theta_0 + 2.0 * PI * i as f64 / point_count as f64;
        for theta in (1..point_count + 1).map(corner_i_to_theta) {
            let distance = radius + random(-spread, spread, &mut rng);
            points.push(to_cartesian(theta, distance));
        }
        let point = points[0];
        points.push(point);
        let mut lines = Vec::with_capacity(point_count);
        for point in points.iter().zip(points.iter().skip(1)) {
            let (&(x1, x2), &(y1, y2)) = point;
            lines.push([x1, x2, y1, y2]);
        }
        return lines;
    }

    pub fn edges(&self) -> Vec<[f64; 4]> {
        return self.border
            .iter()
            .map(|edge| {
                [edge[0] + self.obj.x,
                 edge[1] + self.obj.y,
                 edge[2] + self.obj.x,
                 edge[3] + self.obj.y]
            })
            .collect();
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::f64::consts::PI;
    use expectest::prelude::*;

    #[test]
    fn test_wrapped_add() {
        assert_eq!(wrapped_add(1.0, 1.0, 10.0), 2.0);
        assert_eq!(wrapped_add(1.0, 10.0, 10.0), 1.0);
        assert_eq!(wrapped_add(1.0, -5.0, 10.0), 6.0);
    }

    fn expect_both_close_to((r, theta): (f64, f64), (x_expected, y_expected): (f64, f64)) {
        match to_cartesian(r, theta) {
            (x, y) => {
                expect!(x_expected).to(be_close_to(x));
                expect!(y_expected).to(be_close_to(y));
            }
        }
    }

    #[test]
    fn test_to_cartesian() {
        expect_both_close_to((0.0, 1.0), (0.0, -1.0));
        expect_both_close_to((PI / 2.0, 1.0), (1.0, 0.0));
    }

    #[test]
    fn test_game_object_factories() {
        expect!(GameObject::new(2.0, 3.0, 5.0, 7.0)).to(be_equal_to(GameObject {
            x: 2.0,
            y: 3.0,
            v: 5.0,
            theta: 7.0,
        }));
    }

    #[test]
    fn test_game_object_go() {
        let obj = GameObject::new(2.0, 3.0, 1.0, 0.0);
        expect!(obj.with_go(1.0, 200.0, 200.0))
            .to(be_equal_to(GameObject::new(2.0, 2.0, 1.0, 0.0)));
        expect!(obj.with_go(200.0, 200.0, 200.0))
            .to(be_equal_to(GameObject::new(2.0, 3.0, 1.0, 0.0)));
    }
}
<commit_msg>Add to_polar function<commit_after>use graphics::{DrawState, Transformed, rectangle};
use graphics::polygon::Polygon;
use graphics::line::Line;
use graphics::math::{transform_pos, rotate_radians};
use opengl_graphics::GlGraphics;
use piston::input::Key;
use rand::Rng;
use rand::distributions::{Range, IndependentSample, Normal};
use rand::distributions::range::SampleRange;
use std::f64::consts::PI;
use intersect::{lines_intersect, point_in};
use point::Point;

use config::Config;

pub fn to_cartesian(theta: f64, r: f64) -> (f64, f64) {
    return (theta.sin() * r, -theta.cos() * r);
}

pub fn to_polar(x: f64, y: f64) -> (f64, f64) {
    return (x.atan2(-y), (x * x + y * y).sqrt());
}

fn random<T: SampleRange + PartialOrd>(low: T, high: T, mut rng: &mut Rng) -> T {
    return Range::new(low, high).ind_sample(&mut rng);
}

pub fn wrapped_add(a: f64, b: f64, bound: f64) -> f64 {
    (a + b + bound) % bound
}

#[derive(PartialEq, Debug, Clone)]
pub struct GameObject {
    x: f64,
    y: f64,
    v: f64,
    theta: f64,
}

impl GameObject {
    fn new(x: f64, y: f64, v: f64, theta: f64) -> GameObject {
        GameObject {
            x: x,
            y: y,
            v: v,
            theta: theta,
        }
    }

    pub fn with_go(&self, dt: f64, x_max: f64, y_max: f64) -> GameObject {
        let (dx, dy) = to_cartesian(self.theta, self.v * dt);
        GameObject::new(wrapped_add(self.x, dx, x_max),
                        wrapped_add(self.y, dy, y_max),
                        self.v,
                        self.theta)
    }
}

#[derive(Clone)]
pub struct Spaceship {
    obj: GameObject,
    sprite_theta: f64,
    accel: f64,
    reverse: f64,
    left: f64,
    right: f64,
    firing: bool,
    cooldown: f64,
}

const SPACESHIP_POINTS: [[f64; 2]; 3] = [[5.0, 7.0], [-5.0, 7.0], [0.0, -13.0]];

impl Spaceship {
    pub fn new(config: &Config) -> Spaceship {
        return Spaceship {
            obj: GameObject::new(config.width() / 2.0, config.height() / 2.0, 0.0, 0.0),
            sprite_theta: 0.0,
            accel: 0.0,
            reverse: 0.0,
            left: 0.0,
            right: 0.0,
            firing: false,
            cooldown: 0.0,
        };
    }

    pub fn handle_press(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 1.0,
            Key::Down => self.reverse = 1.0,
            Key::Left => self.left = 0.05,
            Key::Right => self.right = 0.05,
            Key::Space => self.firing = true,
            _ => (),
        }
    }

    pub fn handle_release(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 0.0,
            Key::Down => self.reverse = 0.0,
            Key::Left => self.left = 0.0,
            Key::Right => self.right = 0.0,
            Key::Space => self.firing = false,
            _ => (),
        }
    }

    pub fn draw(&self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        Polygon::new(color).draw(&SPACESHIP_POINTS,
                                 ds,
                                 t.trans(self.obj.x, self.obj.y)
                                     .rot_rad(self.sprite_theta),
                                 gl);
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.obj = self.obj.with_go(dt, x_max, y_max);
    }

    pub fn accelerate(&mut self, dt: f64) {
        let net_accel = (self.accel - self.reverse) * dt * 100.0;
        let (dx, dy) = to_cartesian(self.obj.theta, self.obj.v);
        let (ddx, ddy) = to_cartesian(self.sprite_theta, net_accel);
        let new_dx = dx + ddx;
        let new_dy = dy + ddy;
        let (new_theta, new_v) = to_polar(new_dx, new_dy);
        self.obj.v = new_v.min(200.0).max(-200.0);
        self.obj.theta = new_theta;
    }

    pub fn turn(&mut self, dt: f64) {
        self.sprite_theta += (self.right - self.left) * dt * 100.0;
    }

    pub fn cooldown(&mut self, dt: f64) {
        self.cooldown = (self.cooldown - dt).max(0.0);
    }

    pub fn ready_to_fire(&self) -> bool {
        return self.cooldown == 0.0;
    }

    pub fn is_firing(&self) -> bool {
        return self.firing;
    }

    pub fn fire(&mut self, bullets: &mut Vec<Bullet>) {
        self.cooldown = 0.5;
        bullets.push(Bullet::new(self.obj.x, self.obj.y, self.sprite_theta));
    }

    pub fn edges(&self) -> Vec<[f64; 4]> {
        let rotation_matrix = rotate_radians(self.sprite_theta);
        let points: Vec<[f64; 2]> = SPACESHIP_POINTS.iter()
            .map(|p| transform_pos(rotation_matrix, *p))
            .collect();
        return points.iter()
            .zip(points.iter().cycle().skip(1))
            .map(|(p1, p2)| {
                [p1[0] + self.obj.x, p1[1] + self.obj.y, p2[0] + self.obj.x, p2[1] + self.obj.y]
            })
            .collect();
    }

    pub fn collides<I: Iterator<Item = [f64; 4]>>(&self, edges: I) -> bool {
        let edges_vec: Vec<[f64; 4]> = edges.collect();
        return self.edges()
            .iter()
            .any(|edge| edges_vec.iter().any(|other_edge| lines_intersect(*edge, *other_edge)));
    }
}

#[derive(Clone, Debug)]
pub struct Bullet {
    obj: GameObject,
    distance: f64,
}

impl Bullet {
    fn new(x: f64, y: f64, theta: f64) -> Bullet {
        return Bullet {
            obj: GameObject::new(x, y, 100.0, theta),
            distance: 0.0,
        };
    }

    pub fn draw(&self, color: [f32; 4], t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        rectangle(color, rectangle::square(self.obj.x, self.obj.y, 2.0), t, gl);
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.obj = self.obj.with_go(dt, x_max, y_max);
        self.distance += self.obj.v * dt;
    }

    pub fn is_alive(&self) -> bool {
        return self.distance < 100.0;
    }

    pub fn coords(&self) -> Point {
        return Point::new(self.obj.x, self.obj.y);
    }

    pub fn collides(&self, astroid: &Astroid) -> bool {
        return point_in(self.coords(), astroid.edges().iter().cloned());
    }
}

#[derive(Clone)]
pub struct Astroid {
    obj: GameObject,
    size: i64,
    border: Vec<[f64; 4]>,
}

const ASTROID_LARGE: i64 = 3;

impl Astroid {
    pub fn large_new(config: &Config, mut rng: &mut Rng) -> Astroid {
        return Self::new(ASTROID_LARGE, config, rng);
    }

    fn random_start(max: f64, gap: f64, mut rng: &mut Rng) -> f64 {
        if random(0, 2, rng) == 0 {
            return random(0.0, max / 2.0 - gap, rng);
        } else {
            return random(max / 2.0 + gap, max, rng);
        }
    }

    pub fn new(size: i64, config: &Config, mut rng: &mut Rng) -> Astroid {
        let radius = (size * 5) as f64;
        return Astroid {
            obj: GameObject::new(Astroid::random_start(config.width(),
                                                       config.astroid_gap_distance(),
                                                       &mut rng),
                                 Astroid::random_start(config.height(),
                                                       config.astroid_gap_distance(),
                                                       &mut rng),
                                 random(40.0, 60.0, &mut rng),
                                 random(0.0, 2.0 * PI, &mut rng)),
            size: size,
            border: Astroid::create_border(&mut rng, radius),
        };
    }

    fn exploded(&self, mut rng: &mut Rng) -> Astroid {
        let new_size = self.size - 1;
        let radius = (new_size * 5) as f64;
        let theta_range = Normal::new(0.0, PI / 2.0);
        let d_theta = theta_range.ind_sample(&mut rng);
        let theta = self.obj.theta + d_theta;
        return Astroid {
            obj: GameObject::new(self.obj.x + random(-5.0, 5.0, &mut rng),
                                 self.obj.y + random(-5.0, 5.0, &mut rng),
                                 random(40.0, 60.0, &mut rng),
                                 theta),
            size: new_size,
            border: Astroid::create_border(&mut rng, radius),
        };
    }

    pub fn explode(&self, mut rng: &mut Rng) -> Vec<Astroid> {
        if self.size <= 1 {
            vec![]
        } else {
            vec![self.exploded(rng), self.exploded(rng)]
        }
    }

    pub fn draw(&self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        let line_info = Line::new(color, 0.5);
        for line_points in self.border.iter() {
            line_info.draw(*line_points, ds, t.trans(self.obj.x, self.obj.y), gl);
        }
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.obj = self.obj.with_go(dt, x_max, y_max);
    }

    pub fn create_border(mut rng: &mut Rng, radius: f64) -> Vec<[f64; 4]> {
        let spread = radius / 5.0;
        let point_count = random(8, 12, &mut rng);
        let mut points = Vec::with_capacity(point_count);
        let theta_0 = random(0.0, 2.0 * PI, &mut rng);
        let corner_i_to_theta = |i| theta_0 + 2.0 * PI * i as f64 / point_count as f64;
        for theta in (1..point_count + 1).map(corner_i_to_theta) {
            let distance = radius + random(-spread, spread, &mut rng);
            points.push(to_cartesian(theta, distance));
        }
        let point = points[0];
        points.push(point);
        let mut lines = Vec::with_capacity(point_count);
        for point in points.iter().zip(points.iter().skip(1)) {
            let (&(x1, x2), &(y1, y2)) = point;
            lines.push([x1, x2, y1, y2]);
        }
        return lines;
    }

    pub fn edges(&self) -> Vec<[f64; 4]> {
        return self.border
            .iter()
            .map(|edge| {
                [edge[0] + self.obj.x,
                 edge[1] + self.obj.y,
                 edge[2] + self.obj.x,
                 edge[3] + self.obj.y]
            })
            .collect();
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::f64::consts::PI;
    use expectest::prelude::*;

    #[test]
    fn test_wrapped_add() {
        assert_eq!(wrapped_add(1.0, 1.0, 10.0), 2.0);
        assert_eq!(wrapped_add(1.0, 10.0, 10.0), 1.0);
        assert_eq!(wrapped_add(1.0, -5.0, 10.0), 6.0);
    }

    fn expect_both_close_to((x, y): (f64, f64), (x_expected, y_expected): (f64, f64)) {
        expect!(x).to(be_close_to(x_expected));
        expect!(y).to(be_close_to(y_expected));
    }

    #[test]
    fn test_to_cartesian() {
        expect_both_close_to(to_cartesian(0.0, 1.0), (0.0, -1.0));
        expect_both_close_to(to_cartesian(PI / 2.0, 1.0), (1.0, 0.0));
    }

    #[test]
    fn test_to_polar() {
        expect_both_close_to(to_polar(0.0, -1.0), (0.0, 1.0));
        expect_both_close_to(to_polar(1.0, 0.0), (PI / 2.0, 1.0));
    }

    #[test]
    fn test_game_object_factories() {
        expect!(GameObject::new(2.0, 3.0, 5.0, 7.0)).to(be_equal_to(GameObject {
            x: 2.0,
            y: 3.0,
            v: 5.0,
            theta: 7.0,
        }));
    }

    #[test]
    fn test_game_object_go() {
        let obj = GameObject::new(2.0, 3.0, 1.0, 0.0);
        expect!(obj.with_go(1.0, 200.0, 200.0))
            .to(be_equal_to(GameObject::new(2.0, 2.0, 1.0, 0.0)));
        expect!(obj.with_go(200.0, 200.0, 200.0))
            .to(be_equal_to(GameObject::new(2.0, 3.0, 1.0, 0.0)));
    }
}
<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) 2015, Nathan Zadoks <nathan@nathan7.eu>
// See the LICENSE file included in this distribution.
use core::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};

pub use self::imp::{map_stack, protect_stack, unmap_stack};
use self::imp::sys_page_size;

#[cfg(unix)]
#[path = "unix.rs"]
mod imp;

static PAGE_SIZE_CACHE: AtomicUsize = ATOMIC_USIZE_INIT;
pub fn page_size() -> usize {
  match PAGE_SIZE_CACHE.load(Ordering::Relaxed) {
    0 => {
      let page_size = sys_page_size();
      PAGE_SIZE_CACHE.store(page_size, Ordering::Relaxed);
      page_size
    }
    page_size => page_size
  }
}
<commit_msg>core::atomic -> core::sync::atomic<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) 2015, Nathan Zadoks <nathan@nathan7.eu>
// See the LICENSE file included in this distribution.
use core::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};

pub use self::imp::{map_stack, protect_stack, unmap_stack};
use self::imp::sys_page_size;

#[cfg(unix)]
#[path = "unix.rs"]
mod imp;

static PAGE_SIZE_CACHE: AtomicUsize = ATOMIC_USIZE_INIT;
pub fn page_size() -> usize {
  match PAGE_SIZE_CACHE.load(Ordering::Relaxed) {
    0 => {
      let page_size = sys_page_size();
      PAGE_SIZE_CACHE.store(page_size, Ordering::Relaxed);
      page_size
    }
    page_size => page_size
  }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};

use bytes::{BufMut, Bytes, BytesMut};
use futures::{future, stream, Stream, StreamExt};
use pin_project::pin_project;
use tokio::io::AsyncRead;

/// Stream of bytes.
#[pin_project]
pub struct ByteStream {
    size_hint: Option<usize>,
    #[pin]
    inner: Pin<Box<dyn Stream<Item = Result<Bytes, io::Error>> + Send + Sync + 'static>>,
}

impl ByteStream {
    /// Create a new `ByteStream` by wrapping a `futures` stream.
    pub fn new<S>(stream: S) -> ByteStream
    where
        S: Stream<Item = Result<Bytes, io::Error>> + Send + Sync + 'static,
    {
        ByteStream {
            size_hint: None,
            inner: Box::pin(stream),
        }
    }

    pub(crate) fn size_hint(&self) -> Option<usize> {
        self.size_hint
    }

    /// Return an implementation of `AsyncRead` that uses async i/o to consume the stream.
    pub fn into_async_read(self) -> impl AsyncRead + Send {
        ImplAsyncRead::new(self.inner)
    }

    /// Return an implementation of `Read` that uses blocking i/o to consume the stream.
    pub fn into_blocking_read(self) -> impl io::Read + Send {
        ImplBlockingRead::new(self.inner)
    }
}

impl From<Vec<u8>> for ByteStream {
    fn from(buf: Vec<u8>) -> ByteStream {
        ByteStream {
            size_hint: Some(buf.len()),
            inner: Box::pin(stream::once(async move { Ok(Bytes::from(buf)) })),
        }
    }
}

impl fmt::Debug for ByteStream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<ByteStream size_hint={:?}>", self.size_hint)
    }
}

impl Stream for ByteStream {
    type Item = Result<Bytes, io::Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let this = self.project();
        this.inner.poll_next(cx)
    }
}

#[pin_project]
struct ImplAsyncRead {
    buffer: BytesMut,
    #[pin]
    stream: futures::stream::Fuse<Pin<Box<dyn Stream<Item = Result<Bytes, io::Error>> + Send>>>,
}

impl ImplAsyncRead {
    fn new(stream: Pin<Box<dyn Stream<Item = Result<Bytes, io::Error>> + Send>>) -> Self {
        ImplAsyncRead {
            buffer: BytesMut::new(),
            stream: stream.fuse(),
        }
    }
}

impl AsyncRead for ImplAsyncRead {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        let this = self.project();
        if this.buffer.is_empty() {
            match futures::ready!(this.stream.poll_next(cx)) {
                None => return Poll::Ready(Ok(0)),
                Some(Err(e)) => return Poll::Ready(Err(e)),
                Some(Ok(bytes)) => {
                    this.buffer.put(bytes);
                }
            }
        }
        let available = std::cmp::min(buf.len(), this.buffer.len());
        let bytes = this.buffer.split_to(available);
        let (left, _) = buf.split_at_mut(available);
        left.copy_from_slice(&bytes[..available]);
        Poll::Ready(Ok(available))
    }
}

#[pin_project]
struct ImplBlockingRead {
    #[pin]
    inner: ImplAsyncRead,
}

impl ImplBlockingRead {
    fn new(stream: Pin<Box<dyn Stream<Item = Result<Bytes, io::Error>> + Send + Sync>>) -> Self {
        ImplBlockingRead {
            inner: ImplAsyncRead::new(stream),
        }
    }
}

impl io::Read for ImplBlockingRead {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut rt = tokio::runtime::Runtime::new()?;
        rt.block_on(future::poll_fn(|cx| {
            tokio::io::AsyncRead::poll_read(Pin::new(&mut self.inner), cx, buf)
        }))
    }
}

#[tokio::test]
async fn test_async_read() {
    use bytes::Bytes;
    use tokio::io::AsyncReadExt;

    let chunks = vec![
        Ok(Bytes::from_static(b"1234")),
        Ok(Bytes::from_static(b"5678")),
    ];
    let stream = ByteStream::new(stream::iter(chunks));
    let mut async_read = stream.into_async_read();

    let mut buf = [0u8; 3];
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 3);
    assert_eq!(&buf[..3], b"123");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 1);
    assert_eq!(&buf[..1], b"4");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 3);
    assert_eq!(&buf[..3], b"567");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 1);
    assert_eq!(&buf[..1], b"8");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 0);
}

#[test]
fn test_blocking_read() {
    use bytes::Bytes;
    use std::io::Read;

    let chunks = vec![
        Ok(Bytes::from_static(b"1234")),
        Ok(Bytes::from_static(b"5678")),
    ];
    let stream = ByteStream::new(stream::iter(chunks));
    let mut async_read = stream.into_blocking_read();

    let mut buf = [0u8; 3];
    assert_eq!(async_read.read(&mut buf).unwrap(), 3);
    assert_eq!(&buf[..3], b"123");
    assert_eq!(async_read.read(&mut buf).unwrap(), 1);
    assert_eq!(&buf[..1], b"4");
    assert_eq!(async_read.read(&mut buf).unwrap(), 3);
    assert_eq!(&buf[..3], b"567");
    assert_eq!(async_read.read(&mut buf).unwrap(), 1);
    assert_eq!(&buf[..1], b"8");
    assert_eq!(async_read.read(&mut buf).unwrap(), 0);
}
<commit_msg>Added new_with_size to ByteStream<commit_after>use std::fmt;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};

use bytes::{BufMut, Bytes, BytesMut};
use futures::{future, stream, Stream, StreamExt};
use pin_project::pin_project;
use tokio::io::AsyncRead;

/// Stream of bytes.
#[pin_project]
pub struct ByteStream {
    size_hint: Option<usize>,
    #[pin]
    inner: Pin<Box<dyn Stream<Item = Result<Bytes, io::Error>> + Send + Sync + 'static>>,
}

impl ByteStream {
    /// Create a new `ByteStream` by wrapping a `futures` stream.
    pub fn new<S>(stream: S) -> ByteStream
    where
        S: Stream<Item = Result<Bytes, io::Error>> + Send + Sync + 'static,
    {
        ByteStream {
            size_hint: None,
            inner: Box::pin(stream),
        }
    }

    /// Creates a new `ByteStream` by wrapping a `futures` stream. Allows for the addition of a
    /// size_hint to satisy S3's `PutObject` API.
    pub fn new_with_size<S>(stream: S, size_hint: usize) -> ByteStream
    where
        S: Stream<Item = Result<Bytes, io::Error>> + Send + Sync + 'static,
    {
        ByteStream {
            size_hint: Some(size_hint),
            inner: Box::pin(stream),
        }
    }

    pub(crate) fn size_hint(&self) -> Option<usize> {
        self.size_hint
    }

    /// Return an implementation of `AsyncRead` that uses async i/o to consume the stream.
    pub fn into_async_read(self) -> impl AsyncRead + Send {
        ImplAsyncRead::new(self.inner)
    }

    /// Return an implementation of `Read` that uses blocking i/o to consume the stream.
    pub fn into_blocking_read(self) -> impl io::Read + Send {
        ImplBlockingRead::new(self.inner)
    }
}

impl From<Vec<u8>> for ByteStream {
    fn from(buf: Vec<u8>) -> ByteStream {
        ByteStream {
            size_hint: Some(buf.len()),
            inner: Box::pin(stream::once(async move { Ok(Bytes::from(buf)) })),
        }
    }
}

impl fmt::Debug for ByteStream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<ByteStream size_hint={:?}>", self.size_hint)
    }
}

impl Stream for ByteStream {
    type Item = Result<Bytes, io::Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let this = self.project();
        this.inner.poll_next(cx)
    }
}

#[pin_project]
struct ImplAsyncRead {
    buffer: BytesMut,
    #[pin]
    stream: futures::stream::Fuse<Pin<Box<dyn Stream<Item = Result<Bytes, io::Error>> + Send>>>,
}

impl ImplAsyncRead {
    fn new(stream: Pin<Box<dyn Stream<Item = Result<Bytes, io::Error>> + Send>>) -> Self {
        ImplAsyncRead {
            buffer: BytesMut::new(),
            stream: stream.fuse(),
        }
    }
}

impl AsyncRead for ImplAsyncRead {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        let this = self.project();
        if this.buffer.is_empty() {
            match futures::ready!(this.stream.poll_next(cx)) {
                None => return Poll::Ready(Ok(0)),
                Some(Err(e)) => return Poll::Ready(Err(e)),
                Some(Ok(bytes)) => {
                    this.buffer.put(bytes);
                }
            }
        }
        let available = std::cmp::min(buf.len(), this.buffer.len());
        let bytes = this.buffer.split_to(available);
        let (left, _) = buf.split_at_mut(available);
        left.copy_from_slice(&bytes[..available]);
        Poll::Ready(Ok(available))
    }
}

#[pin_project]
struct ImplBlockingRead {
    #[pin]
    inner: ImplAsyncRead,
}

impl ImplBlockingRead {
    fn new(stream: Pin<Box<dyn Stream<Item = Result<Bytes, io::Error>> + Send + Sync>>) -> Self {
        ImplBlockingRead {
            inner: ImplAsyncRead::new(stream),
        }
    }
}

impl io::Read for ImplBlockingRead {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut rt = tokio::runtime::Runtime::new()?;
        rt.block_on(future::poll_fn(|cx| {
            tokio::io::AsyncRead::poll_read(Pin::new(&mut self.inner), cx, buf)
        }))
    }
}

#[tokio::test]
async fn test_async_read() {
    use bytes::Bytes;
    use tokio::io::AsyncReadExt;

    let chunks = vec![
        Ok(Bytes::from_static(b"1234")),
        Ok(Bytes::from_static(b"5678")),
    ];
    let stream = ByteStream::new(stream::iter(chunks));
    let mut async_read = stream.into_async_read();

    let mut buf = [0u8; 3];
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 3);
    assert_eq!(&buf[..3], b"123");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 1);
    assert_eq!(&buf[..1], b"4");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 3);
    assert_eq!(&buf[..3], b"567");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 1);
    assert_eq!(&buf[..1], b"8");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 0);
}

#[test]
fn test_blocking_read() {
    use bytes::Bytes;
    use std::io::Read;

    let chunks = vec![
        Ok(Bytes::from_static(b"1234")),
        Ok(Bytes::from_static(b"5678")),
    ];
    let stream = ByteStream::new(stream::iter(chunks));
    let mut async_read = stream.into_blocking_read();

    let mut buf = [0u8; 3];
    assert_eq!(async_read.read(&mut buf).unwrap(), 3);
    assert_eq!(&buf[..3], b"123");
    assert_eq!(async_read.read(&mut buf).unwrap(), 1);
    assert_eq!(&buf[..1], b"4");
    assert_eq!(async_read.read(&mut buf).unwrap(), 3);
    assert_eq!(&buf[..3], b"567");
    assert_eq!(async_read.read(&mut buf).unwrap(), 1);
    assert_eq!(&buf[..1], b"8");
    assert_eq!(async_read.read(&mut buf).unwrap(), 0);
}

#[tokio::test]
async fn test_new_with_size_read() {
    use bytes::Bytes;
    use tokio::io::AsyncReadExt;

    let chunks = vec![
        Ok(Bytes::from_static(b"1234")),
        Ok(Bytes::from_static(b"5678")),
    ];
    let stream = ByteStream::new_with_size(stream::iter(chunks), 8);

    assert_eq!(stream.size_hint, Some(8));

    let mut async_read = stream.into_async_read();

    let mut buf = [0u8; 3];
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 3);
    assert_eq!(&buf[..3], b"123");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 1);
    assert_eq!(&buf[..1], b"4");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 3);
    assert_eq!(&buf[..3], b"567");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 1);
    assert_eq!(&buf[..1], b"8");
    assert_eq!(async_read.read(&mut buf).await.unwrap(), 0);
}
<|endoftext|>


<commit_before>use values::RcValue;

use std::collections::HashMap;

pub struct Env<'a> {
    defs: HashMap<String, RcValue>,
    outer: Option<&'a Env<'a>>,
}

impl<'a> Env<'a> {
    pub fn new() -> Env<'a> {
        Env {
            defs: HashMap::new(),
            outer: None,
        }
    }

    pub fn wraps(outer: &'a Env) -> Env<'a> {
        Env {
            defs: HashMap::new(),
            outer: Some(outer),
        }
    }

    pub fn set(&mut self, name: String, expr: RcValue) {
        self.defs.insert(name, expr);
    }

    pub fn get(&self, name: &String) -> Option<RcValue> {
        match self.defs.get(name) {
            Some(value) => Some(value.clone()),
            None        => self.get_from_outer(name),
        }
    }

    fn get_from_outer(&self, name: &String) -> Option<RcValue> {
        self.outer.and_then(|env| env.get(name))
    }

    pub fn remove(&mut self, name: &String) {
        self.defs.remove(name);
    }
}
<commit_msg>Removed unused Env#remove.<commit_after>use values::RcValue;

use std::collections::HashMap;

pub struct Env<'a> {
    defs: HashMap<String, RcValue>,
    outer: Option<&'a Env<'a>>,
}

impl<'a> Env<'a> {
    pub fn new() -> Env<'a> {
        Env {
            defs: HashMap::new(),
            outer: None,
        }
    }

    pub fn wraps(outer: &'a Env) -> Env<'a> {
        Env {
            defs: HashMap::new(),
            outer: Some(outer),
        }
    }

    pub fn set(&mut self, name: String, expr: RcValue) {
        self.defs.insert(name, expr);
    }

    pub fn get(&self, name: &String) -> Option<RcValue> {
        match self.defs.get(name) {
            Some(value) => Some(value.clone()),
            None        => self.get_from_outer(name),
        }
    }

    fn get_from_outer(&self, name: &String) -> Option<RcValue> {
        self.outer.and_then(|env| env.get(name))
    }
}
<|endoftext|>


<commit_before>use std::io::process::Command;

fn run(input: &str, set1: &str, set2: &str) -> Vec<u8> {
    let mut process = Command::new("build/tr").arg(set1).arg(set2).spawn().unwrap();

    process.stdin.take_unwrap().write_str(input).unwrap();

    let po = match process.wait_with_output() {
        Ok(p) => p,
        Err(err) => fail!("{}", err),
    };
    po.output
}

#[test]
fn test_toupper() {
    let out = run("!abcd!", "a-z", "A-Z");
    assert_eq!(out.as_slice(), bytes!("!ABCD!"));
}

#[test]
fn test_small_set2() {
    let out = run("@0123456789", "0-9", "X");
    assert_eq!(out.as_slice(), bytes!("@XXXXXXXXXX"));
}

#[test]
fn test_unicode() {
    let out = run("(,°□°）, ┬─┬", ", ┬─┬", "╯︵┻━┻");
    assert_eq!(out.as_slice(), bytes!("(╯°□°）╯︵┻━┻"));
}

<commit_msg>tr: add -c/-d tests<commit_after>use std::io::process::Command;

fn run(input: &str, args: &[&'static str]) -> Vec<u8> {
    let mut process = Command::new("build/tr").args(args).spawn().unwrap();

    process.stdin.take_unwrap().write_str(input).unwrap();

    let po = match process.wait_with_output() {
        Ok(p) => p,
        Err(err) => fail!("{}", err),
    };
    po.output
}

#[test]
fn test_toupper() {
    let out = run("!abcd!", ["a-z", "A-Z"]);
    assert_eq!(out.as_slice(), bytes!("!ABCD!"));
}

#[test]
fn test_small_set2() {
    let out = run("@0123456789", ["0-9", "X"]);
    assert_eq!(out.as_slice(), bytes!("@XXXXXXXXXX"));
}

#[test]
fn test_unicode() {
    let out = run("(,°□°）, ┬─┬", [", ┬─┬", "╯︵┻━┻"]);
    assert_eq!(out.as_slice(), bytes!("(╯°□°）╯︵┻━┻"));
}

#[test]
fn test_delete() {
    let out = run("aBcD", ["-d", "a-z"]);
    assert_eq!(out.as_slice(), bytes!("BD"));
}

#[test]
fn test_delete_complement() {
    let out = run("aBcD", ["-d", "-c", "a-z"]);
    assert_eq!(out.as_slice(), bytes!("ac"));
}

<|endoftext|>


<commit_before>use dns_parser::Packet as DnsPacket;
use dns_parser::Opcode;
use serde_json::{Value, Map, Number};

pub struct DnsHeader {
	id: Number,
	opcode: String,
	total_questions: Number,
	total_answer_rrs: Number,
	total_authority_rrs: Number,
	total_additional_rrs: Number,
}

impl DnsHeader {
	pub fn new(p: &DnsPacket) -> DnsHeader {
		let opcode_number = p.header.opcode;
		let opcode_string = match opcode_number {
			Opcode::StandardQuery => "QUERY",
			Opcode::InverseQuery => "IQUERY",
			Opcode::ServerStatusRequest => "STATUS",
			_ => "UNKNOWN",
		};

		DnsHeader {
			id: Number::from(p.header.id),
			opcode: opcode_string.to_string(),
			total_questions: Number::from(p.header.questions),
			total_answer_rrs: Number::from(p.header.answers),
			total_authority_rrs: Number::from(p.header.nameservers),
			total_additional_rrs: Number::from(p.header.additional),
		}
	}

	pub fn to_json_map(&self) -> Map<String, Value> {
		let mut header = Map::new();

		header.insert("id".to_string(), Value::Number(self.id.clone()));
		header.insert("opcode".to_string(), Value::String(self.opcode.clone()));
		header.insert("total_questions".to_string(), Value::Number(self.total_questions.clone()));
		header.insert("total_answer_rrs".to_string(), Value::Number(self.total_answer_rrs.clone()));
		header.insert("total_authority_rrs".to_string(), Value::Number(self.total_authority_rrs.clone()));
		header.insert("total_additional_rrs".to_string(), Value::Number(self.total_additional_rrs.clone()));

		header
	}
}<commit_msg>Parse DNS flags<commit_after>use dns_parser::Packet as DnsPacket;
use dns_parser::Opcode;
use serde_json::{Value, Map, Number};

pub struct DnsHeader {
	id: Number,
	opcode: String,
	flags: Value,
	total_questions: Number,
	total_answer_rrs: Number,
	total_authority_rrs: Number,
	total_additional_rrs: Number,
}

impl DnsHeader {
	pub fn new(p: &DnsPacket) -> DnsHeader {
		let opcode_number = p.header.opcode;
		let opcode_string = match opcode_number {
			Opcode::StandardQuery => "QUERY",
			Opcode::InverseQuery => "IQUERY",
			Opcode::ServerStatusRequest => "STATUS",
			_ => "UNKNOWN",
		};

		let mut flags: Vec<&str> = Vec::new();
		if p.header.authoritative {
			flags.push("AA");
		}
		if p.header.truncated {
			flags.push("TC");
		}
		if p.header.recursion_desired {
			flags.push("RD");
		}
		if p.header.recursion_available {
			flags.push("RA");
		}
		if p.header.authenticated_data {
			flags.push("AD");
		}
		if p.header.checking_disabled {
			flags.push("CD");
		}

		DnsHeader {
			id: Number::from(p.header.id),
			opcode: opcode_string.to_string(),
			flags: Value::from(flags),
			total_questions: Number::from(p.header.questions),
			total_answer_rrs: Number::from(p.header.answers),
			total_authority_rrs: Number::from(p.header.nameservers),
			total_additional_rrs: Number::from(p.header.additional),
		}
	}

	pub fn to_json_map(&self) -> Map<String, Value> {
		let mut header = Map::new();

		header.insert("id".to_string(), Value::Number(self.id.clone()));
		header.insert("opcode".to_string(), Value::String(self.opcode.clone()));
		header.insert("flags".to_string(), self.flags.clone());
		header.insert("total_questions".to_string(), Value::Number(self.total_questions.clone()));
		header.insert("total_answer_rrs".to_string(), Value::Number(self.total_answer_rrs.clone()));
		header.insert("total_authority_rrs".to_string(), Value::Number(self.total_authority_rrs.clone()));
		header.insert("total_additional_rrs".to_string(), Value::Number(self.total_additional_rrs.clone()));

		header
	}
}<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::cmp;
use std::fmt;
use std::io;
use std::ops::Deref;

pub use self::Doc::{Nil, Append, Space, Group, Nest, Newline, Text};

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
enum Mode {
    Break,
    Flat,
}

/// The concrete document type. This type is not meant to be used directly. Instead use the static
/// functions on `Doc` or the methods on an `DocAllocator`.
///
/// The `B` parameter is used to abstract over pointers to `Doc`. See `RefDoc` and `BoxDoc` for how
/// it is used
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Doc<'a, B> {
    Nil,
    Append(B, B),
    Group(B),
    Nest(usize, B),
    Space,
    Newline,
    Text(Cow<'a, str>),
}

impl<'a, B, S> From<S> for Doc<'a, B>
where
    S: Into<Cow<'a, str>>,
{
    fn from(s: S) -> Doc<'a, B> {
        Doc::Text(s.into())
    }
}

trait Render {
    type Error;
    fn write_str(&mut self, s: &str) -> Result<usize, Self::Error>;
    fn write_str_all(&mut self, s: &str) -> Result<(), Self::Error>;
}

struct IoWrite<W>(W);
impl<W> Render for IoWrite<W>
where
    W: io::Write,
{
    type Error = io::Error;

    fn write_str(&mut self, s: &str) -> io::Result<usize> {
        self.0.write(s.as_bytes())
    }
    fn write_str_all(&mut self, s: &str) -> io::Result<()> {
        self.0.write_all(s.as_bytes())
    }
}

struct FmtWrite<W>(W);
impl<W> Render for FmtWrite<W>
where
    W: fmt::Write,
{
    type Error = fmt::Error;

    fn write_str(&mut self, s: &str) -> Result<usize, fmt::Error> {
        self.write_str_all(s).map(|_| s.len())
    }
    fn write_str_all(&mut self, s: &str) -> fmt::Result {
        self.0
            .write_str(s)
    }
}

impl<'a, B> Doc<'a, B> {
    /// Writes a rendered document.
    #[inline]
    pub fn render<'b, W>(&'b self, width: usize, out: &mut W) -> io::Result<()>
    where
        B: Deref<Target = Doc<'b, B>>,
        W: ?Sized + io::Write
    {
        best(self, width, &mut IoWrite(out))
    }

    #[inline]
    pub fn render_fmt<'b, W>(
        &'b self,
        width: usize,
        out: &mut W,
    ) -> fmt::Result
    where
        B: Deref<Target = Doc<'b, B>>,
        W: ?Sized + fmt::Write
    {
        best(self, width, &mut FmtWrite(out))
    }
}

type Cmd<'a, B> = (usize, Mode, &'a Doc<'a, B>);

fn write_newline<W>(ind: usize, out: &mut W) -> Result<(), W::Error>
where
    W: ?Sized + Render,
{
    try!(out.write_str_all("\n"));
    write_spaces(ind, out)
}

fn write_spaces<W>(spaces: usize, out: &mut W) -> Result<(), W::Error>
where
    W: ?Sized + Render,
{
    macro_rules! make_spaces {
        () => {
            ""
        };
        ($s: tt $($t: tt)*) => {
            concat!("          ", make_spaces!($($t)*))
        };
    }
    const SPACES: &str = make_spaces!(,,,,,,,,,,);
    let mut inserted = 0;
    while inserted < spaces {
        let insert = cmp::min(SPACES.len(), spaces - inserted);
        inserted += try!(out.write_str(&SPACES[..insert]));
    }
    Ok(())
}

#[inline]
fn fitting<'a, B>(
    next: Cmd<'a, B>,
    bcmds: &Vec<Cmd<'a, B>>,
    fcmds: &mut Vec<Cmd<'a, B>>,
    mut rem: isize,
) -> bool
where
    B: Deref<Target = Doc<'a, B>>,
{
    let mut bidx = bcmds.len();
    fcmds.clear(); // clear from previous calls from best
    fcmds.push(next);
    while rem >= 0 {
        match fcmds.pop() {
            None => {
                if bidx == 0 {
                    // All commands have been processed
                    return true;
                } else {
                    fcmds.push(bcmds[bidx - 1]);
                    bidx -= 1;
                }
            }
            Some((ind, mode, doc)) => {
                match doc {
                    &Nil => {}
                    &Append(ref ldoc, ref rdoc) => {
                        fcmds.push((ind, mode, rdoc));
                        // Since appended documents often appear in sequence on the left side we
                        // gain a slight performance increase by batching these pushes (avoiding
                        // to push and directly pop `Append` documents)
                        let mut doc = ldoc;
                        while let Append(ref l, ref r) = **doc {
                            fcmds.push((ind, mode, r));
                            doc = l;
                        }
                        fcmds.push((ind, mode, doc));
                    }
                    &Group(ref doc) => {
                        fcmds.push((ind, mode, doc));
                    }
                    &Nest(off, ref doc) => {
                        fcmds.push((ind + off, mode, doc));
                    }
                    &Space => {
                        match mode {
                            Mode::Flat => {
                                rem -= 1;
                            }
                            Mode::Break => {
                                return true;
                            }
                        }
                    }
                    &Newline => return true,
                    &Text(ref str) => {
                        rem -= str.len() as isize;
                    }
                }
            }
        }
    }
    false
}

#[inline]
fn best<'a, W, B>(doc: &'a Doc<'a, B>, width: usize, out: &mut W) -> Result<(), W::Error>
where
    B: Deref<Target = Doc<'a, B>>,
    W: ?Sized + Render,
{
    let mut pos = 0usize;
    let mut bcmds = vec![(0usize, Mode::Break, doc)];
    let mut fcmds = vec![];
    while let Some((ind, mode, doc)) = bcmds.pop() {
        match doc {
            &Nil => {}
            &Append(ref ldoc, ref rdoc) => {
                bcmds.push((ind, mode, rdoc));
                let mut doc = ldoc;
                while let Append(ref l, ref r) = **doc {
                    bcmds.push((ind, mode, r));
                    doc = l;
                }
                bcmds.push((ind, mode, doc));
            }
            &Group(ref doc) => {
                match mode {
                    Mode::Flat => {
                        bcmds.push((ind, Mode::Flat, doc));
                    }
                    Mode::Break => {
                        let next = (ind, Mode::Flat, &**doc);
                        let rem = width as isize - pos as isize;
                        if fitting(next, &bcmds, &mut fcmds, rem) {
                            bcmds.push(next);
                        } else {
                            bcmds.push((ind, Mode::Break, doc));
                        }
                    }
                }
            }
            &Nest(off, ref doc) => {
                bcmds.push((ind + off, mode, doc));
            }
            &Space => {
                match mode {
                    Mode::Flat => {
                        try!(write_spaces(1, out));
                    }
                    Mode::Break => {
                        try!(write_newline(ind, out));
                    }
                }
                pos = ind;
            }
            &Newline => {
                try!(write_newline(ind, out));
                pos = ind;
            }
            &Text(ref s) => {
                try!(out.write_str_all(s));
                pos += s.len();
            }
        }
    }
    Ok(())
}
<commit_msg>feat: Add a fmt::Display adapter for documents<commit_after>use std::borrow::Cow;
use std::cmp;
use std::fmt;
use std::io;
use std::ops::Deref;

pub use self::Doc::{Nil, Append, Space, Group, Nest, Newline, Text};

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
enum Mode {
    Break,
    Flat,
}

/// The concrete document type. This type is not meant to be used directly. Instead use the static
/// functions on `Doc` or the methods on an `DocAllocator`.
///
/// The `B` parameter is used to abstract over pointers to `Doc`. See `RefDoc` and `BoxDoc` for how
/// it is used
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Doc<'a, B> {
    Nil,
    Append(B, B),
    Group(B),
    Nest(usize, B),
    Space,
    Newline,
    Text(Cow<'a, str>),
}

impl<'a, B, S> From<S> for Doc<'a, B>
where
    S: Into<Cow<'a, str>>,
{
    fn from(s: S) -> Doc<'a, B> {
        Doc::Text(s.into())
    }
}

trait Render {
    type Error;
    fn write_str(&mut self, s: &str) -> Result<usize, Self::Error>;
    fn write_str_all(&mut self, s: &str) -> Result<(), Self::Error>;
}

struct IoWrite<W>(W);
impl<W> Render for IoWrite<W>
where
    W: io::Write,
{
    type Error = io::Error;

    fn write_str(&mut self, s: &str) -> io::Result<usize> {
        self.0.write(s.as_bytes())
    }
    fn write_str_all(&mut self, s: &str) -> io::Result<()> {
        self.0.write_all(s.as_bytes())
    }
}

struct FmtWrite<W>(W);
impl<W> Render for FmtWrite<W>
where
    W: fmt::Write,
{
    type Error = fmt::Error;

    fn write_str(&mut self, s: &str) -> Result<usize, fmt::Error> {
        self.write_str_all(s).map(|_| s.len())
    }
    fn write_str_all(&mut self, s: &str) -> fmt::Result {
        self.0.write_str(s)
    }
}

pub struct Pretty<'a, D>
where
    D: 'a,
{
    doc: &'a Doc<'a, D>,
    width: usize,
}

impl<'a, D> fmt::Display for Pretty<'a, D>
where
    D: Deref<Target = Doc<'a, D>>,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.doc.render_fmt(self.width, f)
    }
}

impl<'a, B> Doc<'a, B> {
    /// Writes a rendered document to a `std::io::Write` object.
    #[inline]
    pub fn render<'b, W>(&'b self, width: usize, out: &mut W) -> io::Result<()>
    where
        B: Deref<Target = Doc<'b, B>>,
        W: ?Sized + io::Write,
    {
        best(self, width, &mut IoWrite(out))
    }

    /// Writes a rendered document to a `std::fmt::Write` object.
    #[inline]
    pub fn render_fmt<'b, W>(&'b self, width: usize, out: &mut W) -> fmt::Result
    where
        B: Deref<Target = Doc<'b, B>>,
        W: ?Sized + fmt::Write,
    {
        best(self, width, &mut FmtWrite(out))
    }

    /// Returns a value which implements `std::fmt::Display`
    ///
    /// ```
    /// use pretty::Doc;
    /// let doc = Doc::group(
    ///     Doc::text("hello").append(Doc::space()).append(Doc::text("world"))
    /// );
    /// assert_eq!(format!("{}", doc.pretty(80)), "hello world");
    /// ```
    #[inline]
    pub fn pretty<'b>(&'b self, width: usize) -> Pretty<'b, B>
    where
        B: Deref<Target = Doc<'b, B>>,
    {
        Pretty {
            doc: self,
            width: width,
        }
    }
}

type Cmd<'a, B> = (usize, Mode, &'a Doc<'a, B>);

fn write_newline<W>(ind: usize, out: &mut W) -> Result<(), W::Error>
where
    W: ?Sized + Render,
{
    try!(out.write_str_all("\n"));
    write_spaces(ind, out)
}

fn write_spaces<W>(spaces: usize, out: &mut W) -> Result<(), W::Error>
where
    W: ?Sized + Render,
{
    macro_rules! make_spaces {
        () => {
            ""
        };
        ($s: tt $($t: tt)*) => {
            concat!("          ", make_spaces!($($t)*))
        };
    }
    const SPACES: &str = make_spaces!(,,,,,,,,,,);
    let mut inserted = 0;
    while inserted < spaces {
        let insert = cmp::min(SPACES.len(), spaces - inserted);
        inserted += try!(out.write_str(&SPACES[..insert]));
    }
    Ok(())
}

#[inline]
fn fitting<'a, B>(
    next: Cmd<'a, B>,
    bcmds: &Vec<Cmd<'a, B>>,
    fcmds: &mut Vec<Cmd<'a, B>>,
    mut rem: isize,
) -> bool
where
    B: Deref<Target = Doc<'a, B>>,
{
    let mut bidx = bcmds.len();
    fcmds.clear(); // clear from previous calls from best
    fcmds.push(next);
    while rem >= 0 {
        match fcmds.pop() {
            None => {
                if bidx == 0 {
                    // All commands have been processed
                    return true;
                } else {
                    fcmds.push(bcmds[bidx - 1]);
                    bidx -= 1;
                }
            }
            Some((ind, mode, doc)) => {
                match doc {
                    &Nil => {}
                    &Append(ref ldoc, ref rdoc) => {
                        fcmds.push((ind, mode, rdoc));
                        // Since appended documents often appear in sequence on the left side we
                        // gain a slight performance increase by batching these pushes (avoiding
                        // to push and directly pop `Append` documents)
                        let mut doc = ldoc;
                        while let Append(ref l, ref r) = **doc {
                            fcmds.push((ind, mode, r));
                            doc = l;
                        }
                        fcmds.push((ind, mode, doc));
                    }
                    &Group(ref doc) => {
                        fcmds.push((ind, mode, doc));
                    }
                    &Nest(off, ref doc) => {
                        fcmds.push((ind + off, mode, doc));
                    }
                    &Space => {
                        match mode {
                            Mode::Flat => {
                                rem -= 1;
                            }
                            Mode::Break => {
                                return true;
                            }
                        }
                    }
                    &Newline => return true,
                    &Text(ref str) => {
                        rem -= str.len() as isize;
                    }
                }
            }
        }
    }
    false
}

#[inline]
fn best<'a, W, B>(doc: &'a Doc<'a, B>, width: usize, out: &mut W) -> Result<(), W::Error>
where
    B: Deref<Target = Doc<'a, B>>,
    W: ?Sized + Render,
{
    let mut pos = 0usize;
    let mut bcmds = vec![(0usize, Mode::Break, doc)];
    let mut fcmds = vec![];
    while let Some((ind, mode, doc)) = bcmds.pop() {
        match doc {
            &Nil => {}
            &Append(ref ldoc, ref rdoc) => {
                bcmds.push((ind, mode, rdoc));
                let mut doc = ldoc;
                while let Append(ref l, ref r) = **doc {
                    bcmds.push((ind, mode, r));
                    doc = l;
                }
                bcmds.push((ind, mode, doc));
            }
            &Group(ref doc) => {
                match mode {
                    Mode::Flat => {
                        bcmds.push((ind, Mode::Flat, doc));
                    }
                    Mode::Break => {
                        let next = (ind, Mode::Flat, &**doc);
                        let rem = width as isize - pos as isize;
                        if fitting(next, &bcmds, &mut fcmds, rem) {
                            bcmds.push(next);
                        } else {
                            bcmds.push((ind, Mode::Break, doc));
                        }
                    }
                }
            }
            &Nest(off, ref doc) => {
                bcmds.push((ind + off, mode, doc));
            }
            &Space => {
                match mode {
                    Mode::Flat => {
                        try!(write_spaces(1, out));
                    }
                    Mode::Break => {
                        try!(write_newline(ind, out));
                    }
                }
                pos = ind;
            }
            &Newline => {
                try!(write_newline(ind, out));
                pos = ind;
            }
            &Text(ref s) => {
                try!(out.write_str_all(s));
                pos += s.len();
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::iter::FromIterator;

pub struct StreamOfPrimes {
    seed_primes: Vec<u64>,
    upper_bound: u64,
    current_index: usize,
    segment_size: usize,
    next_segment_floor: u64,
}

fn primes_from_next_seive_segment(floor: u64, size: usize, seed_primes: &Vec<u64>) -> Vec<u64> {
    let mut result = Vec::with_capacity(size / 2);

    let mut new_segment = vec![true; size+1];
    for i in seed_primes.iter().take_while(|&x| x.pow(2) < (floor + size as u64)) {
        let p = i.clone() as f64;

        let start_at = (floor as f64 / p).ceil() as u64;
        let end_at = ((floor as usize + size) as f64 / p).floor() as u64;

        for j in start_at..end_at + 1 {
            let target = (i * j) - floor;
            new_segment[target as usize] = false;
        }
    }

    for (pos, &is_prime) in new_segment.iter().enumerate() {
        if is_prime {
            result.push(pos as u64 + floor)
        }
    }

    result
}

impl Iterator for StreamOfPrimes {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current_index < self.seed_primes.len() {
            let current_index = self.current_index;
            self.current_index += 1;
            Some(self.seed_primes[current_index])
        } else if self.next_segment_floor >= self.upper_bound {
            None
        } else {
            let mut next_segment = primes_from_next_seive_segment(self.next_segment_floor,
                                                                  self.segment_size,
                                                                  &self.seed_primes);

            self.seed_primes.append(&mut next_segment);

            self.next_segment_floor = self.next_segment_floor + self.segment_size as u64;

            self.next()
        }
    }
}

pub fn stream_of_primes(upper_bound: u64) -> StreamOfPrimes {

    let segment_size = if upper_bound > 1000 {
        (upper_bound as f64).sqrt().ceil() as usize
    } else {
        (upper_bound + 1) as usize
    };

    let mut initial_seive = vec![true; segment_size + 1];
    initial_seive[0] = false;
    initial_seive[1] = false;

    let mut seed_primes = Vec::with_capacity(segment_size / 2);

    for i in 2..segment_size {
        if initial_seive[i] {
            for j in i..(segment_size / i) + 1 {
                initial_seive[i * j] = false
            }
            seed_primes.push(i as u64);
        }
    }

    StreamOfPrimes {
        seed_primes: seed_primes,
        upper_bound: upper_bound,
        current_index: 0,
        segment_size: segment_size,
        next_segment_floor: segment_size as u64,
    }
}

#[derive(Debug)]
pub struct PrimeBag {
    primes: Vec<u64>,
}

impl PrimeBag {
    pub fn merged_with(&self, other: &PrimeBag) -> PrimeBag {
        let mut pos_self = 0;
        let mut pos_other = 0;
        let mut new_primes = Vec::with_capacity(self.primes.len() + other.primes.len());
        loop {
            if pos_self >= self.primes.len() || pos_other >= other.primes.len() {
                break;
            }
            if self.primes[pos_self] == other.primes[pos_other] {
                new_primes.push(self.primes[pos_self]);
                pos_self += 1;
                pos_other += 1;
            } else if self.primes[pos_self] < other.primes[pos_other] {
                new_primes.push(self.primes[pos_self]);
                pos_self += 1;
            } else if self.primes[pos_self] > other.primes[pos_other] {
                new_primes.push(other.primes[pos_other]);
                pos_other += 1;
            }
        }

        new_primes.extend_from_slice(&self.primes[pos_self..]);
        new_primes.extend_from_slice(&other.primes[pos_other..]);

        PrimeBag { primes: new_primes }
    }

    pub fn from<T>(from: T) -> PrimeBag
        where T: IntoIterator<Item = u64>
    {
        PrimeBag { primes: Vec::from_iter(from) }
    }

    pub fn empty() -> PrimeBag {
        PrimeBag { primes: vec![] }
    }
}

impl IntoIterator for PrimeBag {
    type Item = u64;
    type IntoIter = ::std::vec::IntoIter<u64>;

    fn into_iter(self) -> Self::IntoIter {
        self.primes.into_iter()
    }
}

#[cfg(test)]
mod tests {
    use super::stream_of_primes;
    use super::PrimeBag;
    use std::iter::FromIterator;

    #[test]
    fn stream_of_primes_yields_some_primes() {
        let mut s = stream_of_primes(100);
        assert_eq!(s.next(), Some(2));
        assert_eq!(s.next(), Some(3));
        assert_eq!(s.next(), Some(5));
        assert_eq!(s.next(), Some(7));
    }

    #[test]
    fn stream_of_primes_yields_primes_including_max() {
        let mut s = stream_of_primes(7);
        assert_eq!(s.next(), Some(2));
        assert_eq!(s.next(), Some(3));
        assert_eq!(s.next(), Some(5));
        assert_eq!(s.next(), Some(7));
    }

    #[test]
    fn stream_of_primes_finished_at_its_upper_bound() {
        let r = stream_of_primes(100).collect::<Vec<_>>();
        assert_eq!(r,
                   vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
                        71, 73, 79, 83, 89, 97]);
    }

    #[test]
    fn merging_disjoint_prime_bags_leaves_us_with_both_sets_of_primes_merged() {
        let p = PrimeBag::from(vec![2, 3, 5]);
        let res = p.merged_with(&PrimeBag::from(vec![7, 11, 13]));
        let result: Vec<u64> = Vec::from_iter(res);

        assert_eq!(result, vec![2, 3, 5, 7, 11, 13]);
    }

    #[test]
    fn merging_overlapping_prime_bags_dedups_where_possible() {
        let p = PrimeBag::from(vec![2, 3, 5]);
        let res = p.merged_with(&PrimeBag::from(vec![3, 5, 7]));

        let result: Vec<u64> = Vec::from_iter(res);

        assert_eq!(result, vec![2, 3, 5, 7]);
    }

    #[test]
    fn merging_prime_bags_with_same_factor_different_number_of_times_takes_the_max() {
        let p = PrimeBag::from(vec![2, 3, 5, 5]);
        let res = p.merged_with(&PrimeBag::from(vec![3, 3, 5, 7]));

        let result: Vec<u64> = Vec::from_iter(res);

        assert_eq!(result, vec![2, 3, 3, 5, 5, 7]);
    }
}
<commit_msg>Profile guided tweaks<commit_after>use std::iter::FromIterator;

pub struct StreamOfPrimes {
    seed_primes: Vec<u64>,
    upper_bound: u64,
    current_index: usize,
    segment_size: usize,
    next_segment_floor: u64,
}

fn primes_from_next_seive_segment(floor: u64, size: usize, seed_primes: &Vec<u64>) -> Vec<u64> {
    let mut result = Vec::with_capacity(size / 2);

    let mut new_segment = vec![true; size+1];
    for i in seed_primes.iter().take_while(|&x| x.pow(2) < (floor + size as u64)) {

        let p = i.clone() as f64;
        let start_at = (floor as f64 / p).ceil() as u64;
        let end_at = start_at + (size as f64 / p).floor() as u64;

        for j in start_at..end_at {
            let target = (i * j) - floor;
            new_segment[target as usize] = false;
        }
    }

    for (pos, &is_prime) in new_segment.iter().enumerate() {
        if is_prime {
            result.push(pos as u64 + floor)
        }
    }

    result
}

impl Iterator for StreamOfPrimes {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current_index < self.seed_primes.len() {
            let current_index = self.current_index;
            self.current_index += 1;
            Some(self.seed_primes[current_index])
        } else if self.next_segment_floor >= self.upper_bound {
            None
        } else {
            let mut next_segment = primes_from_next_seive_segment(self.next_segment_floor,
                                                                  self.segment_size,
                                                                  &self.seed_primes);

            self.seed_primes.append(&mut next_segment);

            self.next_segment_floor = self.next_segment_floor + self.segment_size as u64;

            self.next()
        }
    }
}

pub fn stream_of_primes(upper_bound: u64) -> StreamOfPrimes {

    let segment_size = if upper_bound > 1000 {
        (upper_bound as f64).sqrt().ceil() as usize
    } else {
        (upper_bound + 1) as usize
    };

    let mut initial_seive = vec![true; segment_size + 1];
    initial_seive[0] = false;
    initial_seive[1] = false;

    let mut seed_primes = Vec::with_capacity(segment_size / 2);

    for i in 2..segment_size {
        if initial_seive[i] {
            for j in i..(segment_size / i) + 1 {
                initial_seive[i * j] = false
            }
            seed_primes.push(i as u64);
        }
    }

    StreamOfPrimes {
        seed_primes: seed_primes,
        upper_bound: upper_bound,
        current_index: 0,
        segment_size: segment_size,
        next_segment_floor: segment_size as u64,
    }
}

#[derive(Debug)]
pub struct PrimeBag {
    primes: Vec<u64>,
}

impl PrimeBag {
    pub fn merged_with(&self, other: &PrimeBag) -> PrimeBag {
        let mut pos_self = 0;
        let mut pos_other = 0;
        let mut new_primes = Vec::with_capacity(self.primes.len() + other.primes.len());
        loop {
            if pos_self >= self.primes.len() || pos_other >= other.primes.len() {
                break;
            }
            if self.primes[pos_self] == other.primes[pos_other] {
                new_primes.push(self.primes[pos_self]);
                pos_self += 1;
                pos_other += 1;
            } else if self.primes[pos_self] < other.primes[pos_other] {
                new_primes.push(self.primes[pos_self]);
                pos_self += 1;
            } else if self.primes[pos_self] > other.primes[pos_other] {
                new_primes.push(other.primes[pos_other]);
                pos_other += 1;
            }
        }

        new_primes.extend_from_slice(&self.primes[pos_self..]);
        new_primes.extend_from_slice(&other.primes[pos_other..]);

        PrimeBag { primes: new_primes }
    }

    pub fn from<T>(from: T) -> PrimeBag
        where T: IntoIterator<Item = u64>
    {
        PrimeBag { primes: Vec::from_iter(from) }
    }

    pub fn empty() -> PrimeBag {
        PrimeBag { primes: vec![] }
    }
}

impl IntoIterator for PrimeBag {
    type Item = u64;
    type IntoIter = ::std::vec::IntoIter<u64>;

    fn into_iter(self) -> Self::IntoIter {
        self.primes.into_iter()
    }
}

#[cfg(test)]
mod tests {
    use super::stream_of_primes;
    use super::PrimeBag;
    use std::iter::FromIterator;

    #[test]
    fn stream_of_primes_yields_some_primes() {
        let mut s = stream_of_primes(100);
        assert_eq!(s.next(), Some(2));
        assert_eq!(s.next(), Some(3));
        assert_eq!(s.next(), Some(5));
        assert_eq!(s.next(), Some(7));
    }

    #[test]
    fn stream_of_primes_yields_primes_including_max() {
        let mut s = stream_of_primes(7);
        assert_eq!(s.next(), Some(2));
        assert_eq!(s.next(), Some(3));
        assert_eq!(s.next(), Some(5));
        assert_eq!(s.next(), Some(7));
    }

    #[test]
    fn stream_of_primes_finished_at_its_upper_bound() {
        let r = stream_of_primes(100).collect::<Vec<_>>();
        assert_eq!(r,
                   vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
                        71, 73, 79, 83, 89, 97]);
    }

    #[test]
    fn merging_disjoint_prime_bags_leaves_us_with_both_sets_of_primes_merged() {
        let p = PrimeBag::from(vec![2, 3, 5]);
        let res = p.merged_with(&PrimeBag::from(vec![7, 11, 13]));
        let result: Vec<u64> = Vec::from_iter(res);

        assert_eq!(result, vec![2, 3, 5, 7, 11, 13]);
    }

    #[test]
    fn merging_overlapping_prime_bags_dedups_where_possible() {
        let p = PrimeBag::from(vec![2, 3, 5]);
        let res = p.merged_with(&PrimeBag::from(vec![3, 5, 7]));

        let result: Vec<u64> = Vec::from_iter(res);

        assert_eq!(result, vec![2, 3, 5, 7]);
    }

    #[test]
    fn merging_prime_bags_with_same_factor_different_number_of_times_takes_the_max() {
        let p = PrimeBag::from(vec![2, 3, 5, 5]);
        let res = p.merged_with(&PrimeBag::from(vec![3, 3, 5, 7]));

        let result: Vec<u64> = Vec::from_iter(res);

        assert_eq!(result, vec![2, 3, 3, 5, 5, 7]);
    }
}
<|endoftext|>


<commit_before>use shoe;
use cards;
use suit;
use value;
use shoe::DirectShoe;
use std::rand;

pub trait SuitPicker {
    fn suit(&mut self) -> Option<suit::Suit>;
}

struct CycleSuitPicker {
    suitIndex: uint,
}

impl SuitPicker for CycleSuitPicker {
    fn suit(&mut self) -> &suit::Suit {
        self.suitIndex += 1;
        return Some(suit::SUITS[self.suitIndex % 4]);
    }
}

struct SuitCount {
    suit: suit::SuitImpl,
    counts: uint,
}

struct RandomDeckSuitPicker {
    suitCounts: Vec<SuitCount>,
}

impl SuitPicker for RandomDeckSuitPicker {
    fn suit(&mut self) -> Option<suit::Suit> {
        if self.suitCounts.len() == 0 {
            return None;
        }
        let (suitToRet, remove_index) = {
            let suitIndex = rand::random::<uint>() % self.suitCounts.len();
            let ref mut suitToLook = self.suitCounts.get_mut(suitIndex);
            let suitToRet = suitToLook.suit;
            suitToLook.counts -= 1;
            if suitToLook.counts == 0 {
                (suitToRet, Some(suitIndex))
            } else {
                (suitToRet, None)
            }
        };
        match remove_index {
            Some(i) => self.suitCounts.remove(i),
            None => (),
        }
        return Some(suitToRet);
    }
}

pub trait ValuePicker {
    fn value(&mut self) -> Option<value::Value>;
}

struct RandomValuePicker;

impl ValuePicker for RandomValuePicker {
    fn value(&mut self) -> Option<value::Value> {
        let valueIndex = rand::random::<uint>() % value::VALUES.len();
        return Some(value::VALUES[valueIndex]);
    }
}

struct ValueCount {
    value: value::ValueImpl,
    counts: uint,
}

struct RandomDeckValuePicker {
    valueCounts: Vec<ValueCount>,
}

impl ValuePicker for RandomDeckValuePicker {
    fn value(&mut self) -> Option<value::Value> {
        if self.valueCounts.len() == 0 {
            return None;
        }
        let (valueToRet, remove_index) = {
            let valueIndex = rand::random::<uint>() % self.valueCounts.len();
            let ref mut valueToLook = self.valueCounts.get_mut(valueIndex);
            let valueoRet = valueToLook.suit;
            valueToLook.counts -= 1;
            if valueToLook.counts == 0 {
                (valuToRet, Some(valueIndex))
            } else {
                (valueToRet, None)
            }
        };
        match remove_index {
            Some(i) => self.valueCounts.remove(i),
            None => (),
        }
        return Some(valueToRet);
    }
}

pub struct DirectRandomShoe {
   cardCounts: Vec<ValueCount>,
   len: uint,
}

impl shoe::DirectShoe for DirectRandomShoe {
    fn pop(&mut self) -> Option<cards::CardImpl> {
        if self.len == 0 {
            return None;
        }
        // TODO: must be better way than % rand
        let cardIndex = rand::random::<uint>() % self.cardCounts.len();
        let (valueToRet, suitToRet, remove_value_index) = {
            let ref mut cardToLook = self.cardCounts.get_mut(cardIndex);
            let valueToRet = cardToLook.value;
            cardToLook.counts -= 1;

            let suitIndex = rand::random::<uint>() % cardToLook.suitCounts.len();
            let (suitToRet, remove_index) = {
                let ref mut suitToLook = cardToLook.suitCounts.get_mut(suitIndex);
                let suitToRet = suitToLook.suit;
                suitToLook.counts -= 1;
                if suitToLook.counts == 0 {
                    (suitToRet, true)
                } else {
                    (suitToRet, false)
                }
            };
            if remove_index {
                cardToLook.suitCounts.remove(suitIndex);
            }
            if cardToLook.counts == 0 {
                (valueToRet, suitToRet, true)
            } else {
                (valueToRet, suitToRet, false)
            }
        };
        if remove_value_index {
            self.cardCounts.remove(cardIndex);
        }
        self.len -= 1;
        return Some(cards::CardImpl{
            v: valueToRet,
            s: suitToRet,
        });
    }
    fn len(&self) -> uint {
        return self.len;
    }
}

impl DirectRandomShoe {
    fn new(numDeck: uint) ->  DirectRandomShoe {
        let mut c = Vec::new();
        for &v in value::VALUES.iter() {
            let mut sc = Vec::new();
            for &s in suit::SUITS.iter() {
                let scount = SuitCount {
                    suit: s,
                    counts: numDeck,
                };
                sc.push(scount);
            }
            let vc = ValueCount{
                value: v,
                counts: numDeck * 4,
                suitCounts: sc,
            };
            c.push(vc);
        }
        return DirectRandomShoe{
            len: numDeck * 52,
            cardCounts: c,
        };
    }
}

#[test]
fn test_random() {
    let mut randDeck = DirectRandomShoe::new(1);
    shoe::test_single_deck(&mut randDeck);
}
<commit_msg>More changes<commit_after>use shoe;
use cards;
use suit;
use value;
use shoe::DirectShoe;
use std::rand;

pub trait SuitPicker {
    fn suit(&mut self) -> Option<&suit::Suit>;
}

struct CycleSuitPicker {
    suitIndex: uint,
}

impl SuitPicker for CycleSuitPicker {
    fn suit(&mut self) -> Option<&suit::Suit> {
        self.suitIndex += 1;
        let r:&suit::Suit = &suit::SUITS[self.suitIndex % 4];
        return Some(r);
    }
}

struct SuitCount {
    suit: suit::SuitImpl,
    counts: uint,
}

struct RandomDeckSuitPicker {
    suitCounts: Vec<SuitCount>,
}

impl SuitPicker for RandomDeckSuitPicker {
    fn suit(&mut self) -> Option<&suit::Suit> {
        if self.suitCounts.len() == 0 {
            return None;
        }
        let (suitToRet, remove_index) = {
            let suitIndex = rand::random::<uint>() % self.suitCounts.len();
            let ref mut suitToLook = self.suitCounts.get_mut(suitIndex);
            let suitToRet = suitToLook.suit;
            suitToLook.counts -= 1;
            if suitToLook.counts == 0 {
                (suitToRet, Some(suitIndex))
            } else {
                (suitToRet, None)
            }
        };
        match remove_index {
            Some(i) => {self.suitCounts.remove(i);()},
            None => (),
        };
        let r:&suit::Suit = &suitToRet;
        return Some(r);
    }
}

pub trait ValuePicker {
    fn value(&mut self) -> Option<&value::Value>;
}

struct RandomValuePicker;

impl ValuePicker for RandomValuePicker {
    fn value(&mut self) -> Option<&value::Value> {
        let valueIndex = rand::random::<uint>() % value::VALUES.len();
        return Some(&value::VALUES[valueIndex] as &value::Value);
    }
}

struct ValueCount {
    value: value::ValueImpl,
    counts: uint,
}

struct RandomDeckValuePicker {
    valueCounts: Vec<ValueCount>,
}

impl ValuePicker for RandomDeckValuePicker {
    fn value(&mut self) -> Option<&value::Value> {
        if self.valueCounts.len() == 0 {
            return None;
        }
        let (valueToRet, remove_index) = {
            let valueIndex = rand::random::<uint>() % self.valueCounts.len();
            let ref mut valueToLook = self.valueCounts.get_mut(valueIndex);
            let valueToRet = valueToLook.value;
            valueToLook.counts -= 1;
            if valueToLook.counts == 0 {
                (valueToRet, Some(valueIndex))
            } else {
                (valueToRet, None)
            }
        };
        match remove_index {
            Some(i) => {self.valueCounts.remove(i);()},
            None => (),
        }
        return Some(&valueToRet as &value::Value);
    }
}

pub struct GenericShoe<'a> {
    valuePicker: &'a mut ValuePicker + 'a,
    suitPickers: [&'a mut SuitPicker + 'a, ..13],
}
/*
impl shoe::DirectShoe for DirectRandomShoe {
}

impl DirectRandomShoe {
    fn new(numDeck: uint) ->  DirectRandomShoe {
        let mut c = Vec::new();
        for &v in value::VALUES.iter() {
            let mut sc = Vec::new();
            for &s in suit::SUITS.iter() {
                let scount = SuitCount {
                    suit: s,
                    counts: numDeck,
                };
                sc.push(scount);
            }
            let vc = ValueCount{
                value: v,
                counts: numDeck * 4,
                suitCounts: sc,
            };
            c.push(vc);
        }
        return DirectRandomShoe{
            len: numDeck * 52,
            cardCounts: c,
        };
    }
}

#[test]
fn test_random() {
    let mut randDeck = DirectRandomShoe::new(1);
    shoe::test_single_deck(&mut randDeck);
}
*/
<|endoftext|>


<commit_before>use crate::{
    config, db,
    models::Version,
    schema::{crates, readme_renderings, versions},
    uploaders::Uploader,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use cargo_registry_markdown::text_to_html;
use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";
const USER_AGENT: &str = "crates-admin";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let base_config = Arc::new(config::Base::from_environment());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let base_config = base_config.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(base_config.uploader(), &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(
                    header::CACHE_CONTROL,
                    header::HeaderValue::from_static(CACHE_CONTROL_README),
                );
                base_config
                    .uploader()
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    uploader: &Uploader,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let pkg_name = format!("{}-{}", krate_name, version.num);

    let location = uploader.crate_location(krate_name, &version.num.to_string());

    let location = match uploader {
        Uploader::S3 { .. } => location,
        Uploader::Local => format!("http://localhost:8888/{}", location),
    };

    let mut extra_headers = header::HeaderMap::new();
    extra_headers.insert(
        header::USER_AGENT,
        header::HeaderValue::from_static(USER_AGENT),
    );
    let response = match client.get(&location).headers(extra_headers).send() {
        Ok(r) => r,
        Err(err) => {
            println!("[{}] Unable to fetch crate: {}", pkg_name, err);
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}] Failed to get a 200 response: {}",
            pkg_name,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let mut archive = Archive::new(reader);
    let mut entries = archive
        .entries()
        .unwrap_or_else(|_| panic!("[{}] Invalid tar archive entries", pkg_name));

    let manifest: Manifest = {
        let path = format!("{}/Cargo.toml", pkg_name);
        let contents = find_file_by_path(&mut entries, Path::new(&path), &pkg_name);
        toml::from_str(&contents)
            .unwrap_or_else(|_| panic!("[{}] Syntax error in manifest file", pkg_name))
    };

    let rendered = {
        let readme_path = manifest.package.readme.as_ref()?;
        let path = format!("{}/{}", pkg_name, readme_path);
        let contents = find_file_by_path(&mut entries, Path::new(&path), &pkg_name);
        text_to_html(
            &contents,
            readme_path,
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Debug, Deserialize)]
    struct Package {
        readme: Option<String>,
        repository: Option<String>,
    }

    #[derive(Debug, Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    pkg_name: &str,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })
        .unwrap_or_else(|| panic!("[{}] couldn't open file: {}", pkg_name, path.display()))
        .unwrap_or_else(|_| panic!("[{}] file is not present: {}", pkg_name, path.display()));

    let mut contents = String::new();
    file.read_to_string(&mut contents)
        .unwrap_or_else(|_| panic!("[{}] Couldn't read file contents", pkg_name));
    contents
}
<commit_msg>admin::render_readmes: Extract `render_pkg_readme()` function<commit_after>use crate::{
    config, db,
    models::Version,
    schema::{crates, readme_renderings, versions},
    uploaders::Uploader,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use cargo_registry_markdown::text_to_html;
use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";
const USER_AGENT: &str = "crates-admin";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let base_config = Arc::new(config::Base::from_environment());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let base_config = base_config.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(base_config.uploader(), &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(
                    header::CACHE_CONTROL,
                    header::HeaderValue::from_static(CACHE_CONTROL_README),
                );
                base_config
                    .uploader()
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    uploader: &Uploader,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let pkg_name = format!("{}-{}", krate_name, version.num);

    let location = uploader.crate_location(krate_name, &version.num.to_string());

    let location = match uploader {
        Uploader::S3 { .. } => location,
        Uploader::Local => format!("http://localhost:8888/{}", location),
    };

    let mut extra_headers = header::HeaderMap::new();
    extra_headers.insert(
        header::USER_AGENT,
        header::HeaderValue::from_static(USER_AGENT),
    );
    let response = match client.get(&location).headers(extra_headers).send() {
        Ok(r) => r,
        Err(err) => {
            println!("[{}] Unable to fetch crate: {}", pkg_name, err);
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}] Failed to get a 200 response: {}",
            pkg_name,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let archive = Archive::new(reader);
    render_pkg_readme(archive, &pkg_name)
}

fn render_pkg_readme<R: Read>(mut archive: Archive<R>, pkg_name: &str) -> Option<String> {
    let mut entries = archive
        .entries()
        .unwrap_or_else(|_| panic!("[{}] Invalid tar archive entries", pkg_name));

    let manifest: Manifest = {
        let path = format!("{}/Cargo.toml", pkg_name);
        let contents = find_file_by_path(&mut entries, Path::new(&path), pkg_name);
        toml::from_str(&contents)
            .unwrap_or_else(|_| panic!("[{}] Syntax error in manifest file", pkg_name))
    };

    let rendered = {
        let readme_path = manifest.package.readme.as_ref()?;
        let path = format!("{}/{}", pkg_name, readme_path);
        let contents = find_file_by_path(&mut entries, Path::new(&path), pkg_name);
        text_to_html(
            &contents,
            readme_path,
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Debug, Deserialize)]
    struct Package {
        readme: Option<String>,
        repository: Option<String>,
    }

    #[derive(Debug, Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    pkg_name: &str,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })
        .unwrap_or_else(|| panic!("[{}] couldn't open file: {}", pkg_name, path.display()))
        .unwrap_or_else(|_| panic!("[{}] file is not present: {}", pkg_name, path.display()));

    let mut contents = String::new();
    file.read_to_string(&mut contents)
        .unwrap_or_else(|_| panic!("[{}] Couldn't read file contents", pkg_name));
    contents
}
<|endoftext|>