<commit_before>extern crate rand;

use std::ops::IndexMut;

type Flt = f64;
type Flt2 = (Flt, Flt);

pub struct RaytraceState<'a> {
    buffer: Vec<(Flt, Flt, Flt)>,
    size: (u32, u32),
    orig_buf: &'a [u8],
    blur_buf: &'a [u8],
}

impl<'a> RaytraceState<'a> {
    pub fn new(size: (u32, u32), orig_buf: &'a [u8], blur_buf: &'a [u8]) -> RaytraceState<'a> {
        RaytraceState {
            buffer: vec![(0.0, 0.0, 0.0); (size.0 * size.1) as usize],
            size: size,
            orig_buf: orig_buf,
            blur_buf: blur_buf,
        }
    }
}

struct RaytraceParams {
    origin: Flt2,
    iters_per_frame: u32,
}

const PARAMS: RaytraceParams = RaytraceParams {
    origin: (100.5, 100.5),
    iters_per_frame: 1000,
};

fn next_voxel(pos: Flt2, dir: Flt2) -> Flt2 {
    fn max_inf(x: Flt, y: Flt) -> Flt {
        if x.is_finite() && y.is_finite() {
            x.max(y)
        } else {
            (2.0 as Flt).sqrt()
        }
    }
    let pos_frac = (pos.0.fract(), pos.1.fract());
    let tx1 = (1.0 - pos_frac.0) / dir.0;
    let tx2 = -pos_frac.0 / dir.0;
    let ty1 = (1.0 - pos_frac.1) / dir.1;
    let ty2 = -pos_frac.1 / dir.1;
    let tx = max_inf(tx1, tx2);
    let ty = max_inf(ty1, ty2);
    let dist = tx.min(ty) + 0.01;
    (pos.0 + dir.0 * dist, pos.1 + dir.1 * dist)
}

fn validate_bounds(point: (i32, i32), size: (u32, u32)) -> Option<(u32, u32)> {
    if point.0 < 0 || point.0 >= size.0 as i32 || point.1 < 0 || point.1 >= size.1 as i32 {
        None
    } else {
        Some((point.0 as u32, point.1 as u32))
    }
}

fn normalize(val: Flt2) -> Flt2 {
    let len = (val.0 * val.0 * val.1 * val.1).sqrt();
    (val.0 / len, val.1 / len)
}

fn dot(left: Flt2, right: Flt2) -> Flt {
    left.0 * right.0 + left.1 * right.1
}

fn buf_to_pix(val: Flt) -> u8 {
    if val >= 1.0 {
        255
    } else if val < 0.0 {
        0
    } else {
        (val * 255.0) as u8
    }
}

impl<'a> RaytraceState<'a> {
    pub fn raytrace(&mut self, data: &mut [u8], frame: u32) {
        let fixed_frame = frame * PARAMS.iters_per_frame;
        let weight = PARAMS.iters_per_frame as Flt / fixed_frame as Flt;
        for _ in 0..PARAMS.iters_per_frame {
            self.raytrace_single(weight);
        }
        let mulby = 1.0 - weight;
        self.mul(mulby);
        self.blit(data);
    }

    fn raytrace_single(&mut self, weight: Flt) {
        let mut pos = PARAMS.origin;
        let mut dir = {
            let theta: Flt = rand::random::<Flt>() * 6.28318530718;
            (theta.cos(), theta.sin())
        };
        let mut old_value = 0.0;
        loop {
            let floor_pos = (pos.0.floor() as i32, pos.1.floor() as i32);
            if let Some(ipos) = validate_bounds(floor_pos, self.size) {
                self.refract(&mut dir, &mut old_value, ipos);
                let temp = 1.0;
                self.put_pixel(ipos, (temp, temp, temp), weight);
            } else {
                break;
            }
            pos = next_voxel(pos, dir);
        }
    }

    fn refract(&self, dir: &mut Flt2, old: &mut Flt, coords: (u32, u32)) {
        let new = self.orig_value_at(coords);
        if (new > 0.5) != (*old > 0.5) {
            let index_of_refraction = if new > 0.5 {
                2.0
            } else {
                1.0 / 2.0
            };
            let index_of_refraction2 = index_of_refraction * index_of_refraction;
            let normal = self.normal_at(coords);
            let cos_theta_i = -dot(*dir, normal);
            let sin2_theta_t = index_of_refraction2 *
                               (1.0 - cos_theta_i * cos_theta_i);
            let under_sqrt = 1.0 - sin2_theta_t;
            if under_sqrt < 0.0 {
                *old = new;
                return; // TODO
            }
            let refract_i = (dir.0 * index_of_refraction2, dir.1 * index_of_refraction2);
            let normal_mul = index_of_refraction * cos_theta_i + under_sqrt.sqrt();
            let refract_n = (normal.0 * normal_mul, normal.1 * normal_mul);
            *dir = (refract_i.0 + refract_n.0, refract_i.1 + refract_n.1);
        }
        *old = new;
    }

    fn blur_at(&self, coords: (u32, u32)) -> (u8, u8, u8) {
        let idx = (coords.1 * self.size.0 + coords.0) as usize;
        let red = self.blur_buf[idx * 4 + 0];
        let green = self.blur_buf[idx * 4 + 1];
        let blue = self.blur_buf[idx * 4 + 2];
        return (red, green, blue);
    }

    fn blur_value_at(&self, coords: (u32, u32)) -> Flt {
        let blur = self.blur_at(coords);
        return (blur.0 + blur.1 + blur.2) as Flt / (255.0 * 3.0);
    }

    fn orig_at(&self, coords: (u32, u32)) -> (u8, u8, u8) {
        let idx = (coords.1 * self.size.0 + coords.0) as usize;
        let red = self.orig_buf[idx * 4 + 0];
        let green = self.orig_buf[idx * 4 + 1];
        let blue = self.orig_buf[idx * 4 + 2];
        return (red, green, blue);
    }

    fn orig_value_at(&self, coords: (u32, u32)) -> Flt {
        let orig = self.orig_at(coords);
        return (orig.0 + orig.1 + orig.2) as Flt / (255.0 * 3.0);
    }

    fn normal_at(&self, coords: (u32, u32)) -> Flt2 {
        let c00 = self.blur_value_at((coords.0 - 1, coords.1 - 1));
        let c01 = self.blur_value_at((coords.0 - 1, coords.1 + 1));
        let c10 = self.blur_value_at((coords.0 + 1, coords.1 - 1));
        let c11 = self.blur_value_at((coords.0 + 1, coords.1 + 1));
        let x = (c10 - c00) + (c11 - c10);
        let y = (c01 - c00) + (c11 - c01);
        normalize((x, y))
    }

    fn put_pixel(&mut self, coords: (u32, u32), value: (Flt, Flt, Flt), weight: Flt) {
        let index = coords.1 * self.size.0 + coords.0;
        let arr = self.buffer.index_mut(index as usize);
        arr.0 = arr.0 * (1.0 - weight) + value.0 * weight;
        arr.1 = arr.1 * (1.0 - weight) + value.1 * weight;
        arr.2 = arr.2 * (1.0 - weight) + value.2 * weight;
    }

    fn mul(&mut self, value: Flt) {
        for v in self.buffer.iter_mut() {
            v.0 *= value;
            v.1 *= value;
            v.2 *= value;
        }
    }

    fn blit(&self, data: &mut [u8]) {
        for (i, v) in self.buffer.iter().enumerate() {
            data[i * 4 + 0] = buf_to_pix(v.0);
            data[i * 4 + 1] = buf_to_pix(v.1);
            data[i * 4 + 2] = buf_to_pix(v.2);
        }
    }
}
<commit_msg>Bugfix refraction<commit_after>extern crate rand;

use std::ops::IndexMut;

type Flt = f64;
type Flt2 = (Flt, Flt);

pub struct RaytraceState<'a> {
    buffer: Vec<(Flt, Flt, Flt)>,
    size: (u32, u32),
    orig_buf: &'a [u8],
    blur_buf: &'a [u8],
}

impl<'a> RaytraceState<'a> {
    pub fn new(size: (u32, u32), orig_buf: &'a [u8], blur_buf: &'a [u8]) -> RaytraceState<'a> {
        RaytraceState {
            buffer: vec![(0.0, 0.0, 0.0); (size.0 * size.1) as usize],
            size: size,
            orig_buf: orig_buf,
            blur_buf: blur_buf,
        }
    }
}

struct RaytraceParams {
    origin: Flt2,
    iters_per_frame: u32,
}

const PARAMS: RaytraceParams = RaytraceParams {
    origin: (10.5, 10.5),
    iters_per_frame: 1000,
};

fn next_voxel(pos: Flt2, dir: Flt2) -> Flt2 {
    fn max_inf(x: Flt, y: Flt) -> Flt {
        if x.is_finite() && y.is_finite() {
            x.max(y)
        } else {
            (2.0 as Flt).sqrt()
        }
    }
    let pos_frac = (pos.0.fract(), pos.1.fract());
    let tx1 = (1.0 - pos_frac.0) / dir.0;
    let tx2 = -pos_frac.0 / dir.0;
    let ty1 = (1.0 - pos_frac.1) / dir.1;
    let ty2 = -pos_frac.1 / dir.1;
    let tx = max_inf(tx1, tx2);
    let ty = max_inf(ty1, ty2);
    let dist = tx.min(ty) + 0.01;
    (pos.0 + dir.0 * dist, pos.1 + dir.1 * dist)
}

fn validate_bounds(point: (i32, i32), size: (u32, u32)) -> Option<(u32, u32)> {
    if point.0 < 0 || point.0 >= size.0 as i32 || point.1 < 0 || point.1 >= size.1 as i32 {
        None
    } else {
        Some((point.0 as u32, point.1 as u32))
    }
}

fn normalize(val: Flt2) -> Flt2 {
    let len = (val.0 * val.0 * val.1 * val.1).sqrt();
    (val.0 / len, val.1 / len)
}

fn dot(left: Flt2, right: Flt2) -> Flt {
    left.0 * right.0 + left.1 * right.1
}

fn buf_to_pix(val: Flt) -> u8 {
    if val >= 1.0 {
        255
    } else if val < 0.0 {
        0
    } else {
        (val * 255.0) as u8
    }
}

impl<'a> RaytraceState<'a> {
    pub fn raytrace(&mut self, data: &mut [u8], frame: u32) {
        let fixed_frame = frame * PARAMS.iters_per_frame;
        let weight = PARAMS.iters_per_frame as Flt / fixed_frame as Flt;
        for _ in 0..PARAMS.iters_per_frame {
            self.raytrace_single(weight);
        }
        let mulby = 1.0 - weight;
        self.mul(mulby);
        self.blit(data);
    }

    fn raytrace_single(&mut self, weight: Flt) {
        let mut pos = PARAMS.origin;
        let mut dir = {
            let theta: Flt = rand::random::<Flt>() * 6.28318530718;
            (theta.cos(), theta.sin())
        };
        let mut old_value = -1.0;
        for _ in 0..1000 {
            let floor_pos = (pos.0.floor() as i32, pos.1.floor() as i32);
            if let Some(ipos) = validate_bounds(floor_pos, self.size) {
                self.refract(&mut dir, &mut old_value, ipos);
                let temp = 1.0;
                self.put_pixel(ipos, (temp, temp, temp), weight);
            } else {
                break;
            }
            pos = next_voxel(pos, dir);
        }
    }

    fn refract(&self, dir: &mut Flt2, old: &mut Flt, coords: (u32, u32)) {
        let new = self.orig_value_at(coords);
        // old >= 0 to not do first iteration
        if *old >= 0.0 && (new > 0.5) != (*old > 0.5) {
            let index_of_refraction = if new > 0.5 {
                2.0
            } else {
                1.0 / 2.0
            };
            let index_of_refraction2 = index_of_refraction * index_of_refraction;
            let normal = self.normal_at(coords);
            let cos_theta_i = -dot(*dir, normal);
            let sin2_theta_t = index_of_refraction2 * (1.0 - cos_theta_i * cos_theta_i);
            let under_sqrt = 1.0 - sin2_theta_t;
            if under_sqrt < 0.0 {
                *old = new;
                *dir = (dir.0 + 2.0 * cos_theta_i * normal.0, dir.0 + 2.0 * cos_theta_i * normal.1);
                // println!("Refraction fail");
                return; // TODO
            } else {
                let refract_i = (dir.0 * index_of_refraction2, dir.1 * index_of_refraction2);
                let normal_mul = index_of_refraction * cos_theta_i + under_sqrt.sqrt();
                let refract_n = (normal.0 * normal_mul, normal.1 * normal_mul);
                *dir = normalize((refract_i.0 + refract_n.0, refract_i.1 + refract_n.1));
            }
        }
        *old = new;
    }

    fn blur_at(&self, coords: (u32, u32)) -> (u8, u8, u8) {
        let idx = (coords.1 * self.size.0 + coords.0) as usize;
        let red = self.blur_buf[idx * 4 + 0];
        let green = self.blur_buf[idx * 4 + 1];
        let blue = self.blur_buf[idx * 4 + 2];
        return (red, green, blue);
    }

    fn blur_value_at(&self, coords: (u32, u32)) -> Flt {
        let blur = self.blur_at(coords);
        return (blur.0 as Flt + blur.1 as Flt + blur.2 as Flt) / (255.0 * 3.0);
    }

    fn orig_at(&self, coords: (u32, u32)) -> (u8, u8, u8) {
        let idx = (coords.1 * self.size.0 + coords.0) as usize;
        let red = self.orig_buf[idx * 4 + 0];
        let green = self.orig_buf[idx * 4 + 1];
        let blue = self.orig_buf[idx * 4 + 2];
        return (red, green, blue);
    }

    fn orig_value_at(&self, coords: (u32, u32)) -> Flt {
        let orig = self.orig_at(coords);
        return (orig.0 as Flt + orig.1 as Flt + orig.2 as Flt) / (255.0 * 3.0);
    }

    fn normal_at(&self, coords: (u32, u32)) -> Flt2 {
        let c00 = self.blur_value_at((coords.0 - 1, coords.1 - 1));
        let c01 = self.blur_value_at((coords.0 - 1, coords.1 + 1));
        let c10 = self.blur_value_at((coords.0 + 1, coords.1 - 1));
        let c11 = self.blur_value_at((coords.0 + 1, coords.1 + 1));
        let x = (c10 - c00) + (c11 - c10);
        let y = (c01 - c00) + (c11 - c01);
        normalize((x, y))
    }

    fn put_pixel(&mut self, coords: (u32, u32), value: (Flt, Flt, Flt), weight: Flt) {
        let index = coords.1 * self.size.0 + coords.0;
        let arr = self.buffer.index_mut(index as usize);
        arr.0 = arr.0 * (1.0 - weight) + value.0 * weight;
        arr.1 = arr.1 * (1.0 - weight) + value.1 * weight;
        arr.2 = arr.2 * (1.0 - weight) + value.2 * weight;
    }

    fn mul(&mut self, value: Flt) {
        for v in self.buffer.iter_mut() {
            v.0 *= value;
            v.1 *= value;
            v.2 *= value;
        }
    }

    fn blit(&self, data: &mut [u8]) {
        for (i, v) in self.buffer.iter().enumerate() {
            data[i * 4 + 0] = buf_to_pix(v.0);
            data[i * 4 + 1] = buf_to_pix(v.1);
            data[i * 4 + 2] = buf_to_pix(v.2);
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{self, TryRecvError};

use piston_window::{
    PistonWindow,
    G2d,
    context,
    clear,
    line,
    polygon,
};

use turtle_window::ReadOnly;
use extensions::ToCanvasCoordinates;
use {Point, Color};
use state::{Path, Pen,TurtleState};

pub struct Renderer {
    paths: Vec<Path>,
}

impl Renderer {
    pub fn new() -> Renderer {
        Self {
            paths: Vec::new(),
        }
    }

    pub fn run(&mut self, window: &mut PistonWindow, paths_rx: mpsc::Receiver<Path>, state: ReadOnly) {
        'renderloop:
        while let Some(e) = window.next() {
            loop {
                match paths_rx.try_recv() {
                    Ok(path) => if path.pen.enabled {
                        self.paths.push(path);
                    },
                    Err(TryRecvError::Empty) => break, // Do nothing
                    Err(TryRecvError::Disconnected) => break 'renderloop, // Quit
                }
            }

            window.draw_2d(&e, |c, g| {
                let background = state.drawing().background;
                clear(background.into(), g);

                let view = c.get_view_size();
                let width = view[0] as f64;
                let height = view[1] as f64;
                let center = [width * 0.5, height * 0.5];

                for path in &self.paths {
                    self.render_path(c, g, center, path);
                }

                if let Some(ref path) = *state.temporary_path() {
                    self.render_path(c, g, center, path);
                }

                self.render_shell(c, g, center, &state);
            });
        }
    }

    /// Render a path assuming that its pen is enabled
    fn render_path(&self, c: context::Context, g: &mut G2d, center: Point, path: &Path) {
        let &Path {start, end, ref pen} = path;
        let &Pen {thickness, color, enabled} = pen;
        debug_assert!(enabled, "bug: attempt to render path when pen was not enabled");

        let start = start.to_canvas_coords(center);
        let end = end.to_canvas_coords(center);

        line(color.into(), thickness,
            [start[0], start[1], end[0], end[1]],
            c.transform, g);
    }

    /// Draw the turtle's shell
    fn render_shell(&self, c: context::Context, g: &mut G2d, center: Point, state: &ReadOnly) {
        // Calculate all the points on the shell by rotating the shell shape by the turtle's
        // heading and moving it to the turtle's position
        let TurtleState {position, heading, ..} = *state.turtle();
        let cos = heading.cos();
        let sin = heading.sin();
        let turtle_x = position[0];
        let turtle_y = position[1];
        let shell: Vec<_> = [
            [0., 15.],
            [10., 0.],
            [0., -15.],
        ].into_iter().map(|pt| {
            // Rotate each point by the heading and add the current turtle position
            let x = cos * pt[0] - sin * pt[1] + turtle_x;
            let y = sin * pt[0] + cos * pt[1] + turtle_y;
            [x, y].to_canvas_coords(center)
        }).collect();

        // Draw the turtle shell with its background first, then its border
        polygon(Color::White.into(), &shell, c.transform, g);
        for i in 0..shell.len() {
            let start = shell[i];
            let end = shell[(i + 1) % shell.len()];

            line(Color::Black.into(), 1.,
            [start[0], start[1], end[0], end[1]],
            c.transform, g);
        }
    }
}
<commit_msg>Quit immediately when the window is closed<commit_after>use std::process;
use std::sync::mpsc::{self, TryRecvError};

use piston_window::{
    PistonWindow,
    G2d,
    context,
    clear,
    line,
    polygon,
};

use turtle_window::ReadOnly;
use extensions::ToCanvasCoordinates;
use {Point, Color};
use state::{Path, Pen,TurtleState};

pub struct Renderer {
    paths: Vec<Path>,
}

impl Renderer {
    pub fn new() -> Renderer {
        Self {
            paths: Vec::new(),
        }
    }

    pub fn run(&mut self, window: &mut PistonWindow, paths_rx: mpsc::Receiver<Path>, state: ReadOnly) {
        'renderloop:
        while let Some(e) = window.next() {
            loop {
                match paths_rx.try_recv() {
                    Ok(path) => if path.pen.enabled {
                        self.paths.push(path);
                    },
                    Err(TryRecvError::Empty) => break, // Do nothing
                    Err(TryRecvError::Disconnected) => break 'renderloop, // Quit
                }
            }

            window.draw_2d(&e, |c, g| {
                let background = state.drawing().background;
                clear(background.into(), g);

                let view = c.get_view_size();
                let width = view[0] as f64;
                let height = view[1] as f64;
                let center = [width * 0.5, height * 0.5];

                for path in &self.paths {
                    self.render_path(c, g, center, path);
                }

                if let Some(ref path) = *state.temporary_path() {
                    self.render_path(c, g, center, path);
                }

                self.render_shell(c, g, center, &state);
            });
        }

        // Quit immediately when the window is closed
        process::exit(0);
    }

    /// Render a path assuming that its pen is enabled
    fn render_path(&self, c: context::Context, g: &mut G2d, center: Point, path: &Path) {
        let &Path {start, end, ref pen} = path;
        let &Pen {thickness, color, enabled} = pen;
        debug_assert!(enabled, "bug: attempt to render path when pen was not enabled");

        let start = start.to_canvas_coords(center);
        let end = end.to_canvas_coords(center);

        line(color.into(), thickness,
            [start[0], start[1], end[0], end[1]],
            c.transform, g);
    }

    /// Draw the turtle's shell
    fn render_shell(&self, c: context::Context, g: &mut G2d, center: Point, state: &ReadOnly) {
        // Calculate all the points on the shell by rotating the shell shape by the turtle's
        // heading and moving it to the turtle's position
        let TurtleState {position, heading, ..} = *state.turtle();
        let cos = heading.cos();
        let sin = heading.sin();
        let turtle_x = position[0];
        let turtle_y = position[1];
        let shell: Vec<_> = [
            [0., 15.],
            [10., 0.],
            [0., -15.],
        ].into_iter().map(|pt| {
            // Rotate each point by the heading and add the current turtle position
            let x = cos * pt[0] - sin * pt[1] + turtle_x;
            let y = sin * pt[0] + cos * pt[1] + turtle_y;
            [x, y].to_canvas_coords(center)
        }).collect();

        // Draw the turtle shell with its background first, then its border
        polygon(Color::White.into(), &shell, c.transform, g);
        for i in 0..shell.len() {
            let start = shell[i];
            let end = shell[(i + 1) % shell.len()];

            line(Color::Black.into(), 1.,
            [start[0], start[1], end[0], end[1]],
            c.transform, g);
        }
    }
}
<|endoftext|>


<commit_before>//! An augmentation of the rust-http Response struct.

use std::io::{IoResult, File, MemReader};
use std::io::util::copy;
use std::path::BytesContainer;

use http::status::{Status, InternalServerError};
use http::headers::response::HeaderCollection;

pub use HttpResponse = http::server::response::ResponseWriter;

use contenttype::get_content_type;

/// The response representation given to `Middleware`
pub struct Response<'a, 'b> {
    http_res: &'a mut HttpResponse<'b>,
    pub body: Box<Reader>,
    pub headers: Box<HeaderCollection>,
    pub status: Status
}

impl<'a, 'b> Response<'a, 'b> {
    pub fn from_http(http_res: &'a mut HttpResponse<'b>) -> Response<'a, 'b> {
        Response {
            headers: http_res.headers.clone(),
            status: http_res.status.clone(),
            http_res: http_res,
            body: box MemReader::new(vec![]) as Box<Reader>
        }
    }

    pub fn serve<S: BytesContainer>(&mut self, status: Status, body: S) {
        self.status = status;
        self.body = box MemReader::new(body.container_as_bytes().to_owned()) as Box<Reader>;
    }

    /// Serve the file located at `path`.
    ///
    /// This is usually a terminal process, and `Middleware` may want to
    /// call `Unwind` after a file is served. If the status should be
    /// anything other than `200`, the `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will err out if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    pub fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let file = try!(File::open(path));
        self.headers.content_type = path.extension_str().and_then(get_content_type);
        self.body = box file as Box<Reader>;
        Ok(())
    }

    fn serve<S: BytesContainer>(&mut self, status: Status, body: S) -> IoResult<()> {
        self.status = status;
        Ok(try!(self.write(body.container_as_bytes())))
    }

    pub fn write_back(mut self) {
        self.http_res.headers = self.headers.clone();
        self.http_res.status = self.status.clone();
        let _ = match self.body.read_to_string() {
            Ok(body) => {
                self.http_res.write_content_auto(
                    match self.headers.content_type {
                        Some(ref ctype) => ctype.clone(),
                        None => get_content_type("txt").unwrap()
                    }, body)
            },
            Err(e) => Err(e)
        }.map_err(|e| {
            error!("Error reading/writing body: {}", e);
            self.http_res.status = InternalServerError;
            let _ = self.http_res.write(b"Internal Server Error")
                .map_err(|e| error!("Error writing error message: {}", e));
        });
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_content_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<commit_msg>(doc) Documented Response wrapper.<commit_after>//! An augmentation of the rust-http Response struct.

use std::io::{IoResult, File, MemReader};
use std::io::util::copy;
use std::path::BytesContainer;

use http::status::{Status, InternalServerError};
use http::headers::response::HeaderCollection;

pub use HttpResponse = http::server::response::ResponseWriter;

use contenttype::get_content_type;

/// The response representation given to `Middleware`
pub struct Response<'a, 'b> {
    http_res: &'a mut HttpResponse<'b>,
    pub body: Box<Reader>,
    pub headers: Box<HeaderCollection>,
    pub status: Status
}

impl<'a, 'b> Response<'a, 'b> {
    /// Construct a Response from an HttpResponse reference
    pub fn from_http(http_res: &'a mut HttpResponse<'b>) -> Response<'a, 'b> {
        Response {
            headers: http_res.headers.clone(),
            status: http_res.status.clone(),
            http_res: http_res,
            body: box MemReader::new(vec![]) as Box<Reader>
        }
    }

    /// Write the `Status` and data to the `Response`.
    pub fn serve<S: BytesContainer>(&mut self, status: Status, body: S) {
        self.status = status;
        self.body = box MemReader::new(body.container_as_bytes().to_owned()) as Box<Reader>;
    }

    /// Serve the file located at `path`.
    ///
    /// This usually means a request has been handlded, and `Middleware`
    /// may want to `Unwind` after a file is served. If the status should be
    /// anything other than `200`, `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will error if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    /// from the file. `Middleware` should handle this gracefully.
    pub fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let file = try!(File::open(path));
        self.headers.content_type = path.extension_str().and_then(get_content_type);
        self.body = box file as Box<Reader>;
        Ok(())
    }

    /// Internal. Should not be called by the user.
    ///
    /// `write_back` is used to put all the data added to `self`
    /// back onto an `HttpResponse` so that it is sent back to the
    /// client.
    ///
    /// `write_back` consumes the `Response`.
    pub fn write_back(mut self) {
        self.http_res.headers = self.headers.clone();
        self.http_res.status = self.status.clone();
        let _ = match self.body.read_to_string() {
            Ok(body) => {
                self.http_res.write_content_auto(
                    match self.headers.content_type {
                        Some(ref ctype) => ctype.clone(),
                        None => get_content_type("txt").unwrap()
                    }, body)
            },
            Err(e) => Err(e)
        }.map_err(|e| {
            error!("Error reading/writing body: {}", e);
            self.http_res.status = InternalServerError;
            let _ = self.http_res.write(b"Internal Server Error")
                .map_err(|e| error!("Error writing error message: {}", e));
        });
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_content_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<|endoftext|>


<commit_before>//! Iron's HTTP Response representation and associated methods.

use std::io::{self, Write};
use std::fmt::{self, Debug};
use std::fs::File;

use typemap::TypeMap;
use plugin::Extensible;
use modifier::{Set, Modifier};
use hyper::header::Headers;

use status::{self, Status};
use {Plugin, headers};

pub use hyper::server::response::Response as HttpResponse;
use hyper::net::Fresh;

/// A `Write`r of HTTP response bodies.
pub struct ResponseBody<'a>(Box<Write + 'a>);

impl<'a> ResponseBody<'a> {
    /// Create a new ResponseBody, mostly for use in mocking.
    pub fn new<W: Write + 'a>(writer: W) -> ResponseBody<'a> {
        ResponseBody(Box::new(writer))
    }
}

impl<'a> Write for ResponseBody<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// A trait which writes the body of an HTTP response.
pub trait WriteBody {
    /// Writes the body to the provided `ResponseBody`.
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()>;
}

impl WriteBody for String {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        self.as_bytes().write_body(res)
    }
}

impl<'a> WriteBody for &'a str {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        self.as_bytes().write_body(res)
    }
}

impl WriteBody for Vec<u8> {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        res.write_all(self)
    }
}

impl<'a> WriteBody for &'a [u8] {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        res.write_all(self)
    }
}

impl WriteBody for File {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res).map(|_| ())
    }
}

impl WriteBody for Box<io::Read> {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res).map(|_| ())
    }
}

/* Needs specialization :(
impl<R: Read> WriteBody for R {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res)
    }
}
*/

/// The response representation given to `Middleware`
pub struct Response {
    /// The response status-code.
    pub status: Option<Status>,

    /// The headers of the response.
    pub headers: Headers,

    /// A TypeMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: TypeMap,

    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Option<Box<WriteBody + Send>>
}

impl Response {
    /// Construct a blank Response
    pub fn new() -> Response {
        Response {
            status: None, // Start with no response code.
            body: None, // Start with no body.
            headers: Headers::new(),
            extensions: TypeMap::new()
        }
    }

    /// Construct a Response with the specified modifier pre-applied.
    pub fn with<M: Modifier<Response>>(m: M) -> Response {
        Response::new().set(m)
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(self, mut http_res: HttpResponse<Fresh>) {
        *http_res.headers_mut() = self.headers;

        // Default to a 404 if no response code was set
        *http_res.status_mut() = self.status.clone().unwrap_or(status::NotFound);

        let out = match self.body {
            Some(body) => write_with_body(http_res, body),
            None => {
                http_res.headers_mut().set(headers::ContentLength(0));
                http_res.start().and_then(|res| res.end())
            }
        };

        match out {
            Err(e) => {
                error!("Error writing response: {}", e);
            },
            _ => {}
        }
    }
}

fn write_with_body(mut res: HttpResponse<Fresh>, mut body: Box<WriteBody + Send>)
                   -> io::Result<()> {
    let content_type = res.headers().get::<headers::ContentType>()
                           .map(|cx| cx.clone())
                           .unwrap_or_else(|| headers::ContentType("text/plain".parse().unwrap()));
    res.headers_mut().set(content_type);

    let mut raw_res = try!(res.start());
    try!(body.write_body(&mut ResponseBody::new(&mut raw_res)));
    raw_res.end()
}

impl Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "HTTP/1.1 {} {}\n{}",
            self.status.unwrap_or(status::NotFound),
            self.status.unwrap_or(status::NotFound).canonical_reason().unwrap(),
            self.headers
        )
    }
}

impl fmt::Display for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

// Allow plugins to attach to responses.
impl Extensible for Response {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl Plugin for Response {}
impl Set for Response {}

<commit_msg>Remove outdated response body documentation<commit_after>//! Iron's HTTP Response representation and associated methods.

use std::io::{self, Write};
use std::fmt::{self, Debug};
use std::fs::File;

use typemap::TypeMap;
use plugin::Extensible;
use modifier::{Set, Modifier};
use hyper::header::Headers;

use status::{self, Status};
use {Plugin, headers};

pub use hyper::server::response::Response as HttpResponse;
use hyper::net::Fresh;

/// A `Write`r of HTTP response bodies.
pub struct ResponseBody<'a>(Box<Write + 'a>);

impl<'a> ResponseBody<'a> {
    /// Create a new ResponseBody, mostly for use in mocking.
    pub fn new<W: Write + 'a>(writer: W) -> ResponseBody<'a> {
        ResponseBody(Box::new(writer))
    }
}

impl<'a> Write for ResponseBody<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// A trait which writes the body of an HTTP response.
pub trait WriteBody {
    /// Writes the body to the provided `ResponseBody`.
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()>;
}

impl WriteBody for String {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        self.as_bytes().write_body(res)
    }
}

impl<'a> WriteBody for &'a str {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        self.as_bytes().write_body(res)
    }
}

impl WriteBody for Vec<u8> {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        res.write_all(self)
    }
}

impl<'a> WriteBody for &'a [u8] {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        res.write_all(self)
    }
}

impl WriteBody for File {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res).map(|_| ())
    }
}

impl WriteBody for Box<io::Read> {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res).map(|_| ())
    }
}

/* Needs specialization :(
impl<R: Read> WriteBody for R {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res)
    }
}
*/

/// The response representation given to `Middleware`
pub struct Response {
    /// The response status-code.
    pub status: Option<Status>,

    /// The headers of the response.
    pub headers: Headers,

    /// A TypeMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: TypeMap,

    /// The body of the response.
    pub body: Option<Box<WriteBody + Send>>
}

impl Response {
    /// Construct a blank Response
    pub fn new() -> Response {
        Response {
            status: None, // Start with no response code.
            body: None, // Start with no body.
            headers: Headers::new(),
            extensions: TypeMap::new()
        }
    }

    /// Construct a Response with the specified modifier pre-applied.
    pub fn with<M: Modifier<Response>>(m: M) -> Response {
        Response::new().set(m)
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(self, mut http_res: HttpResponse<Fresh>) {
        *http_res.headers_mut() = self.headers;

        // Default to a 404 if no response code was set
        *http_res.status_mut() = self.status.clone().unwrap_or(status::NotFound);

        let out = match self.body {
            Some(body) => write_with_body(http_res, body),
            None => {
                http_res.headers_mut().set(headers::ContentLength(0));
                http_res.start().and_then(|res| res.end())
            }
        };

        match out {
            Err(e) => {
                error!("Error writing response: {}", e);
            },
            _ => {}
        }
    }
}

fn write_with_body(mut res: HttpResponse<Fresh>, mut body: Box<WriteBody + Send>)
                   -> io::Result<()> {
    let content_type = res.headers().get::<headers::ContentType>()
                           .map(|cx| cx.clone())
                           .unwrap_or_else(|| headers::ContentType("text/plain".parse().unwrap()));
    res.headers_mut().set(content_type);

    let mut raw_res = try!(res.start());
    try!(body.write_body(&mut ResponseBody::new(&mut raw_res)));
    raw_res.end()
}

impl Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "HTTP/1.1 {} {}\n{}",
            self.status.unwrap_or(status::NotFound),
            self.status.unwrap_or(status::NotFound).canonical_reason().unwrap(),
            self.headers
        )
    }
}

impl fmt::Display for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

// Allow plugins to attach to responses.
impl Extensible for Response {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl Plugin for Response {}
impl Set for Response {}

<|endoftext|>


<commit_before>//! Variable parameters module.
use std::f64;
use std::ops::{Add, Div, Mul, Sub};

#[derive(Clone, Copy)]
pub enum Parameter {
    Fixed(f64),
    Exponential {
        init: f64,
        floor: f64,
        tau: f64,
        count: u32,
    },
    Polynomial {
        init: f64,
        floor: f64,
        tau: f64,
        count: u32,
    },
    Boyan {
        init: f64,
        floor: f64,
        n0: u32,
        count: u32,
    },
    // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.384.9576&rep=rep1&type=pdf
    GHC {
        init: f64,
        floor: f64,
        tau: f64,
        count: u32,
    },
}

impl Parameter {
    pub fn fixed(value: f64) -> Parameter { Parameter::Fixed(value) }

    pub fn exponential(init: f64, floor: f64, tau: f64) -> Parameter {
        Parameter::Exponential {
            init,
            floor,
            tau,
            count: 0,
        }
    }

    pub fn polynomial(init: f64, floor: f64, tau: f64) -> Parameter {
        Parameter::Polynomial {
            init,
            floor,
            tau,
            count: 0,
        }
    }

    pub fn boyan(init: f64, floor: f64, n0: u32) -> Parameter {
        Parameter::Boyan {
            init,
            floor,
            n0,
            count: 0,
        }
    }

    pub fn ghc(init: f64, floor: f64, tau: f64) -> Parameter {
        Parameter::GHC {
            init,
            floor,
            tau,
            count: 0,
        }
    }

    pub fn value(&self) -> f64 {
        match *self {
            Parameter::Fixed(v) => v,

            Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => f64::max(i * t.powf(f64::from(c)), f),

            Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => f64::max(i / (f64::from(c) + 1.0).powf(t), f),

            Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c,
            } => f64::max(i * (f64::from(n + 1)) / (f64::from(n + c)), f),

            Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => f64::max(i * t / (t + f64::from(c) - 1.0), f),
        }
    }

    pub fn to_fixed(self) -> Parameter { Parameter::Fixed(self.value()) }

    pub fn step(self) -> Parameter {
        match self {
            Parameter::Fixed(_) => self,
            Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_add(1),
            },
            Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_add(1),
            },
            Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c,
            } => Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c.saturating_add(1),
            },
            Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_add(1),
            },
        }
    }

    pub fn back(self) -> Parameter {
        match self {
            Parameter::Fixed(_) => self,
            Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_sub(1),
            },
            Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_sub(1),
            },
            Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c,
            } => Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c.saturating_sub(1),
            },
            Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_sub(1),
            },
        }
    }
}

impl Into<Parameter> for f64 {
    fn into(self) -> Parameter { Parameter::Fixed(self) }
}

macro_rules! impl_op {
    ($name: ident, $num_type: ty, $fn_name: ident, $op: tt) => {
        impl $name<$num_type> for Parameter {
            type Output = $num_type;

            fn $fn_name(self, other: $num_type) -> $num_type {
                self.value() $op other
            }
        }

        impl $name<Parameter> for $num_type {
            type Output = $num_type;

            fn $fn_name(self, other: Parameter) -> $num_type {
                self $op other.value()
            }
        }

        impl $name<Parameter> for Parameter {
            type Output = $num_type;

            fn $fn_name(self, other: Parameter) -> $num_type {
                self.value() $op other.value()
            }
        }
    }
}

impl_op!(Add, f64, add, +);
impl_op!(Sub, f64, sub, -);
impl_op!(Mul, f64, mul, *);
impl_op!(Div, f64, div, /);

#[cfg(test)]
mod tests {
    use super::Parameter;

    #[test]
    fn test_fixed() {
        let mut p = Parameter::fixed(1.0);

        assert_eq!(p.value(), 1.0);

        for _ in 0..1000 {
            p = p.step();
            assert_eq!(p.value(), 1.0);
        }

        for _ in 0..1000 {
            p = p.back();
            assert_eq!(p.value(), 1.0);
        }
    }

    #[test]
    fn test_exponential() {
        let mut p = Parameter::exponential(1.0, 0.5, 0.9);

        assert!((p.value() - 1.0).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.9).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.81).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.729).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 0.81).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 0.9).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 1.0).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 1.0).abs() < 1e-7);

        for _ in 0..1000 {
            p = p.step();
            assert!(p.value() >= 0.5);
        }

        assert!((p.value() - 0.5).abs() < 1e-7);
    }

    #[test]
    fn test_polynomial() {
        let mut p = Parameter::polynomial(1.0, 0.1, 0.6);

        assert!((p.value() - 1.0).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.659753955386447).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.517281857971786).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.435275281648062).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 0.517281857971786).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 0.659753955386447).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 1.0).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 1.0).abs() < 1e-7);

        for _ in 0..1000 {
            p = p.step();
            assert!(p.value() >= 0.1);
        }

        assert!((p.value() - 0.1).abs() < 1e-7);
    }

    #[test]
    fn test_to_fixed() {
        let mut p = Parameter::exponential(1.0, 0.5, 0.9);
        p = p.step().to_fixed();

        assert!((p.value() - 0.9).abs() < 1e-7);

        p = p.step().step().step().back().back();
        assert!((p.value() - 0.9).abs() < 1e-7);
    }
}
<commit_msg>feat(core): derive serde traits for core::Parameter<commit_after>//! Variable parameters module.
use std::f64;
use std::ops::{Add, Div, Mul, Sub};

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum Parameter {
    Fixed(f64),
    Exponential {
        init: f64,
        floor: f64,
        tau: f64,
        count: u32,
    },
    Polynomial {
        init: f64,
        floor: f64,
        tau: f64,
        count: u32,
    },
    Boyan {
        init: f64,
        floor: f64,
        n0: u32,
        count: u32,
    },
    // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.384.9576&rep=rep1&type=pdf
    GHC {
        init: f64,
        floor: f64,
        tau: f64,
        count: u32,
    },
}

impl Parameter {
    pub fn fixed(value: f64) -> Parameter { Parameter::Fixed(value) }

    pub fn exponential(init: f64, floor: f64, tau: f64) -> Parameter {
        Parameter::Exponential {
            init,
            floor,
            tau,
            count: 0,
        }
    }

    pub fn polynomial(init: f64, floor: f64, tau: f64) -> Parameter {
        Parameter::Polynomial {
            init,
            floor,
            tau,
            count: 0,
        }
    }

    pub fn boyan(init: f64, floor: f64, n0: u32) -> Parameter {
        Parameter::Boyan {
            init,
            floor,
            n0,
            count: 0,
        }
    }

    pub fn ghc(init: f64, floor: f64, tau: f64) -> Parameter {
        Parameter::GHC {
            init,
            floor,
            tau,
            count: 0,
        }
    }

    pub fn value(&self) -> f64 {
        match *self {
            Parameter::Fixed(v) => v,

            Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => f64::max(i * t.powf(f64::from(c)), f),

            Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => f64::max(i / (f64::from(c) + 1.0).powf(t), f),

            Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c,
            } => f64::max(i * (f64::from(n + 1)) / (f64::from(n + c)), f),

            Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => f64::max(i * t / (t + f64::from(c) - 1.0), f),
        }
    }

    pub fn to_fixed(self) -> Parameter { Parameter::Fixed(self.value()) }

    pub fn step(self) -> Parameter {
        match self {
            Parameter::Fixed(_) => self,
            Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_add(1),
            },
            Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_add(1),
            },
            Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c,
            } => Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c.saturating_add(1),
            },
            Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_add(1),
            },
        }
    }

    pub fn back(self) -> Parameter {
        match self {
            Parameter::Fixed(_) => self,
            Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::Exponential {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_sub(1),
            },
            Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::Polynomial {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_sub(1),
            },
            Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c,
            } => Parameter::Boyan {
                init: i,
                floor: f,
                n0: n,
                count: c.saturating_sub(1),
            },
            Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c,
            } => Parameter::GHC {
                init: i,
                floor: f,
                tau: t,
                count: c.saturating_sub(1),
            },
        }
    }
}

impl Into<Parameter> for f64 {
    fn into(self) -> Parameter { Parameter::Fixed(self) }
}

macro_rules! impl_op {
    ($name: ident, $num_type: ty, $fn_name: ident, $op: tt) => {
        impl $name<$num_type> for Parameter {
            type Output = $num_type;

            fn $fn_name(self, other: $num_type) -> $num_type {
                self.value() $op other
            }
        }

        impl $name<Parameter> for $num_type {
            type Output = $num_type;

            fn $fn_name(self, other: Parameter) -> $num_type {
                self $op other.value()
            }
        }

        impl $name<Parameter> for Parameter {
            type Output = $num_type;

            fn $fn_name(self, other: Parameter) -> $num_type {
                self.value() $op other.value()
            }
        }
    }
}

impl_op!(Add, f64, add, +);
impl_op!(Sub, f64, sub, -);
impl_op!(Mul, f64, mul, *);
impl_op!(Div, f64, div, /);

#[cfg(test)]
mod tests {
    use super::Parameter;

    #[test]
    fn test_fixed() {
        let mut p = Parameter::fixed(1.0);

        assert_eq!(p.value(), 1.0);

        for _ in 0..1000 {
            p = p.step();
            assert_eq!(p.value(), 1.0);
        }

        for _ in 0..1000 {
            p = p.back();
            assert_eq!(p.value(), 1.0);
        }
    }

    #[test]
    fn test_exponential() {
        let mut p = Parameter::exponential(1.0, 0.5, 0.9);

        assert!((p.value() - 1.0).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.9).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.81).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.729).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 0.81).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 0.9).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 1.0).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 1.0).abs() < 1e-7);

        for _ in 0..1000 {
            p = p.step();
            assert!(p.value() >= 0.5);
        }

        assert!((p.value() - 0.5).abs() < 1e-7);
    }

    #[test]
    fn test_polynomial() {
        let mut p = Parameter::polynomial(1.0, 0.1, 0.6);

        assert!((p.value() - 1.0).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.659753955386447).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.517281857971786).abs() < 1e-7);

        p = p.step();
        assert!((p.value() - 0.435275281648062).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 0.517281857971786).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 0.659753955386447).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 1.0).abs() < 1e-7);

        p = p.back();
        assert!((p.value() - 1.0).abs() < 1e-7);

        for _ in 0..1000 {
            p = p.step();
            assert!(p.value() >= 0.1);
        }

        assert!((p.value() - 0.1).abs() < 1e-7);
    }

    #[test]
    fn test_to_fixed() {
        let mut p = Parameter::exponential(1.0, 0.5, 0.9);
        p = p.step().to_fixed();

        assert!((p.value() - 0.9).abs() < 1e-7);

        p = p.step().step().step().back().back();
        assert!((p.value() - 0.9).abs() < 1e-7);
    }
}
<|endoftext|>


<commit_before>use world::World;
use piston_window::*;
use camera::Camera;
use cgmath::{Vector2, vec3};
use cgmath::prelude::*;
use color::*;
use car::*;
use piston_window::Ellipse;
use bot::BoxRules;
use std::cell::RefCell;
use std::ops::DerefMut;
use std::time::Instant;

// `Game` contains every things to run the game
pub struct Game {
    config: GameConfig,
    world: World, // All objects in the game
    window: PistonWindow,
    bot_rules: BoxRules, // Rules to create a new bot
    camera: Camera, // Camera for rendering
    state: State, // Current state of game
    // Wrap these caches in `RefCell` to allow interior mutability
    glyphs: RefCell<Glyphs>, // Font cache
    ellipse: RefCell<Ellipse>, // Model to draw a circle
}

struct State {
    pub turn: Turn, // Presents movement of player
    pub sprint: bool, // Player is speeding-up or not
    pub spawn: f64, // Count down time to spawn a new bot
    pub ended: bool, // Game is over or not
    pub game_speed: f64, // Game speed in addition to player's speed
    pub jump_timeout: f64, // Count down to allow the next jump
    pub rotate_cam: bool, // Allow rotation of camera or not
    pub bullets: i64, // The number of bullets left
    pub recharge: f64, // Bullets recharge time
    pub fps: f64, // Real fps of game
    pub last_frame: Instant, // Moment of the last draw
}

pub enum Turn { Left, Right, None, }

// Configurable game's contansts.
// A tuple presents a range of something.
#[derive(Serialize, Deserialize, Clone)]
pub struct GameConfig {
    pub title: String,
    pub screen_size: ::Pixel,
    pub ups: u64, // Update per second
    pub max_fps: u64,
    pub tunel_size: [f64; 3],
    pub player_size: [f64; 3],
    pub player_speed: (f64, f64), // min and max player speed
    pub player_turn_speed: f64,
    pub bot_size: [(f64, f64); 3], // Range of bot's size
    pub bot_speed: (f64, f64),
    pub bot_turn_speed: (f64, f64),
    pub divider_size: [f64; 2],
    pub camera_height: f64, // Height of camera (from player)
    pub camera_distance: f64, // Distance from camera to player
    pub decor_distance: f64, // Distance between each decoration
    pub sprint_factor: f64,
    pub spawn_time: (f64, f64),
    pub game_sprint: f64, // The increase of game_speed
    pub game_max_speed: f64,
    pub player_jump_v: f64,
    pub player_jump_a: f64,
    pub jump_turn_decrease: f64,
    pub jump_timeout: f64,
    pub mouse_speed: f64,
    pub trueshot_distance: f64,
    pub bullet_stock: i64, // Number of bullets
    pub recharge_time: f64,
    pub bullet_len: f64,
    pub bullet_speed: f64,
    pub zoom_in: bool, // If true, zoom-in while on stare mode
}

impl Game {
    pub fn new(config: GameConfig) -> Game {
        let mut window: PistonWindow = WindowSettings::new(
            config.title.clone(), [config.screen_size.w, config.screen_size.h])
            .exit_on_esc(true).build()
            .expect("Cannot create window.");
        window.set_ups(config.ups);
        window.set_max_fps(config.max_fps);
        window.set_capture_cursor(true);
        let glyphs = Glyphs::new("resources/Ubuntu-R.ttf", window.factory.clone())
            .expect("Unable to load font.");
        let bot_rules = BoxRules {
            size: config.bot_size,
            position: [(0., config.tunel_size[0]), (0., 0.), (config.tunel_size[2], config.tunel_size[2])],
            speed: config.bot_speed,
            turn_speed: config.bot_turn_speed,
            color: vec![RED, ORANGE, VIOLET, GREEN, PALE],
            jump_turn_decrease: config.jump_turn_decrease,
        };
        let world = World::new(&config);
        let camera = Game::new_camera(&config, &world.player);
        let state = State {
            turn: Turn::None,
            sprint: false,
            spawn: 0.,
            ended: false,
            game_speed: 0.,
            jump_timeout: 0.,
            rotate_cam: false,
            bullets: config.bullet_stock,
            recharge: 0.,
            fps: 0.,
            last_frame: Instant::now(),
        };
        let ellipse = Ellipse {
            color: BLACK.alpha(0.).into(),
            border: Some(ellipse::Border {
                color: RED.alpha(0.5).into(),
                radius: 1.,
            }),
            resolution: 360,
        };

        Game {
            config: config,
            world: world,
            window: window,
            bot_rules: bot_rules,
            camera: camera,
            state: state,
            glyphs: RefCell::new(glyphs),
            ellipse: RefCell::new(ellipse),
        }
    }

    fn new_camera<T: Car>(config: &GameConfig, player: &T) -> Camera {
        Camera::new(
            config.screen_size.clone(),
            vec3(0., config.camera_height, -config.camera_distance) + player.pos()
        )
    }

    pub fn run(&mut self) {
        while let Some(e) = self.window.next() {
            match e {
                Input::Press(key) => self.press(key),
                Input::Release(key) => self.release(key),
                Input::Render(_) => {
                    // Calculate fps
                    let d = self.state.last_frame.elapsed();
                    self.state.last_frame = Instant::now();
                    self.state.fps = 1. / (d.as_secs() as f64 + 1e-9*d.subsec_nanos() as f64);
                    self.draw(&e);
                },
                Input::Update(args) => self.update(args.dt),
                Input::Move(Motion::MouseRelative(a, b)) => self.mouse_move(a as f64, b as f64),
                _ => {}
            }
            if self.state.ended {
                break;
            }
        }
    }
    fn mouse_move(&mut self, x: f64, y: f64) {
        if self.state.rotate_cam {
            self.camera.rotate(x*self.config.mouse_speed, y*self.config.mouse_speed, self.world.player.position);
        }
    }
    fn press(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => self.state.turn = Turn::Left,
            Button::Keyboard(Key::D) => self.state.turn = Turn::Right,
            Button::Keyboard(Key::W) => self.state.sprint = true,
            Button::Keyboard(Key::Space) => if self.state.jump_timeout <= 0. {
                self.state.jump_timeout = self.config.jump_timeout;
                self.world.player.jump();
            },
            Button::Mouse(MouseButton::Right) => {
                if self.config.zoom_in {
                    self.camera.zoom_in();
                }
                self.state.rotate_cam = true;
            },
            Button::Mouse(MouseButton::Left) => if self.state.rotate_cam && self.state.bullets > 0 {
                let mut pos = self.world.player.position;
                pos.y += self.world.player.size.y;
                let mut d = vec3(0., 0., self.config.trueshot_distance + self.config.camera_distance);
                d = self.camera.c * d.magnitude2() / d.dot(self.camera.c);
                d = self.camera.eye + d - pos;
                d = d * self.config.bullet_speed / d.magnitude();
                self.world.add_bullet(pos, d, self.config.bullet_len);
                self.state.bullets -= 1;
                if self.state.bullets <= 0 {
                    self.state.recharge = self.config.recharge_time;
                }
            },
            _ => (),
        }
    }
    fn release(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => if let Turn::Left = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::D) => if let Turn::Right = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::W) => self.state.sprint = false,
            Button::Mouse(MouseButton::Right) => {
                self.state.rotate_cam = false;
                self.camera = Game::new_camera(&self.config, &self.world.player);
            },
            _ => (),
        }
    }
    fn draw(&mut self, e: &Input) {
        // Return a horizontal bar
        macro_rules! bar {
            ($curr: expr, $full: expr) => {
                [0.,
                self.config.screen_size.h as f64 - 20.,
                self.config.screen_size.w as f64/2.*$curr/$full,
                self.config.screen_size.h as f64,]
            };
        }
        let jump_bar = bar!(self.state.jump_timeout, self.config.jump_timeout);
        let recharge_bar = bar!(self.state.recharge, self.config.recharge_time);
        let bullets_bar = bar!(self.state.bullets as f64, self.config.bullet_stock as f64);
        // Closure in `draw_2d` requires unique access to `self`,
        // so we use RefCell to hack it.
        let mut glyphs = self.glyphs.borrow_mut();
        let fps = format!("{:.3}", self.state.fps);
        let lines = self.world.render(&self.camera);
        self.window.draw_2d(e, |c, g| {
            clear(BLACK.into(), g);
            for (l, color) in lines {
                line(color.into(), 1., convert(l), c.transform, g);
            }
            rectangle(BLUE.alpha(0.4).into(), jump_bar, c.transform, g);
            rectangle(RED.alpha(0.4).into(), recharge_bar, c.transform, g);
            rectangle(GREEN.alpha(0.4).into(), bullets_bar, c.transform, g);
            text(WHITE.into(), 10, &fps, glyphs.deref_mut(), c.transform.trans(0., 10.), g);
        });

        if self.state.rotate_cam {
            let w = 20.;
            let x = self.config.screen_size.w as f64 /2. - w/2.;
            let y = self.config.screen_size.h as f64 /2. - w/2.;
            let ellipse = self.ellipse.borrow();
            self.window.draw_2d(e, |c, g| {
                ellipse.draw([x, y, w, w], &c.draw_state, c.transform, g);
                rectangle(RED.into(), [x+w/2.-1., y+w/2.-1., 2., 2.], c.transform, g);
            });
        }

    }
    // `dt` stands for delta, duration since the last update
    fn update(&mut self, dt: f64) {
        let old = self.world.player.position;
        if self.state.bullets <= 0 {
            self.state.recharge -= dt;
            if self.state.recharge < 0. {
                self.state.bullets = self.config.bullet_stock;
            }
        }
        self.state.jump_timeout -= dt;
        if self.state.game_speed < self.config.game_max_speed {
            self.state.game_speed += dt*self.config.game_sprint;
        }
        if self.state.sprint {
            if self.world.player.speed < self.config.player_speed.1 {
                self.world.player.speed += dt*self.config.sprint_factor;
            }
        } else if self.world.player.speed > self.config.player_speed.0 {
            self.world.player.speed -= dt*self.config.sprint_factor;
        }
        self.state.spawn -= dt;
        if self.state.spawn < 0. {
            self.world.add_bot(&self.bot_rules);
            self.state.spawn += ::rnd(self.config.spawn_time);
        }
        match self.state.turn {
            Turn::Left => self.world.player.turn_left(dt),
            Turn::Right => self.world.player.turn_right(dt),
            Turn::None => (),
        }
        // Update objects in the world
        self.world.update(dt, self.state.game_speed);
        // Validate things like object's boundary, bullets and boxes
        // collisions.
        self.world.validate();
        // Update camera's location
        self.camera.eye += self.world.player.position - old;
        // Check for player's collision with bot
        if self.world.bots.iter().any(|x| self.world.player.crashed(&x.car)) {
            self.state.ended = true;
        }
    }
}

fn convert(x: [Vector2<f64>; 2]) -> [f64; 4] {
    [x[0].x, x[0].y, x[1].x, x[1].y]
}
<commit_msg>Re-calculate delta<commit_after>use world::World;
use piston_window::*;
use camera::Camera;
use cgmath::{Vector2, vec3};
use cgmath::prelude::*;
use color::*;
use car::*;
use piston_window::Ellipse;
use bot::BoxRules;
use std::cell::RefCell;
use std::ops::DerefMut;
use std::time::Instant;

// `Game` contains every things to run the game
pub struct Game {
    config: GameConfig,
    world: World, // All objects in the game
    window: PistonWindow,
    bot_rules: BoxRules, // Rules to create a new bot
    camera: Camera, // Camera for rendering
    state: State, // Current state of game
    // Wrap these caches in `RefCell` to allow interior mutability
    glyphs: RefCell<Glyphs>, // Font cache
    ellipse: RefCell<Ellipse>, // Model to draw a circle
}

struct State {
    pub turn: Turn, // Presents movement of player
    pub sprint: bool, // Player is speeding-up or not
    pub spawn: f64, // Count down time to spawn a new bot
    pub ended: bool, // Game is over or not
    pub game_speed: f64, // Game speed in addition to player's speed
    pub jump_timeout: f64, // Count down to allow the next jump
    pub rotate_cam: bool, // Allow rotation of camera or not
    pub bullets: i64, // The number of bullets left
    pub recharge: f64, // Bullets recharge time
    pub fps: f64, // Real fps of game
    pub last_frame: Instant, // Moment of the last draw
}

pub enum Turn { Left, Right, None, }

// Configurable game's contansts.
// A tuple presents a range of something.
#[derive(Serialize, Deserialize, Clone)]
pub struct GameConfig {
    pub title: String,
    pub screen_size: ::Pixel,
    pub ups: u64, // Update per second
    pub max_fps: u64,
    pub tunel_size: [f64; 3],
    pub player_size: [f64; 3],
    pub player_speed: (f64, f64), // min and max player speed
    pub player_turn_speed: f64,
    pub bot_size: [(f64, f64); 3], // Range of bot's size
    pub bot_speed: (f64, f64),
    pub bot_turn_speed: (f64, f64),
    pub divider_size: [f64; 2],
    pub camera_height: f64, // Height of camera (from player)
    pub camera_distance: f64, // Distance from camera to player
    pub decor_distance: f64, // Distance between each decoration
    pub sprint_factor: f64,
    pub spawn_time: (f64, f64),
    pub game_sprint: f64, // The increase of game_speed
    pub game_max_speed: f64,
    pub player_jump_v: f64,
    pub player_jump_a: f64,
    pub jump_turn_decrease: f64,
    pub jump_timeout: f64,
    pub mouse_speed: f64,
    pub trueshot_distance: f64,
    pub bullet_stock: i64, // Number of bullets
    pub recharge_time: f64,
    pub bullet_len: f64,
    pub bullet_speed: f64,
    pub zoom_in: bool, // If true, zoom-in while on stare mode
}

impl Game {
    pub fn new(config: GameConfig) -> Game {
        let mut window: PistonWindow = WindowSettings::new(
            config.title.clone(), [config.screen_size.w, config.screen_size.h])
            .exit_on_esc(true).build()
            .expect("Cannot create window.");
        window.set_ups(config.ups);
        window.set_max_fps(config.max_fps);
        window.set_capture_cursor(true);
        let glyphs = Glyphs::new("resources/Ubuntu-R.ttf", window.factory.clone())
            .expect("Unable to load font.");
        let bot_rules = BoxRules {
            size: config.bot_size,
            position: [(0., config.tunel_size[0]), (0., 0.), (config.tunel_size[2], config.tunel_size[2])],
            speed: config.bot_speed,
            turn_speed: config.bot_turn_speed,
            color: vec![RED, ORANGE, VIOLET, GREEN, PALE],
            jump_turn_decrease: config.jump_turn_decrease,
        };
        let world = World::new(&config);
        let camera = Game::new_camera(&config, &world.player);
        let state = State {
            turn: Turn::None,
            sprint: false,
            spawn: 0.,
            ended: false,
            game_speed: 0.,
            jump_timeout: 0.,
            rotate_cam: false,
            bullets: config.bullet_stock,
            recharge: 0.,
            fps: 0.,
            last_frame: Instant::now(),
        };
        let ellipse = Ellipse {
            color: BLACK.alpha(0.).into(),
            border: Some(ellipse::Border {
                color: RED.alpha(0.5).into(),
                radius: 1.,
            }),
            resolution: 360,
        };

        Game {
            config: config,
            world: world,
            window: window,
            bot_rules: bot_rules,
            camera: camera,
            state: state,
            glyphs: RefCell::new(glyphs),
            ellipse: RefCell::new(ellipse),
        }
    }

    fn new_camera<T: Car>(config: &GameConfig, player: &T) -> Camera {
        Camera::new(
            config.screen_size.clone(),
            vec3(0., config.camera_height, -config.camera_distance) + player.pos()
        )
    }
    // Re-calculate fps
    fn update_fps(&mut self) {
        let d = self.state.last_frame.elapsed();
        self.state.last_frame = Instant::now();
        self.state.fps = 1. / (d.as_secs() as f64 + 1e-9*d.subsec_nanos() as f64);
    }

    pub fn run(&mut self) {
        while let Some(e) = self.window.next() {
            match e {
                Input::Press(key) => self.press(key),
                Input::Release(key) => self.release(key),
                Input::Render(_) => {
                    self.update_fps();
                    self.draw(&e);
                },
                Input::Update(args) => self.update(args.dt),
                Input::Move(Motion::MouseRelative(a, b)) => self.mouse_move(a as f64, b as f64),
                _ => {}
            }
            if self.state.ended {
                break;
            }
        }
    }
    fn mouse_move(&mut self, x: f64, y: f64) {
        if self.state.rotate_cam {
            self.camera.rotate(x*self.config.mouse_speed, y*self.config.mouse_speed, self.world.player.position);
        }
    }
    fn press(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => self.state.turn = Turn::Left,
            Button::Keyboard(Key::D) => self.state.turn = Turn::Right,
            Button::Keyboard(Key::W) => self.state.sprint = true,
            Button::Keyboard(Key::Space) => if self.state.jump_timeout <= 0. {
                self.state.jump_timeout = self.config.jump_timeout;
                self.world.player.jump();
            },
            Button::Mouse(MouseButton::Right) => {
                if self.config.zoom_in {
                    self.camera.zoom_in();
                }
                self.state.rotate_cam = true;
            },
            Button::Mouse(MouseButton::Left) => if self.state.rotate_cam && self.state.bullets > 0 {
                let mut pos = self.world.player.position;
                pos.y += self.world.player.size.y;
                let mut d = vec3(0., 0., self.config.trueshot_distance + self.config.camera_distance);
                d = self.camera.c * d.magnitude2() / d.dot(self.camera.c);
                d = self.camera.eye + d - pos;
                d = d * self.config.bullet_speed / d.magnitude();
                self.world.add_bullet(pos, d, self.config.bullet_len);
                self.state.bullets -= 1;
                if self.state.bullets <= 0 {
                    self.state.recharge = self.config.recharge_time;
                }
            },
            _ => (),
        }
    }
    fn release(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => if let Turn::Left = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::D) => if let Turn::Right = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::W) => self.state.sprint = false,
            Button::Mouse(MouseButton::Right) => {
                self.state.rotate_cam = false;
                self.camera = Game::new_camera(&self.config, &self.world.player);
            },
            _ => (),
        }
    }
    fn draw(&mut self, e: &Input) {
        // Return a horizontal bar
        macro_rules! bar {
            ($curr: expr, $full: expr) => {
                [0.,
                self.config.screen_size.h as f64 - 20.,
                self.config.screen_size.w as f64/2.*$curr/$full,
                self.config.screen_size.h as f64,]
            };
        }
        let jump_bar = bar!(self.state.jump_timeout, self.config.jump_timeout);
        let recharge_bar = bar!(self.state.recharge, self.config.recharge_time);
        let bullets_bar = bar!(self.state.bullets as f64, self.config.bullet_stock as f64);
        // Closure in `draw_2d` requires unique access to `self`,
        // so we use RefCell to hack it.
        let mut glyphs = self.glyphs.borrow_mut();
        let fps = format!("{:.3}", self.state.fps);
        let lines = self.world.render(&self.camera);
        self.window.draw_2d(e, |c, g| {
            clear(BLACK.into(), g);
            for (l, color) in lines {
                line(color.into(), 1., convert(l), c.transform, g);
            }
            rectangle(BLUE.alpha(0.4).into(), jump_bar, c.transform, g);
            rectangle(RED.alpha(0.4).into(), recharge_bar, c.transform, g);
            rectangle(GREEN.alpha(0.4).into(), bullets_bar, c.transform, g);
            text(WHITE.into(), 10, &fps, glyphs.deref_mut(), c.transform.trans(0., 10.), g);
        });

        if self.state.rotate_cam {
            let w = 20.;
            let x = self.config.screen_size.w as f64 /2. - w/2.;
            let y = self.config.screen_size.h as f64 /2. - w/2.;
            let ellipse = self.ellipse.borrow();
            self.window.draw_2d(e, |c, g| {
                ellipse.draw([x, y, w, w], &c.draw_state, c.transform, g);
                rectangle(RED.into(), [x+w/2.-1., y+w/2.-1., 2., 2.], c.transform, g);
            });
        }

    }
    // `dt` stands for delta, duration since the last update
    fn update(&mut self, dt: f64) {
        // Re-calculate delta according to fps
        let dt = if self.state.fps != 0. { 1./self.state.fps}
        else { dt };
        let old = self.world.player.position;
        if self.state.bullets <= 0 {
            self.state.recharge -= dt;
            if self.state.recharge < 0. {
                self.state.bullets = self.config.bullet_stock;
            }
        }
        self.state.jump_timeout -= dt;
        if self.state.game_speed < self.config.game_max_speed {
            self.state.game_speed += dt*self.config.game_sprint;
        }
        if self.state.sprint {
            if self.world.player.speed < self.config.player_speed.1 {
                self.world.player.speed += dt*self.config.sprint_factor;
            }
        } else if self.world.player.speed > self.config.player_speed.0 {
            self.world.player.speed -= dt*self.config.sprint_factor;
        }
        self.state.spawn -= dt;
        if self.state.spawn < 0. {
            self.world.add_bot(&self.bot_rules);
            self.state.spawn += ::rnd(self.config.spawn_time);
        }
        match self.state.turn {
            Turn::Left => self.world.player.turn_left(dt),
            Turn::Right => self.world.player.turn_right(dt),
            Turn::None => (),
        }
        // Update objects in the world
        self.world.update(dt, self.state.game_speed);
        // Validate things like object's boundary, bullets and boxes
        // collisions.
        self.world.validate();
        // Update camera's location
        self.camera.eye += self.world.player.position - old;
        // Check for player's collision with bot
        if self.world.bots.iter().any(|x| self.world.player.crashed(&x.car)) {
            self.state.ended = true;
        }
    }
}

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