<commit_before>use std::default::Default;
use std::marker::PhantomData;
use std::mem;

use gfx;
use gfx::traits::*;

use bitmap_font::BitmapFont;
use utils::{grow_buffer, MAT4_ID};

pub struct TextRenderer<R: gfx::Resources> {
    program: gfx::handle::Program<R>,
    state: gfx::DrawState,
    bitmap_font: BitmapFont,
    vertex_data: Vec<Vertex>,
    index_data: Vec<u32>,
    vertex_buffer: gfx::handle::Buffer<R, Vertex>,
    index_buffer: gfx::handle::IndexBuffer<R, u32>,
    params: TextShaderParams<R>,
}

impl<R: gfx::Resources> TextRenderer<R> {

    pub fn new<F: gfx::Factory<R>> (
        device_capabilities: gfx::device::Capabilities,
        factory: &mut F,
        frame_size: [u32; 2],
        initial_buffer_size: usize,
        bitmap_font: BitmapFont,
        font_texture: gfx::handle::Texture<R>,
    ) -> Result<TextRenderer<R>, gfx::ProgramError> {

        let shader_model = device_capabilities.shader_model;

        let vertex = gfx::ShaderSource {
            glsl_120: Some(VERTEX_SRC[0]),
            glsl_150: Some(VERTEX_SRC[1]),
            .. gfx::ShaderSource::empty()
        };

        let fragment = gfx::ShaderSource {
            glsl_120: Some(FRAGMENT_SRC[0]),
            glsl_150: Some(FRAGMENT_SRC[1]),
            .. gfx::ShaderSource::empty()
        };

        let program = match factory.link_program(
            vertex.choose(shader_model).unwrap(),
            fragment.choose(shader_model).unwrap()
        ) {
            Ok(program_handle) => program_handle,
            Err(e) => return Err(e),
        };

        let vertex_buffer = factory.create_buffer::<Vertex>(initial_buffer_size, gfx::BufferUsage::Dynamic);
        let index_buffer = gfx::handle::IndexBuffer::from_raw(
            factory.create_buffer_raw(initial_buffer_size * mem::size_of::<u32>(), gfx::BufferUsage::Dynamic)
        );

        let sampler = factory.create_sampler(
           gfx::tex::SamplerInfo::new(
               gfx::tex::FilterMethod::Scale,
               gfx::tex::WrapMode::Clamp
            )
        );

        let state = gfx::DrawState::new().blend(gfx::BlendPreset::Alpha);

        Ok(TextRenderer {
            vertex_data: Vec::new(),
            index_data: Vec::new(),
            bitmap_font: bitmap_font,
            program: program,
            state: state,
            vertex_buffer: vertex_buffer,
            index_buffer: index_buffer,
            params: TextShaderParams {
                model_view_proj: MAT4_ID,
                screen_size: [frame_size[0] as f32, frame_size[1] as f32],
                tex_font: (font_texture, Some(sampler)),
                _r: PhantomData,
            },
        })
    }

    pub fn draw_text_at_position(
        &mut self,
        text: &str,
        world_position: [f32; 3],
        color: [f32; 4],
    ) {
        self.draw_text(text, [0, 0], world_position, 0, color);
    }

    pub fn draw_text_on_screen(
        &mut self,
        text: &str,
        screen_position: [i32; 2],
        color: [f32; 4],
    ) {
        self.draw_text(text, screen_position, [0.0, 0.0, 0.0], 1, color);
    }

    fn draw_text(
        &mut self,
        text: &str,
        screen_position: [i32; 2],
        world_position: [f32; 3],
        screen_relative: i32,
        color: [f32; 4],
    ) {
        let mut x = screen_position[0];
        let y = screen_position[1];

        let scale_w = self.bitmap_font.scale_w as f32;
        let scale_h = self.bitmap_font.scale_h as f32;

        // placeholder for characters missing from font
        let default_character = Default::default();

        for character in text.chars() {

            let bc = match self.bitmap_font.characters.get(&character) {
                Some(c) => c,
                None => &default_character,
            };

            // Push quad vertices in CCW direction
            let index = self.vertex_data.len();

            let x_offset = (bc.xoffset as i32 + x) as f32;
            let y_offset = (bc.yoffset as i32 + y) as f32;

            // 0 - top left
            self.vertex_data.push(Vertex {
                position: [
                    x_offset,
                    y_offset,
                ],
                color: color,
                texcoords: [
                    bc.x as f32 / scale_w,
                    bc.y as f32 / scale_h,
                ],
                world_position: world_position,
                screen_relative: screen_relative,
            });

            // 1 - bottom left
            self.vertex_data.push(Vertex{
                position: [
                    x_offset,
                    bc.height as f32 + y_offset
                ],
                color: color,
                texcoords: [
                    bc.x as f32 / scale_w,
                    (bc.y + bc.height) as f32 / scale_h,
                ],
                world_position: world_position,
                screen_relative: screen_relative,
            });

            // 2 - bottom right
            self.vertex_data.push(Vertex{
                position: [
                    bc.width as f32 + x_offset,
                    bc.height as f32 + y_offset,
                ],
                color: color,
                texcoords: [
                    (bc.x + bc.width) as f32 / scale_w,
                    (bc.y + bc.height) as f32 / scale_h,
                ],
                world_position: world_position,
                screen_relative: screen_relative,
            });

            // 3 - top right
            self.vertex_data.push(Vertex{
                position: [
                    bc.width as f32 + x_offset,
                    y_offset,
                ],
                color: color,
                texcoords: [
                    (bc.x + bc.width) as f32 / scale_w,
                    bc.y as f32 / scale_h,
                ],
                world_position: world_position,
                screen_relative: screen_relative,
            });

            // Top-left triangle
            self.index_data.push((index + 0) as u32);
            self.index_data.push((index + 1) as u32);
            self.index_data.push((index + 3) as u32);

            // Bottom-right triangle
            self.index_data.push((index + 3) as u32);
            self.index_data.push((index + 1) as u32);
            self.index_data.push((index + 2) as u32);

            x += bc.xadvance as i32;
        }
    }

    ///
    /// Draw and clear the current batch of text.
    ///
    pub fn render<
        C: gfx::CommandBuffer<R>,
        F: gfx::Factory<R>,
        O: gfx::render::target::Output<R>,
    > (
        &mut self,
        renderer: &mut gfx::Renderer<R, C>,
        factory: &mut F,
        output: &O,
        projection: [[f32; 4]; 4],
    ) {

        if self.vertex_data.len() > self.vertex_buffer.len() {
            self.vertex_buffer = gfx::handle::Buffer::from_raw(
                grow_buffer::<R, F, Vertex>(factory, self.vertex_buffer.raw(), self.vertex_data.len())
            );
        }

        if self.index_data.len() > self.index_buffer.len() {
            self.index_buffer = gfx::handle::IndexBuffer::from_raw(
                grow_buffer::<R, F, u32>(factory, self.index_buffer.raw(), self.index_data.len())
            );
        }

        factory.update_buffer(&self.vertex_buffer, &self.vertex_data[..], 0);
        factory.update_buffer_raw(&self.index_buffer.raw(), gfx::as_byte_slice(&self.index_data[..]), 0);

        self.params.screen_size = {
            let (w, h) = output.get_size();
            [w as f32, h as f32]
        };
        self.params.model_view_proj = projection;

        let mesh = gfx::Mesh::from_format(
            self.vertex_buffer.clone(),
            self.vertex_data.len() as gfx::VertexCount
        );

        let slice = gfx::Slice {
            start: 0,
            end: self.index_data.len() as u32,
            prim_type: gfx::PrimitiveType::TriangleList,
            kind: gfx::SliceKind::Index32(self.index_buffer.clone(), 0),
        };

        renderer.draw(
            &gfx::batch::bind(&self.state, &mesh, slice, &self.program, &self.params),
            output
        ).unwrap();

        self.vertex_data.clear();
        self.index_data.clear();
    }
}

static VERTEX_SRC: [&'static [u8]; 2] = [
b"
    #version 120

    uniform vec2 u_screen_size;
    uniform mat4 u_model_view_proj;
    uniform sampler2D u_tex_font;

    attribute vec2 at_position;
    attribute vec4 at_world_position;
    attribute int at_screen_relative;
    attribute vec4 at_color;
    attribute vec2 at_texcoords;
    varying vec4 v_color;
    varying vec2 v_TexCoord;

    void main() {

        // on-screen offset from text origin
        vec2 screen_offset = vec2(
            2 * at_position.x / u_screen_size.x - 1,
            1 - 2 * at_position.y / u_screen_size.y
        );

        vec4 screen_position = u_model_view_proj * at_world_position;

        // perspective divide to get normalized device coords
        vec2 world_offset = vec2(
            screen_position.x / screen_position.z + 1,
            screen_position.y / screen_position.z - 1
        );

        // on-screen offset accounting for world_position
        world_offset = at_screen_relative == 0 ? world_offset : vec2(0.0, 0.0);

        gl_Position = vec4(world_offset + screen_offset, 0, 1.0);

        v_TexCoord = at_texcoords;
        v_color = at_color;

    }
",
b"
    #version 150 core

    uniform vec2 u_screen_size;
    uniform mat4 u_model_view_proj;

    in vec2 at_position;
    in vec4 at_world_position;
    in int at_screen_relative;
    in vec4 at_color;
    in vec2 at_texcoords;
    out vec4 v_color;
    out vec2 v_TexCoord;

    void main() {

        // on-screen offset from text origin
        vec2 screen_offset = vec2(
            2 * at_position.x / u_screen_size.x - 1,
            1 - 2 * at_position.y / u_screen_size.y
        );

        vec4 screen_position = u_model_view_proj * at_world_position;

        // perspective divide to get normalized device coords
        vec2 world_offset = vec2(
            screen_position.x / screen_position.z + 1,
            screen_position.y / screen_position.z - 1
        );

        // on-screen offset accounting for world_position
        world_offset = at_screen_relative == 0 ? world_offset : vec2(0.0, 0.0);

        gl_Position = vec4(world_offset + screen_offset, 0, 1.0);

        v_TexCoord = at_texcoords;
        v_color = at_color;

    }
"];

static FRAGMENT_SRC: [&'static [u8]; 2] = [
b"
    #version 120

    uniform sampler2D u_tex_font;

    varying vec4 v_color;
    varying vec2 v_TexCoord;

    void main() {
        vec4 font_color = texture2D(u_tex_font, v_TexCoord);
        gl_FragColor = vec4(v_color.xyz, font_color.a * v_color.a);
    }
",
b"
    #version 150 core

    uniform sampler2D u_tex_font;

    in vec4 v_color;
    in vec2 v_TexCoord;
    out vec4 out_color;

    void main() {
        vec4 font_color = texture(u_tex_font, v_TexCoord);
        out_color = vec4(v_color.xyz, font_color.a * v_color.a);
    }
"];

gfx_vertex!( Vertex {
    at_position@ position: [f32; 2],
    at_texcoords@ texcoords: [f32; 2],
    at_world_position@ world_position: [f32; 3],
    at_screen_relative@ screen_relative: i32,
    at_color@ color: [f32; 4],
});

gfx_parameters!( TextShaderParams/Link {
    u_model_view_proj@ model_view_proj: [[f32; 4]; 4],
    u_screen_size@ screen_size: [f32; 2],
    u_tex_font@ tex_font: gfx::shade::TextureParam<R>,
});
<commit_msg>Using link_program_source<commit_after>use std::default::Default;
use std::marker::PhantomData;
use std::mem;

use gfx;
use gfx::traits::*;

use bitmap_font::BitmapFont;
use utils::{grow_buffer, MAT4_ID};

pub struct TextRenderer<R: gfx::Resources> {
    program: gfx::handle::Program<R>,
    state: gfx::DrawState,
    bitmap_font: BitmapFont,
    vertex_data: Vec<Vertex>,
    index_data: Vec<u32>,
    vertex_buffer: gfx::handle::Buffer<R, Vertex>,
    index_buffer: gfx::handle::IndexBuffer<R, u32>,
    params: TextShaderParams<R>,
}

impl<R: gfx::Resources> TextRenderer<R> {

    pub fn new<F: gfx::Factory<R>> (
        device_capabilities: gfx::device::Capabilities,
        factory: &mut F,
        frame_size: [u32; 2],
        initial_buffer_size: usize,
        bitmap_font: BitmapFont,
        font_texture: gfx::handle::Texture<R>,
    ) -> Result<TextRenderer<R>, gfx::ProgramError> {

        let vertex = gfx::ShaderSource {
            glsl_120: Some(VERTEX_SRC[0]),
            glsl_150: Some(VERTEX_SRC[1]),
            .. gfx::ShaderSource::empty()
        };

        let fragment = gfx::ShaderSource {
            glsl_120: Some(FRAGMENT_SRC[0]),
            glsl_150: Some(FRAGMENT_SRC[1]),
            .. gfx::ShaderSource::empty()
        };

        let program = match factory.link_program_source(
            vertex, fragment, &device_capabilities
        ) {
            Ok(program_handle) => program_handle,
            Err(e) => return Err(e),
        };

        let vertex_buffer = factory.create_buffer::<Vertex>(initial_buffer_size, gfx::BufferUsage::Dynamic);
        let index_buffer = gfx::handle::IndexBuffer::from_raw(
            factory.create_buffer_raw(initial_buffer_size * mem::size_of::<u32>(), gfx::BufferUsage::Dynamic)
        );

        let sampler = factory.create_sampler(
           gfx::tex::SamplerInfo::new(
               gfx::tex::FilterMethod::Scale,
               gfx::tex::WrapMode::Clamp
            )
        );

        let state = gfx::DrawState::new().blend(gfx::BlendPreset::Alpha);

        Ok(TextRenderer {
            vertex_data: Vec::new(),
            index_data: Vec::new(),
            bitmap_font: bitmap_font,
            program: program,
            state: state,
            vertex_buffer: vertex_buffer,
            index_buffer: index_buffer,
            params: TextShaderParams {
                model_view_proj: MAT4_ID,
                screen_size: [frame_size[0] as f32, frame_size[1] as f32],
                tex_font: (font_texture, Some(sampler)),
                _r: PhantomData,
            },
        })
    }

    pub fn draw_text_at_position(
        &mut self,
        text: &str,
        world_position: [f32; 3],
        color: [f32; 4],
    ) {
        self.draw_text(text, [0, 0], world_position, 0, color);
    }

    pub fn draw_text_on_screen(
        &mut self,
        text: &str,
        screen_position: [i32; 2],
        color: [f32; 4],
    ) {
        self.draw_text(text, screen_position, [0.0, 0.0, 0.0], 1, color);
    }

    fn draw_text(
        &mut self,
        text: &str,
        screen_position: [i32; 2],
        world_position: [f32; 3],
        screen_relative: i32,
        color: [f32; 4],
    ) {
        let mut x = screen_position[0];
        let y = screen_position[1];

        let scale_w = self.bitmap_font.scale_w as f32;
        let scale_h = self.bitmap_font.scale_h as f32;

        // placeholder for characters missing from font
        let default_character = Default::default();

        for character in text.chars() {

            let bc = match self.bitmap_font.characters.get(&character) {
                Some(c) => c,
                None => &default_character,
            };

            // Push quad vertices in CCW direction
            let index = self.vertex_data.len();

            let x_offset = (bc.xoffset as i32 + x) as f32;
            let y_offset = (bc.yoffset as i32 + y) as f32;

            // 0 - top left
            self.vertex_data.push(Vertex {
                position: [
                    x_offset,
                    y_offset,
                ],
                color: color,
                texcoords: [
                    bc.x as f32 / scale_w,
                    bc.y as f32 / scale_h,
                ],
                world_position: world_position,
                screen_relative: screen_relative,
            });

            // 1 - bottom left
            self.vertex_data.push(Vertex{
                position: [
                    x_offset,
                    bc.height as f32 + y_offset
                ],
                color: color,
                texcoords: [
                    bc.x as f32 / scale_w,
                    (bc.y + bc.height) as f32 / scale_h,
                ],
                world_position: world_position,
                screen_relative: screen_relative,
            });

            // 2 - bottom right
            self.vertex_data.push(Vertex{
                position: [
                    bc.width as f32 + x_offset,
                    bc.height as f32 + y_offset,
                ],
                color: color,
                texcoords: [
                    (bc.x + bc.width) as f32 / scale_w,
                    (bc.y + bc.height) as f32 / scale_h,
                ],
                world_position: world_position,
                screen_relative: screen_relative,
            });

            // 3 - top right
            self.vertex_data.push(Vertex{
                position: [
                    bc.width as f32 + x_offset,
                    y_offset,
                ],
                color: color,
                texcoords: [
                    (bc.x + bc.width) as f32 / scale_w,
                    bc.y as f32 / scale_h,
                ],
                world_position: world_position,
                screen_relative: screen_relative,
            });

            // Top-left triangle
            self.index_data.push((index + 0) as u32);
            self.index_data.push((index + 1) as u32);
            self.index_data.push((index + 3) as u32);

            // Bottom-right triangle
            self.index_data.push((index + 3) as u32);
            self.index_data.push((index + 1) as u32);
            self.index_data.push((index + 2) as u32);

            x += bc.xadvance as i32;
        }
    }

    ///
    /// Draw and clear the current batch of text.
    ///
    pub fn render<
        C: gfx::CommandBuffer<R>,
        F: gfx::Factory<R>,
        O: gfx::render::target::Output<R>,
    > (
        &mut self,
        renderer: &mut gfx::Renderer<R, C>,
        factory: &mut F,
        output: &O,
        projection: [[f32; 4]; 4],
    ) {

        if self.vertex_data.len() > self.vertex_buffer.len() {
            self.vertex_buffer = gfx::handle::Buffer::from_raw(
                grow_buffer::<R, F, Vertex>(factory, self.vertex_buffer.raw(), self.vertex_data.len())
            );
        }

        if self.index_data.len() > self.index_buffer.len() {
            self.index_buffer = gfx::handle::IndexBuffer::from_raw(
                grow_buffer::<R, F, u32>(factory, self.index_buffer.raw(), self.index_data.len())
            );
        }

        factory.update_buffer(&self.vertex_buffer, &self.vertex_data[..], 0);
        factory.update_buffer_raw(&self.index_buffer.raw(), gfx::as_byte_slice(&self.index_data[..]), 0);

        self.params.screen_size = {
            let (w, h) = output.get_size();
            [w as f32, h as f32]
        };
        self.params.model_view_proj = projection;

        let mesh = gfx::Mesh::from_format(
            self.vertex_buffer.clone(),
            self.vertex_data.len() as gfx::VertexCount
        );

        let slice = gfx::Slice {
            start: 0,
            end: self.index_data.len() as u32,
            prim_type: gfx::PrimitiveType::TriangleList,
            kind: gfx::SliceKind::Index32(self.index_buffer.clone(), 0),
        };

        renderer.draw(
            &gfx::batch::bind(&self.state, &mesh, slice, &self.program, &self.params),
            output
        ).unwrap();

        self.vertex_data.clear();
        self.index_data.clear();
    }
}

static VERTEX_SRC: [&'static [u8]; 2] = [
b"
    #version 120

    uniform vec2 u_screen_size;
    uniform mat4 u_model_view_proj;
    uniform sampler2D u_tex_font;

    attribute vec2 at_position;
    attribute vec4 at_world_position;
    attribute int at_screen_relative;
    attribute vec4 at_color;
    attribute vec2 at_texcoords;
    varying vec4 v_color;
    varying vec2 v_TexCoord;

    void main() {

        // on-screen offset from text origin
        vec2 screen_offset = vec2(
            2 * at_position.x / u_screen_size.x - 1,
            1 - 2 * at_position.y / u_screen_size.y
        );

        vec4 screen_position = u_model_view_proj * at_world_position;

        // perspective divide to get normalized device coords
        vec2 world_offset = vec2(
            screen_position.x / screen_position.z + 1,
            screen_position.y / screen_position.z - 1
        );

        // on-screen offset accounting for world_position
        world_offset = at_screen_relative == 0 ? world_offset : vec2(0.0, 0.0);

        gl_Position = vec4(world_offset + screen_offset, 0, 1.0);

        v_TexCoord = at_texcoords;
        v_color = at_color;

    }
",
b"
    #version 150 core

    uniform vec2 u_screen_size;
    uniform mat4 u_model_view_proj;

    in vec2 at_position;
    in vec4 at_world_position;
    in int at_screen_relative;
    in vec4 at_color;
    in vec2 at_texcoords;
    out vec4 v_color;
    out vec2 v_TexCoord;

    void main() {

        // on-screen offset from text origin
        vec2 screen_offset = vec2(
            2 * at_position.x / u_screen_size.x - 1,
            1 - 2 * at_position.y / u_screen_size.y
        );

        vec4 screen_position = u_model_view_proj * at_world_position;

        // perspective divide to get normalized device coords
        vec2 world_offset = vec2(
            screen_position.x / screen_position.z + 1,
            screen_position.y / screen_position.z - 1
        );

        // on-screen offset accounting for world_position
        world_offset = at_screen_relative == 0 ? world_offset : vec2(0.0, 0.0);

        gl_Position = vec4(world_offset + screen_offset, 0, 1.0);

        v_TexCoord = at_texcoords;
        v_color = at_color;

    }
"];

static FRAGMENT_SRC: [&'static [u8]; 2] = [
b"
    #version 120

    uniform sampler2D u_tex_font;

    varying vec4 v_color;
    varying vec2 v_TexCoord;

    void main() {
        vec4 font_color = texture2D(u_tex_font, v_TexCoord);
        gl_FragColor = vec4(v_color.xyz, font_color.a * v_color.a);
    }
",
b"
    #version 150 core

    uniform sampler2D u_tex_font;

    in vec4 v_color;
    in vec2 v_TexCoord;
    out vec4 out_color;

    void main() {
        vec4 font_color = texture(u_tex_font, v_TexCoord);
        out_color = vec4(v_color.xyz, font_color.a * v_color.a);
    }
"];

gfx_vertex!( Vertex {
    at_position@ position: [f32; 2],
    at_texcoords@ texcoords: [f32; 2],
    at_world_position@ world_position: [f32; 3],
    at_screen_relative@ screen_relative: i32,
    at_color@ color: [f32; 4],
});

gfx_parameters!( TextShaderParams/Link {
    u_model_view_proj@ model_view_proj: [[f32; 4]; 4],
    u_screen_size@ screen_size: [f32; 2],
    u_tex_font@ tex_font: gfx::shade::TextureParam<R>,
});
<|endoftext|>


<commit_before>use core::{Distribution, IntoDistribution};
use uniform::Uniform;

use std::ops::{Range};
use std::num::Wrapping as w;
use rand::Rng;
use num::{Bounded, Integer};

pub trait CreateRange: Integer {
    type Unsigned;
}

pub trait UniformPrimitiveIntegerRangeTrait<T: CreateRange> {
    fn new(low: T, high: T) -> UniformPrimitiveIntegerRange<T>;
    fn sample<R: Rng>(d: &UniformPrimitiveIntegerRange<T>, rng: &mut R) -> T;
}

pub struct UniformPrimitiveIntegerRange<T: CreateRange> {
    low: T,
    range: T::Unsigned,
    accept_zone: T::Unsigned,
    base_distribution: Uniform<T::Unsigned>
}

impl <T: CreateRange> UniformPrimitiveIntegerRange<T> where
    UniformPrimitiveIntegerRange<T>: UniformPrimitiveIntegerRangeTrait<T>
{
    #[inline]
    fn new(low: T, high: T) -> UniformPrimitiveIntegerRange<T> {
        assert!(low < high);
        <Self as UniformPrimitiveIntegerRangeTrait<T>>::new(low, high)
    }
}

impl <T> IntoDistribution<T> for Range<T> where
    T: CreateRange,
    UniformPrimitiveIntegerRange<T>: Distribution<Output=T> + UniformPrimitiveIntegerRangeTrait<T>
{
    type Distribution = UniformPrimitiveIntegerRange<T>;

    #[inline]
    fn into_distribution(self) -> UniformPrimitiveIntegerRange<T> {
        UniformPrimitiveIntegerRange::new(self.start, self.end)
    }
}

impl <T> Distribution for UniformPrimitiveIntegerRange<T> where
    T: CreateRange,
    UniformPrimitiveIntegerRange<T>: UniformPrimitiveIntegerRangeTrait<T>
{
    type Output = T;

    #[inline]
    fn sample<R: Rng>(&self, rng: &mut R) -> T {
        <Self as UniformPrimitiveIntegerRangeTrait<T>>::sample(self, rng)
    }
}

macro_rules! uniform_integer_range_impls {
    ($(($ty:ty, $tyUnsigned:ty)),*) => {
        $(
            impl CreateRange for $ty {
                type Unsigned = $tyUnsigned;
            }

            impl UniformPrimitiveIntegerRangeTrait<$ty> for UniformPrimitiveIntegerRange<$ty> {
                #[inline]
                fn new(low: $ty, high: $ty) -> UniformPrimitiveIntegerRange<$ty> {
                    let unsigned_range = (w(high as $tyUnsigned) - w(low as $tyUnsigned)).0;
                    let unsigned_max: $tyUnsigned = Bounded::max_value();
                    let unsigned_zone = unsigned_max - (unsigned_max % unsigned_range);

                    UniformPrimitiveIntegerRange {
                        low: low,
                        range: unsigned_range,
                        accept_zone: unsigned_zone,
                        base_distribution: Uniform::new()
                    }
                }

                #[inline]
                fn sample<R: Rng>(d: &UniformPrimitiveIntegerRange<$ty>, rng: &mut R) -> $ty {
                    loop {
                        let v: $tyUnsigned = d.base_distribution.sample(rng);

                        if v < d.accept_zone {
                            return (w(d.low) + w((v % d.range) as $ty)).0;
                        }
                    }
                }

            }
        )*
    }
}

macro_rules! signed_and_unsigned_range_impls {
    ($(($ty:ty, $tyUnsigned:ty)),*) => {
        uniform_integer_range_impls! { $(($ty, $tyUnsigned), ($tyUnsigned, $tyUnsigned)),* }
    }
}

signed_and_unsigned_range_impls! {
    (i8, u8), (i16, u16), (i32, u32), (i64, u64), (isize, usize)
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::{Distribution, IntoDistribution};

    use rand::{self, thread_rng, Rng};

    #[should_panic]
    #[test]
    fn test_range_bad_limits_equal() {
        UniformPrimitiveIntegerRange::new(10, 10);
    }

    #[should_panic]
    #[test]
    fn test_range_bad_limits_flipped() {
        UniformPrimitiveIntegerRange::new(10, 5);
    }

    #[test]
    fn test_range_into_distribution() {
        let mut rng: rand::XorShiftRng = rand::thread_rng().gen();
        let d = (1..10).into_distribution();
        let _: u8 = d.sample(&mut rng);
    }
}
<commit_msg>Cleaned up implementation of uniform_range.<commit_after>use core::{Distribution, IntoDistribution};
use uniform::Uniform;

use std::ops::{Range, Add, Sub};
use std::num::Wrapping as w;
use rand::Rng;
use num::{Bounded, PrimInt};

trait PrimitiveInteger: PrimInt {
    type Unsigned : PrimitiveInteger;

    fn to_unsigned(self) -> <Self as PrimitiveInteger>::Unsigned;
    fn from_unsigned(u: <Self as PrimitiveInteger>::Unsigned) -> Self;
}

pub struct UniformPrimitiveIntegerRange<T> {
    low: T,
    range: T,
    accept_zone: T,
    base_distribution: Uniform<T>
}

impl <T: PrimitiveInteger> UniformPrimitiveIntegerRange<T> where
    w<T::Unsigned>: Sub<Output=w<T::Unsigned>> + Add<Output=w<T::Unsigned>>,
    Uniform<T>: Distribution<Output=T>
{
    #[inline]
    fn new(low: T, high: T) -> UniformPrimitiveIntegerRange<T> {
        assert!(low < high);
        let unsigned_range = (w(high.to_unsigned()) - w(low.to_unsigned())).0;
        let unsigned_max: T::Unsigned = Bounded::max_value();
        let unsigned_zone = unsigned_max - (unsigned_max % unsigned_range);

        UniformPrimitiveIntegerRange {
            low: low,
            range: T::from_unsigned(unsigned_range),
            accept_zone: T::from_unsigned(unsigned_zone),
            base_distribution: Uniform::new()
        }
    }
}

impl <T: PrimitiveInteger> IntoDistribution<T> for Range<T> where
    w<T::Unsigned>: Sub<Output=w<T::Unsigned>> + Add<Output=w<T::Unsigned>>,
    Uniform<T>: Distribution<Output=T>
{
    type Distribution = UniformPrimitiveIntegerRange<T>;

    #[inline]
    fn into_distribution(self) -> UniformPrimitiveIntegerRange<T> {
        UniformPrimitiveIntegerRange::new(self.start, self.end)
    }
}

impl <T: PrimitiveInteger> Distribution for UniformPrimitiveIntegerRange<T> where
    w<T::Unsigned>: Sub<Output=w<T::Unsigned>> + Add<Output=w<T::Unsigned>>,
    Uniform<T>: Distribution<Output=T>
{
    type Output = T;

    #[inline]
    fn sample<R: Rng>(&self, rng: &mut R) -> T {
        loop {
            let v = self.base_distribution.sample(rng).to_unsigned();

            if v < (self.accept_zone.to_unsigned()) {
                return T::from_unsigned((
                    w(self.low.to_unsigned()) +
                    w(v % self.range.to_unsigned())
                ).0);
            }
        }
    }
}

macro_rules! uniform_integer_range_impls {
    ($(($ty:ty, $tyUnsigned:ty)),*) => {
        $(
            impl PrimitiveInteger for $ty {
                type Unsigned = $tyUnsigned;

                #[inline]
                fn to_unsigned(self) -> $tyUnsigned {
                    self as $tyUnsigned
                }

                #[inline]
                fn from_unsigned(u: $tyUnsigned) -> Self {
                    u as $ty
                }
            }
        )*
    }
}

macro_rules! signed_and_unsigned_range_impls {
    ($(($tySigned:ty, $tyUnsigned:ty)),*) => {
        uniform_integer_range_impls! {
            $(
                ($tySigned, $tyUnsigned),
                ($tyUnsigned, $tyUnsigned)
            ),*
        }
    }
}

signed_and_unsigned_range_impls! {
    (i8, u8), (i16, u16), (i32, u32), (i64, u64), (isize, usize)
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::{Distribution, IntoDistribution};

    use rand::{self, thread_rng, Rng};

    #[should_panic]
    #[test]
    fn test_range_bad_limits_equal() {
        UniformPrimitiveIntegerRange::new(10, 10);
    }

    #[should_panic]
    #[test]
    fn test_range_bad_limits_flipped() {
        UniformPrimitiveIntegerRange::new(10, 5);
    }

    #[test]
    fn test_range_into_distribution() {
        let mut rng: rand::XorShiftRng = rand::thread_rng().gen();
        let d = (1..10).into_distribution();
        let _: u8 = d.sample(&mut rng);
    }
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::iter::FromIterator;
use std::slice::{Iter, IterMut};
use std::vec::IntoIter;

use crate::stable_hasher::{HashStable, StableHasher};

#[derive(Clone, Encodable, Decodable, Debug)]
pub struct VecMap<K, V>(Vec<(K, V)>);

impl<K, V> VecMap<K, V>
where
    K: PartialEq,
{
    pub fn new() -> Self {
        VecMap(Default::default())
    }

    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) {
            Some(std::mem::replace(&mut elem.1, v))
        } else {
            self.0.push((k, v));
            None
        }
    }

    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
    where
        K: Borrow<Q>,
        Q: Eq,
    {
        self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
    }

    pub fn get_by(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
        self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1)
    }

    pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
    where
        K: Borrow<Q>,
        Q: Eq,
    {
        self.get(k).is_some()
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn iter(&self) -> Iter<'_, (K, V)> {
        self.into_iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<'_, (K, V)> {
        self.into_iter()
    }
}

impl<K, V> Default for VecMap<K, V> {
    #[inline]
    fn default() -> Self {
        Self(Default::default())
    }
}

impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> {
    fn from(vec: Vec<(K, V)>) -> Self {
        Self(vec)
    }
}

impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> {
    fn into(self) -> Vec<(K, V)> {
        self.0
    }
}

impl<K, V> FromIterator<(K, V)> for VecMap<K, V> {
    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
        Self(iter.into_iter().collect())
    }
}

impl<'a, K, V> IntoIterator for &'a VecMap<K, V> {
    type Item = &'a (K, V);
    type IntoIter = Iter<'a, (K, V)>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl<'a, K, V> IntoIterator for &'a mut VecMap<K, V> {
    type Item = &'a mut (K, V);
    type IntoIter = IterMut<'a, (K, V)>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.0.iter_mut()
    }
}

impl<K, V> IntoIterator for VecMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<(K, V)>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<K, V> Extend<(K, V)> for VecMap<K, V> {
    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
        self.0.extend(iter);
    }

    fn extend_one(&mut self, item: (K, V)) {
        self.0.extend_one(item);
    }

    fn extend_reserve(&mut self, additional: usize) {
        self.0.extend_reserve(additional);
    }
}

impl<K, V, CTX> HashStable<CTX> for VecMap<K, V>
where
    K: HashStable<CTX> + Eq,
    V: HashStable<CTX>,
{
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        self.0.hash_stable(hcx, hasher)
    }
}

#[cfg(test)]
mod tests;
<commit_msg>add VecMap docs<commit_after>use std::borrow::Borrow;
use std::iter::FromIterator;
use std::slice::{Iter, IterMut};
use std::vec::IntoIter;

use crate::stable_hasher::{HashStable, StableHasher};

/// A map type implemented as a vector of pairs `K` (key) and `V` (value).
/// It currently provides a subset of all the map operations, the rest could be added as needed.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct VecMap<K, V>(Vec<(K, V)>);

impl<K, V> VecMap<K, V>
where
    K: PartialEq,
{
    pub fn new() -> Self {
        VecMap(Default::default())
    }

    /// Sets the value of the entry, and returns the entry's old value.
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) {
            Some(std::mem::replace(&mut elem.1, v))
        } else {
            self.0.push((k, v));
            None
        }
    }

    /// Gets a reference to the value in the entry.
    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
    where
        K: Borrow<Q>,
        Q: Eq,
    {
        self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
    }

    /// Returns the value corresponding to the supplied predicate filter.
    ///
    /// The supplied predicate will be applied to each (key, value) pair and it will return a
    /// reference to the values where the predicate returns `true`.
    pub fn get_by(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
        self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1)
    }

    /// Returns `true` if the map contains a value for the specified key.
    ///
    /// The key may be any borrowed form of the map's key type,
    /// [`Eq`] on the borrowed form *must* match those for
    /// the key type.
    pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
    where
        K: Borrow<Q>,
        Q: Eq,
    {
        self.get(k).is_some()
    }

    /// Returns `true` if the map contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn iter(&self) -> Iter<'_, (K, V)> {
        self.into_iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<'_, (K, V)> {
        self.into_iter()
    }
}

impl<K, V> Default for VecMap<K, V> {
    #[inline]
    fn default() -> Self {
        Self(Default::default())
    }
}

impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> {
    fn from(vec: Vec<(K, V)>) -> Self {
        Self(vec)
    }
}

impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> {
    fn into(self) -> Vec<(K, V)> {
        self.0
    }
}

impl<K, V> FromIterator<(K, V)> for VecMap<K, V> {
    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
        Self(iter.into_iter().collect())
    }
}

impl<'a, K, V> IntoIterator for &'a VecMap<K, V> {
    type Item = &'a (K, V);
    type IntoIter = Iter<'a, (K, V)>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl<'a, K, V> IntoIterator for &'a mut VecMap<K, V> {
    type Item = &'a mut (K, V);
    type IntoIter = IterMut<'a, (K, V)>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.0.iter_mut()
    }
}

impl<K, V> IntoIterator for VecMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<(K, V)>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<K, V> Extend<(K, V)> for VecMap<K, V> {
    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
        self.0.extend(iter);
    }

    fn extend_one(&mut self, item: (K, V)) {
        self.0.extend_one(item);
    }

    fn extend_reserve(&mut self, additional: usize) {
        self.0.extend_reserve(additional);
    }
}

impl<K, V, CTX> HashStable<CTX> for VecMap<K, V>
where
    K: HashStable<CTX> + Eq,
    V: HashStable<CTX>,
{
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        self.0.hash_stable(hcx, hasher)
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>// TODO: Figure out how to not require explicit element count.
macro_rules! terrain_data {
    {
        count: $count:expr;
        $($symbol:ident, $name:expr;)*
    } => {
#[deriving(Eq, PartialEq, Clone)]
        pub enum TerrainType {
            $($symbol,)*
        }

        fn terrain_name(t: TerrainType) -> &'static str {
            match t {
                $($symbol => $name,)*
            }
        }

        pub static TERRAINS: [TerrainType, ..$count] = [
            $($symbol,)*
            ];

    }
}

terrain_data! {
    count: 28;

    Void, "void";
    Floor, "floor";
    Chasm, "chasm";
    Water, "water";
    Shallows, "shallows";
    Magma, "magma";
    Downstairs, "stairs down";
    Wall, "wall";
    RockWall, "rock wall";
    Rock, "rock";
    Tree, "tree";
    Grass, "grass";
    Stalagmite, "stalagmite";
    Portal, "portal";
    Door, "door";
    OpenDoor, "open door";
    Window, "window";
    Table, "table";
    Fence, "fence";
    Bars, "bars";
    Fountain, "fountain";
    Altar, "altar";
    Barrel, "barrel";
    Grave, "grave";
    Stone, "stone";
    Menhir, "menhir";
    DeadTree, "dead tree";
    TallGrass, "tall grass";
}

impl TerrainType {
    pub fn from_name(name: &str) -> Option<TerrainType> {
        for &t in TERRAINS.iter() {
            if t.name() == name { return Some(t); }
        }
        None
    }

    pub fn is_wall(self) -> bool {
        match self {
            Wall | RockWall | Rock | Door | OpenDoor | Window | Bars | Fence => true,
            _ => false
        }
    }

    pub fn is_opaque(self) -> bool {
        match self {
            Wall | RockWall | Rock | Door | Tree | DeadTree | TallGrass => true,
            _ => false
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self {
            Wall | RockWall | Rock | Tree | Stalagmite | Door | Menhir | DeadTree => true,
            _ => false
        }
    }

    pub fn is_walkable(self) -> bool {
        match self {
            Floor | Shallows | Grass | Downstairs | Portal
                | Door | OpenDoor | TallGrass => true,
            _ => false
        }
    }

    pub fn is_exit(self) -> bool {
        match self {
            Downstairs => true,
            _ => false
        }
    }

    pub fn name(self) -> &'static str { terrain_name(self) }
}
<commit_msg>Printable TerrainType<commit_after>// TODO: Figure out how to not require explicit element count.
macro_rules! terrain_data {
    {
        count: $count:expr;
        $($symbol:ident, $name:expr;)*
    } => {
#[deriving(Eq, PartialEq, Clone, Show)]
        pub enum TerrainType {
            $($symbol,)*
        }

        fn terrain_name(t: TerrainType) -> &'static str {
            match t {
                $($symbol => $name,)*
            }
        }

        pub static TERRAINS: [TerrainType, ..$count] = [
            $($symbol,)*
            ];

    }
}

terrain_data! {
    count: 28;

    Void, "void";
    Floor, "floor";
    Chasm, "chasm";
    Water, "water";
    Shallows, "shallows";
    Magma, "magma";
    Downstairs, "stairs down";
    Wall, "wall";
    RockWall, "rock wall";
    Rock, "rock";
    Tree, "tree";
    Grass, "grass";
    Stalagmite, "stalagmite";
    Portal, "portal";
    Door, "door";
    OpenDoor, "open door";
    Window, "window";
    Table, "table";
    Fence, "fence";
    Bars, "bars";
    Fountain, "fountain";
    Altar, "altar";
    Barrel, "barrel";
    Grave, "grave";
    Stone, "stone";
    Menhir, "menhir";
    DeadTree, "dead tree";
    TallGrass, "tall grass";
}

impl TerrainType {
    pub fn from_name(name: &str) -> Option<TerrainType> {
        for &t in TERRAINS.iter() {
            if t.name() == name { return Some(t); }
        }
        None
    }

    pub fn is_wall(self) -> bool {
        match self {
            Wall | RockWall | Rock | Door | OpenDoor | Window | Bars | Fence => true,
            _ => false
        }
    }

    pub fn is_opaque(self) -> bool {
        match self {
            Wall | RockWall | Rock | Door | Tree | DeadTree | TallGrass => true,
            _ => false
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self {
            Wall | RockWall | Rock | Tree | Stalagmite | Door | Menhir | DeadTree => true,
            _ => false
        }
    }

    pub fn is_walkable(self) -> bool {
        match self {
            Floor | Shallows | Grass | Downstairs | Portal
                | Door | OpenDoor | TallGrass => true,
            _ => false
        }
    }

    pub fn is_exit(self) -> bool {
        match self {
            Downstairs => true,
            _ => false
        }
    }

    pub fn name(self) -> &'static str { terrain_name(self) }
}
<|endoftext|>


<commit_before>use state::State;
use context::base::BaseContext;

pub use self::handlers::ActionHandlers;

#[derive(Clone, Debug)]
pub enum Action {
    Message(self::message::MessageAction)
}

impl Action {
    pub fn execute(&self, state: &State, context: &BaseContext) -> ExecResult {
        let result = match *self {
            Action::Message(ref action) => action.execute(state, context)
        };

        ExecResult::from(result)
    }
}

#[derive(Debug)]
pub enum ExecResult {
    Message(self::message::ExecResult)
}

pub mod handlers {
    use super::ExecResult;
    use super::message;

    pub struct ActionHandlers {
        message_handler: Box<message::ActionHandler>
    }

    impl ActionHandlers {
        pub fn new(message: Box<message::ActionHandler>) -> ActionHandlers {
            ActionHandlers {
                message_handler: message
            }
        }

        pub fn handle(&mut self, command: ExecResult) {
            match command {
                ExecResult::Message(message) => self.message_handler.handle(message)
            }
        }
    }
}

pub mod message {
    use context::base::BaseContext;
    use state::State;
    use message::{Builder, Message};

    #[derive(Debug)]
    pub struct ExecResult(Message);

    impl From<ExecResult> for super::ExecResult {
        fn from(result: ExecResult) -> super::ExecResult {
            super::ExecResult::Message(result)
        }
    }

    #[derive(Clone, Debug)]
    pub struct MessageAction;

    impl MessageAction {
        pub fn new() -> MessageAction {
            MessageAction
        }

        pub fn execute(&self, _: &State, _: &BaseContext) -> ExecResult {
            ExecResult(Builder::new("8015340d-5b44-4b16-8a3f-60b505ccd22e").build())
        }
    }

    impl From<MessageAction> for super::Action {
        fn from(action: MessageAction) -> super::Action {
            super::Action::Message(action)
        }
    }

    pub trait ActionHandler {
        fn handle(&mut self, command: ExecResult);
    }
}
<commit_msg>MessageAction: implement serde::Deserialize trait for MessageAction<commit_after>use state::State;
use context::base::BaseContext;

pub use self::handlers::ActionHandlers;

#[derive(Clone, Debug)]
pub enum Action {
    Message(self::message::MessageAction)
}

impl Action {
    pub fn execute(&self, state: &State, context: &BaseContext) -> ExecResult {
        let result = match *self {
            Action::Message(ref action) => action.execute(state, context)
        };

        ExecResult::from(result)
    }
}

#[derive(Debug)]
pub enum ExecResult {
    Message(self::message::ExecResult)
}

pub mod handlers {
    use super::ExecResult;
    use super::message;

    pub struct ActionHandlers {
        message_handler: Box<message::ActionHandler>
    }

    impl ActionHandlers {
        pub fn new(message: Box<message::ActionHandler>) -> ActionHandlers {
            ActionHandlers {
                message_handler: message
            }
        }

        pub fn handle(&mut self, command: ExecResult) {
            match command {
                ExecResult::Message(message) => self.message_handler.handle(message)
            }
        }
    }
}

pub mod message {
    use context::base::BaseContext;
    use state::State;
    use message::{Builder, Message};

    #[derive(Debug)]
    pub struct ExecResult(Message);

    impl From<ExecResult> for super::ExecResult {
        fn from(result: ExecResult) -> super::ExecResult {
            super::ExecResult::Message(result)
        }
    }

    #[derive(Clone, Debug)]
    pub struct MessageAction;

    impl MessageAction {
        pub fn new() -> MessageAction {
            MessageAction
        }

        pub fn execute(&self, _: &State, _: &BaseContext) -> ExecResult {
            ExecResult(Builder::new("8015340d-5b44-4b16-8a3f-60b505ccd22e").build())
        }
    }

    impl From<MessageAction> for super::Action {
        fn from(action: MessageAction) -> super::Action {
            super::Action::Message(action)
        }
    }

    pub trait ActionHandler {
        fn handle(&mut self, command: ExecResult);
    }

    mod deser {

    use super::MessageAction;
    use serde;
    use serde::de::Deserialize;

    impl serde::Deserialize for MessageAction {
        fn deserialize<D>(deserializer: &mut D) -> Result<MessageAction, D::Error>
            where D: serde::de::Deserializer
        {
            deserializer.visit_unit_struct("MessageAction", MessageActionVisitor)
        }
    }

    struct MessageActionVisitor;

    impl serde::de::Visitor for MessageActionVisitor {
        type Value = MessageAction;
        fn visit_unit<E>(&mut self) -> Result<Self::Value, E>
            where E: serde::de::Error {
            Ok(MessageAction)
        }
    }
    }
}
<|endoftext|>


<commit_before>use std::ops::{AddAssign, MulAssign};

// For implementing base10_digits() accessor on LitInt.
pub struct BigInt {
    digits: Vec<u8>,
}

impl BigInt {
    pub fn new() -> Self {
        BigInt {
            digits: Vec::new(),
        }
    }

    pub fn to_string(&self) -> String {
        unimplemented!()
    }

    fn reserve_two_digits(&mut self) {
        let len = self.digits.len();
        let desired = len
            + !self.digits.ends_with(&[0, 0]) as usize
            + !self.digits.ends_with(&[0]) as usize;
        self.digits.resize(desired, 0);
    }
}

impl AddAssign<u8> for BigInt {
    // Assumes increment <16.
    fn add_assign(&mut self, mut increment: u8) {
        self.reserve_two_digits();

        let mut i = 0;
        while increment > 0 {
            let sum = self.digits[i] + increment;
            self.digits[i] = sum % 10;
            increment = sum / 10;
            i += 1;
        }
    }
}

impl MulAssign<u8> for BigInt {
    // Assumes base <=16.
    fn mul_assign(&mut self, base: u8) {
        self.reserve_two_digits();

        let mut carry = 0;
        for digit in &mut self.digits {
            let prod = *digit * base + carry;
            *digit = prod % 10;
            carry = prod / 10;
        }
    }
}
<commit_msg>Implement bigint to string<commit_after>use std::ops::{AddAssign, MulAssign};

// For implementing base10_digits() accessor on LitInt.
pub struct BigInt {
    digits: Vec<u8>,
}

impl BigInt {
    pub fn new() -> Self {
        BigInt {
            digits: Vec::new(),
        }
    }

    pub fn to_string(&self) -> String {
        let mut repr = String::with_capacity(self.digits.len());

        let mut has_nonzero = false;
        for digit in self.digits.iter().rev() {
            has_nonzero |= *digit != 0;
            if has_nonzero {
                repr.push((*digit + b'0') as char);
            }
        }

        if repr.is_empty() {
            repr.push('0');
        }

        repr
    }

    fn reserve_two_digits(&mut self) {
        let len = self.digits.len();
        let desired = len
            + !self.digits.ends_with(&[0, 0]) as usize
            + !self.digits.ends_with(&[0]) as usize;
        self.digits.resize(desired, 0);
    }
}

impl AddAssign<u8> for BigInt {
    // Assumes increment <16.
    fn add_assign(&mut self, mut increment: u8) {
        self.reserve_two_digits();

        let mut i = 0;
        while increment > 0 {
            let sum = self.digits[i] + increment;
            self.digits[i] = sum % 10;
            increment = sum / 10;
            i += 1;
        }
    }
}

impl MulAssign<u8> for BigInt {
    // Assumes base <=16.
    fn mul_assign(&mut self, base: u8) {
        self.reserve_two_digits();

        let mut carry = 0;
        for digit in &mut self.digits {
            let prod = *digit * base + carry;
            *digit = prod % 10;
            carry = prod / 10;
        }
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate extra;

use std::env;
use std::fs::File;
use std::io::{self, stdout, stderr, Read, Write, Stderr};
use std::iter;
use std::ops::{Add, AddAssign};
use std::process::exit;
use extra::option::OptionalExt;
use extra::io::WriteExt;

static MAN_PAGE: &'static str = /* @MANSTART{wc} */ r#"
NAME
    wc - count words, bytes and lines of a file or byte stream.

SYNOPSIS
    wc [-h | --help] [-c | --bytes] [-w | --words] [-l | --lines] [FILE 1] [FILE 2]...

DESCRIPTION
    This utility will dump word count, line count, and byte count of a file or byte stream. If
    multiple files are given, it will print a total count. If no file name is given, 'wc' reads
    from stdin until EOF.

    Flags can be arbitrarily combined into a single flag, for example, '-c -w' (count bytes and
    count words) can be reduced to '-cw'.

    If no flags are given, 'wc' defaults to '-cwl'.

OPTIONS
    -h
    --help
        Print this manual page.

    -c
    --bytes
        Count bytes.

    -w
    --words
        Count words (i.e. contiguous strings seperated by whitespaces).

    -l
    --lines
        Count lines (seperated by NL).

AUTHOR
    This program was written mainly by Alice Maz.
"#; /* @MANEND */

#[derive(Copy, Clone, Debug, Default)]
struct Counter {
    lines: u64,
    words: u64,
    bytes: u64,
}

impl Counter {
    #[inline]
    fn new<T: Read>(input: T) -> Self {
        let mut line_count = 0;
        let mut word_count = 0;
        let mut byte_count = 0;
        let mut got_space = true;
        let mut input_bytes = input.bytes();

        while let Some(Ok(byte)) = input_bytes.next() {
            if byte == b'\n' {
                line_count += 1;
            }

            if byte.is_whitespace() {
                got_space = true;
            } else if got_space {
                got_space = false;
                word_count += 1;
            }

            byte_count += 1;
        }

        Counter { lines: line_count, words: word_count, bytes: byte_count }
    }
}

impl Add for Counter {
    type Output = Counter;

    fn add(self, other: Self) -> Self {
        Counter {
            lines: self.lines + other.lines,
            words: self.words + other.words,
            bytes: self.bytes + other.bytes
        }
    }
}

impl AddAssign for Counter {
    fn add_assign(&mut self, _rhs: Self) {
        self.lines += _rhs.lines;
        self.words += _rhs.words;
        self.bytes += _rhs.bytes;
    }
}

#[derive(Copy, Clone, Default)]
struct Flags {
    count_lines: bool,
    count_words: bool,
    count_bytes: bool,
}

fn u64_num_digits(val: u64) -> usize {
    if val < 10 {
        1
    } else {
        1 + u64_num_digits(val / 10)
    }
}

impl Flags {
    fn print_counts<W: Write>(self, mut counts: Vec<(Counter, String)>, stdout: &mut W, stderr: &mut Stderr) {
        use std::cmp::max;

        let mut max_lines_digits = 0;
        let mut max_words_digits = 0;
        let mut max_bytes_digits = 0;

        for &mut (count, _) in &mut counts {
            if self.count_lines {
                max_lines_digits = max(max_lines_digits, u64_num_digits(count.lines));
            }
            if self.count_words {
                max_words_digits = max(max_words_digits, u64_num_digits(count.words));
            }
            if self.count_bytes {
                max_bytes_digits = max(max_bytes_digits, u64_num_digits(count.bytes));
            }
        }

        for &mut (count, ref mut path) in &mut counts {
            self.print_count(count, path, Counter {
                    lines: (max_lines_digits - u64_num_digits(count.lines) + 1) as u64,
                    words: (max_words_digits - u64_num_digits(count.words) + 1) as u64,
                    bytes: (max_bytes_digits - u64_num_digits(count.bytes) + 1) as u64,
                },
                stdout, stderr)
        }
    }

    fn print_count<'a, W: Write>(self, count: Counter, path: &'a str, padding: Counter, stdout: &mut W, stderr: &mut Stderr) {
        stdout.write(b"    ").try(stderr);

        if self.count_lines {
            stdout.write(count.lines.to_string().as_bytes()).try(stderr);
            for _ in 0..padding.lines {
                stdout.write(b" ").try(stderr);
            }
        }
        if self.count_words {
            stdout.write(count.words.to_string().as_bytes()).try(stderr);
            for _ in 0..padding.words {
                stdout.write(b" ").try(stderr);
            }
        }
        if self.count_bytes {
            stdout.write(count.bytes.to_string().as_bytes()).try(stderr);
            for _ in 0..padding.bytes {
                stdout.write(b" ").try(stderr);
            }
        }

        stdout.writeln(path.as_bytes()).try(&mut *stderr);
    }

    fn default_to(&mut self) {
        // Defaults to behavior of -lwc
        if !(self.count_lines || self.count_words || self.count_bytes) {
            self.count_lines = true;
            self.count_words = true;
            self.count_bytes = true;
        }
    }
}

fn main() {
    let mut opts = Flags::default();
    let mut first_file = String::new();
    let mut args = env::args().skip(1);
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    while let Some(arg) = args.next() {
        // TODO add -m, maybe add -L
        if arg.starts_with("-") {
            match arg.as_str() {
                "--lines" | "-l" => opts.count_lines = true,
                "--words" | "-w" => opts.count_words = true,
                "--bytes" | "-c" => opts.count_bytes = true,
                "--help"  | "-h" => {
                    stdout.writeln(MAN_PAGE.as_bytes()).try(&mut stderr);
                    return;
                },
                _ => {
                    stderr.write(b"error: unknown flag, ").try(&mut stderr);
                    stderr.write(arg.as_bytes()).try(&mut stderr);
                    stderr.flush().try(&mut stderr);
                    exit(1);
                },
            }
        } else { // This is a file name
            first_file = arg;
            break;
        }
    }

    opts.default_to();

    if first_file.is_empty() {
        let stdin = io::stdin();
        let stdin = stdin.lock();

        opts.print_count(Counter::new(stdin), "stdin", Counter {lines: 1, words: 1, bytes: 1}, &mut stdout, &mut stderr);
    } else {
        let mut files = Vec::new();
        let mut total_count = Counter::default();
        let more_than_one: bool = args.len() > 0;

        for path in iter::once(first_file).chain(args) {
            //TODO would be easy to use stdin for - but
            //that is probably something the shell should handle?
            //unix it's all just fds so it's whatever dunno here tho
            //(also - is specific to sh/bash fwiw).

            let file = File::open(&path).try(&mut stderr);
            let file_count = Counter::new(file);
            total_count += file_count;

            files.push((file_count, path.to_owned()));
        }

        if more_than_one {
            files.push((total_count, "total".to_owned()));
        }

        opts.print_counts(files, &mut stdout, &mut stderr);
    }
}

pub trait AsciiWhitespace { fn is_whitespace(self) -> bool; }

impl AsciiWhitespace for u8 {
    fn is_whitespace(self) -> bool {
        //FIXME this works like iswspace w/ default C locale
        //but not good enough for en_US.UTF8 among others

        self == b'\n' // newline
        || self == b'\t' // tab
        || self == b'\r' // cr
        || self == 0xc // formfeed
        || self == 0xb // vtab
        || self == b' ' // space
    }
}
<commit_msg>Apply `ArgParser` to wc.rs and fix a panicking bug when not all switches are enabled from overflow by subtracting from the value `0` in `print_counts()`<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::fs::File;
use std::io::{self, stdout, stderr, Read, Write, Stderr};
use std::ops::{Add, AddAssign};
use std::process::exit;
use coreutils::{ArgParser, Flag};
use extra::option::OptionalExt;
use extra::io::WriteExt;

static MAN_PAGE: &'static str = /* @MANSTART{wc} */ r#"
NAME
    wc - count words, bytes and lines of a file or byte stream.

SYNOPSIS
    wc [-h | --help] [-c | --bytes] [-w | --words] [-l | --lines] [FILE 1] [FILE 2]...

DESCRIPTION
    This utility will dump word count, line count, and byte count of a file or byte stream. If
    multiple files are given, it will print a total count. If no file name is given, 'wc' reads
    from stdin until EOF.

    Flags can be arbitrarily combined into a single flag, for example, '-c -w' (count bytes and
    count words) can be reduced to '-cw'.

    If no flags are given, 'wc' defaults to '-cwl'.

OPTIONS
    -h
    --help
        Print this manual page.

    -c
    --bytes
        Count bytes.

    -w
    --words
        Count words (i.e. contiguous strings seperated by whitespaces).

    -l
    --lines
        Count lines (seperated by NL).

AUTHOR
    This program was written mainly by Alice Maz.
"#; /* @MANEND */

#[derive(Copy, Clone, Debug, Default)]
struct Counter {
    lines: u64,
    words: u64,
    bytes: u64,
}

impl Counter {
    #[inline]
    fn new<T: Read>(input: T) -> Self {
        let mut line_count = 0;
        let mut word_count = 0;
        let mut byte_count = 0;
        let mut got_space = true;
        let mut input_bytes = input.bytes();

        while let Some(Ok(byte)) = input_bytes.next() {
            if byte == b'\n' {
                line_count += 1;
            }

            if byte.is_whitespace() {
                got_space = true;
            } else if got_space {
                got_space = false;
                word_count += 1;
            }

            byte_count += 1;
        }

        Counter { lines: line_count, words: word_count, bytes: byte_count }
    }
}

impl Add for Counter {
    type Output = Counter;

    fn add(self, other: Self) -> Self {
        Counter {
            lines: self.lines + other.lines,
            words: self.words + other.words,
            bytes: self.bytes + other.bytes
        }
    }
}

impl AddAssign for Counter {
    fn add_assign(&mut self, _rhs: Self) {
        self.lines += _rhs.lines;
        self.words += _rhs.words;
        self.bytes += _rhs.bytes;
    }
}

fn u64_num_digits(val: u64) -> usize {
    if val < 10 {
        1
    } else {
        1 + u64_num_digits(val / 10)
    }
}

fn print_counts<W: Write>(parser: &ArgParser, mut counts: Vec<(Counter, String)>, stdout: &mut W, stderr: &mut Stderr) {
    use std::cmp::max;

    let mut max_lines_digits = 0;
    let mut max_words_digits = 0;
    let mut max_bytes_digits = 0;

    for &mut (count, _) in &mut counts {
        if parser.enabled_flag(Flag::Long("lines")) {
            max_lines_digits = max(max_lines_digits, u64_num_digits(count.lines));
        }
        if parser.enabled_flag(Flag::Long("words")) {
            max_words_digits = max(max_words_digits, u64_num_digits(count.words));
        }
        if parser.enabled_flag(Flag::Long("bytes")) {
            max_bytes_digits = max(max_bytes_digits, u64_num_digits(count.bytes));
        }
    }

    for &mut (count, ref mut path) in &mut counts {
        print_count(&parser, count, path, Counter {
            lines:
                if parser.enabled_flag(Flag::Long("lines")) {
                    (max_lines_digits - u64_num_digits(count.lines) + 1) as u64
                } else {
                    0
                },
            words:
                if parser.enabled_flag(Flag::Long("words")) {
                    (max_words_digits - u64_num_digits(count.words) + 1) as u64
                } else {
                    0
                },
            bytes:
                if parser.enabled_flag(Flag::Long("bytes")) {
                    (max_bytes_digits - u64_num_digits(count.bytes) + 1) as u64
                } else {
                    0
                },
        },
        stdout, stderr)
    }
}

fn print_count<'a, W: Write>(parser: &ArgParser, count: Counter, path: &'a str, padding: Counter, stdout: &mut W, stderr: &mut Stderr) {
    stdout.write(b"    ").try(stderr);

    if parser.enabled_flag(Flag::Long("lines")) {
        stdout.write(count.lines.to_string().as_bytes()).try(stderr);
        for _ in 0..padding.lines {
            stdout.write(b" ").try(stderr);
        }
    }
    if parser.enabled_flag(Flag::Long("words")) {
        stdout.write(count.words.to_string().as_bytes()).try(stderr);
        for _ in 0..padding.words {
            stdout.write(b" ").try(stderr);
        }
    }
    if parser.enabled_flag(Flag::Long("bytes")) {
        stdout.write(count.bytes.to_string().as_bytes()).try(stderr);
        for _ in 0..padding.bytes {
            stdout.write(b" ").try(stderr);
        }
    }

    stdout.writeln(path.as_bytes()).try(&mut *stderr);
}

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(4)
        .add_flag("l", "lines")
        .add_flag("w", "words")
        .add_flag("c", "bytes")
        .add_flag("h", "help");
    parser.initialize(env::args());

    if parser.enabled_flag(Flag::Long("help")) {
        stdout.writeln(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    if !(parser.enabled_flag(Flag::Long("lines")) ||
         parser.enabled_flag(Flag::Long("words")) ||
         parser.enabled_flag(Flag::Long("bytes"))) {
        parser.enable_all();
    }

    if parser.args.is_empty() {
        let stdin = io::stdin();
        let stdin = stdin.lock();

        print_count(&parser,
            Counter::new(stdin),
            "stdin",
            Counter {lines: 1, words: 1, bytes: 1},
            &mut stdout,
            &mut stderr);
    } else {
        let mut files = Vec::new();
        let mut total_count = Counter::default();

        for path in parser.args.iter() {
            //TODO would be easy to use stdin for - but
            //that is probably something the shell should handle?
            //unix it's all just fds so it's whatever dunno here tho
            //(also - is specific to sh/bash fwiw).

            let file = File::open(path).try(&mut stderr);
            let file_count = Counter::new(file);
            total_count += file_count;

            files.push((file_count, path.to_owned()));
        }

        if parser.args.len() > 1 {
            files.push((total_count, "total".to_owned()));
        }

        print_counts(&parser, files, &mut stdout, &mut stderr);
    }
}

pub trait AsciiWhitespace { fn is_whitespace(self) -> bool; }

impl AsciiWhitespace for u8 {
    fn is_whitespace(self) -> bool {
        //FIXME this works like iswspace w/ default C locale
        //but not good enough for en_US.UTF8 among others

        self == b'\n' // newline
        || self == b'\t' // tab
        || self == b'\r' // cr
        || self == 0xc // formfeed
        || self == 0xb // vtab
        || self == b' ' // space
    }
}
<|endoftext|>


<commit_before>use slack_api as slack;
use tokio_tungstenite as tungstenite;

use tokio::sync::mpsc;

use chrono::prelude::{Utc, DateTime, NaiveTime};
use chrono_tz::Tz;
use chrono_tz::OffsetComponents;
use chrono::NaiveDateTime;

use crate::core::cache;

use crate::core::event::MsgId;
use crate::core::event::send_simple_message;

use nom::{
  IResult,
  bytes::complete::{
      tag,
      tag_no_case,
  },
  character::complete::{
      multispace0,
      digit1,
  },
  combinator::{
      opt,
      map,
      recognize,
  },
  branch::alt,
  sequence::{
      preceded,
      delimited,
      separated_pair,
  },
  error::{
      Error,
      ErrorKind,
  },
};

const TIME_FORMAT: &str = "%l:%M%P";

pub async fn timezone<R>(
    msg_id: MsgId,
    tx: &mut mpsc::Sender<tungstenite::tungstenite::Message>,
    cache: &cache::Cache<R>,
    channel_id: String,
    thread_ts: Option<String>,
    user_id: String,
    input: Vec<&str>,
)
where
    R: slack::requests::SlackWebRequestSender + std::clone::Clone
{
    // TODO: should check if its within reasonable hours and if its borderline
    // color it yellow, or bad, red, otherwise green.
    if input.is_empty() {
        // !tz --> utc current time + 3 tz (pacific, eastern, uk)
        let utc_time: DateTime<Utc> = Utc::now();
        let pacific = utc_time.with_timezone(&chrono_tz::America::Los_Angeles);
        let eastern = utc_time.with_timezone(&chrono_tz::America::Toronto);
        let london  = utc_time.with_timezone(&chrono_tz::Europe::London);

        let _ = send_simple_message(
            msg_id,
            tx,
            channel_id,
            thread_ts,
            format!(
                "<@{}>: Pacific: {}, Eastern: {}, UK: {}",
                user_id,
                pacific.format(TIME_FORMAT),
                eastern.format(TIME_FORMAT),
                london.format(TIME_FORMAT),
            ),
        ).await;

    } else {
        let input = input.join(" ");
        match parse(&input) {
            Err(e) => {
                eprintln!("ERROR [TZ]: {:?}", e);

                let message = format!(
                    "<@{}>: Usage: `!tz TIME [TZ]`
                    24hr: `!tz 05:00 [TZ]` or `!tz 0500 [TZ]`
                    12hr: `!tz 2:00pm [TZ]` or `!tz 5pm [TZ]`
                    [TZ]: (optional) `PST/PDT`, `EST/EDT`, `BST/GMT`
                    [TZ]: (note) if not specified, will use your slack Timezone",
                    user_id,
                );
                let _ = send_simple_message(
                    msg_id,
                    tx,
                    channel_id,
                    thread_ts,
                    message,
                ).await;
            },
            Ok((_, TzReq { time: nt, zone: None })) => {
                let user_tz = cache.get_user_tz(&user_id).await.unwrap();
                let tz: Tz = user_tz.tz.parse().unwrap();

                // Validate the offset
                validate_offset(&tz, user_tz.offset);

                // Convert time
                let given_datetime_tz = convert_naivetime(nt, tz);

                // Supported locals
                let out_tz = convert_to_locales(given_datetime_tz);

                let _ = send_simple_message(
                    msg_id,
                    tx,
                    channel_id,
                    thread_ts,
                    format!(
                        "<@{}>: Pacific: {}, Eastern: {}, UK: {}",
                        user_id,
                        out_tz.pacific.format(TIME_FORMAT),
                        out_tz.eastern.format(TIME_FORMAT),
                        out_tz.london.format(TIME_FORMAT),
                    ),
                ).await;
            },
            Ok((_, TzReq { time: nt, zone: Some(tz_abbv) })) => {
                println!("lol");
            },
        }
    }
}

fn validate_offset(tz: &Tz, offset: i64) {
    // Validate and compare the offset
    let utc_time: DateTime<Utc> = Utc::now();
    let tz_time = utc_time.with_timezone(tz);
    let tz_offset = tz_time.offset().base_utc_offset() + tz_time.offset().dst_offset();

    if tz_offset.num_seconds() != offset {
        eprintln!(
            "ERROR [TZ]: Slack offset {}, parsed offset {} does not match!",
            offset,
            tz_offset.num_seconds(),
        );
    }
}

fn convert_naivetime(nt: NaiveTime, tz: Tz) -> DateTime<Tz> {
    // Convert the given naive time to the given Tz
    let utc_time: DateTime<Utc> = Utc::now();
    let tz_time = utc_time.with_timezone(&tz);
    let naive_datetime = tz_time.naive_local();
    let naive_date = naive_datetime.date();
    let given_datetime = NaiveDateTime::new(naive_date, nt);
    let given_datetime_tz = given_datetime.and_local_timezone(tz).single().unwrap();

    given_datetime_tz
}

struct OutTz {
    pacific: DateTime<Tz>,
    eastern: DateTime<Tz>,
    london: DateTime<Tz>,
}

fn convert_to_locales(dt: DateTime<Tz>) -> OutTz {
    OutTz {
        pacific: dt.with_timezone(&chrono_tz::America::Los_Angeles),
        eastern: dt.with_timezone(&chrono_tz::America::Toronto),
        london:  dt.with_timezone(&chrono_tz::Europe::London),
    }
}

#[derive(Debug, PartialEq)]
struct TzReq {
    time: NaiveTime,
    zone: Option<Tz>
}

fn parse(input: &str) -> IResult<&str, TzReq> {
    let (input, time) = alt((
        twelve,
        twenty_four,
    ))(input)?;
    let (input, tz) = preceded(multispace0, opt(tz_abbv))(input)?;

    Ok((input, TzReq {
        time: time,
        zone: tz,
    }))
}

// Note: Nonstandard timezones, for user convience only:
// PST, PDT (standard/Daylight(summer)) - pacific
// EST, EDT (standard/Daylight(summer)) - eastern
// BST, GMT (summer time/gmt) - london (GMT != UTC)
fn tz_abbv(input: &str) -> IResult<&str, Tz> {
    alt((
        map(tag_no_case("PST"), |_| chrono_tz::Etc::GMTMinus8),
        map(tag_no_case("PDT"), |_| chrono_tz::Etc::GMTMinus7),
        map(tag_no_case("EST"), |_| chrono_tz::Etc::GMTMinus5),
        map(tag_no_case("EDT"), |_| chrono_tz::Etc::GMTMinus4),
        map(tag_no_case("BST"), |_| chrono_tz::Etc::GMTPlus1),
        map(tag_no_case("GMT"), |_| chrono_tz::Etc::GMTPlus0),
    ))(input)
}

fn meridiem(input: &str) -> IResult<&str, &str> {
    alt((
        map(tag_no_case("am"), |_| "AM"),
        map(tag_no_case("pm"), |_| "PM"),
    ))(input)
}

fn time(input: &str) -> IResult<&str, &str> {
    alt((
        recognize(delimited(digit1, tag(":"), digit1)),
        digit1,
    ))(input)
}

fn twelve(input: &str) -> IResult<&str, NaiveTime> {
    let (input, (time, meri)) = separated_pair(
        time,
        multispace0,
        meridiem
    )(input)?;

    let time_str = if time.contains(":") {
        format!("{}{}", time, meri)
    } else {
        format!("{}:00{}", time, meri)
    };

    match NaiveTime::parse_from_str(&time_str, "%-I:%M%p") {
        Ok(nt) => Ok((input, nt)),
        Err(_) => Err(nom::Err::Error(Error::new(input, ErrorKind::Fail))),
    }
}

fn twenty_four(input: &str) -> IResult<&str, NaiveTime> {
    let (input, time) = map(time, |t| t.replace(":", ""))(input)?;

    match NaiveTime::parse_from_str(&time, "%H%M") {
        Ok(nt) => Ok((input, nt)),
        Err(_) => Err(nom::Err::Error(Error::new(input, ErrorKind::Fail))),
    }
}

#[cfg(test)]
mod test_parser {
    use super::*;

    #[test]
    fn test_meridiem() {
        assert_eq!(
            meridiem("AM"),
            Ok(("", "AM"))
        );

        assert_eq!(
            meridiem("pm"),
            Ok(("", "PM"))
        );
    }

    #[test]
    fn test_time() {
        assert_eq!(
            time("0200"),
            Ok(("", "0200"))
        );
        assert_eq!(
            time("1700"),
            Ok(("", "1700"))
        );
        assert_eq!(
            time("2"),
            Ok(("", "2"))
        );
        assert_eq!(
            time("12"),
            Ok(("", "12"))
        );
        assert_eq!(
            time("3:03"),
            Ok(("", "3:03"))
        );
        assert_eq!(
            time("12:11"),
            Ok(("", "12:11"))
        );
    }

    #[test]
    fn test_twelve() {
        assert_eq!(
            twelve("1pm"),
            Ok(("", NaiveTime::from_hms(13, 0, 0)))
        );
        assert_eq!(
            twelve("5 AM"),
            Ok(("", NaiveTime::from_hms(5, 0, 0)))
        );
        assert_eq!(
            twelve("5:10pm"),
            Ok(("", NaiveTime::from_hms(17, 10, 0)))
        );
        assert_eq!(
            twelve("11:20 am"),
            Ok(("", NaiveTime::from_hms(11, 20, 0)))
        );
    }

    #[test]
    fn test_twenty_four() {
        assert_eq!(
            twenty_four("0220"),
            Ok(("", NaiveTime::from_hms(2, 20, 0)))
        );
        assert_eq!(
            twenty_four("17:10"),
            Ok(("", NaiveTime::from_hms(17, 10, 0)))
        );
    }

    #[test]
    fn test_parse() {
        assert_eq!(
            parse("2pm"),
            Ok(("", TzReq {
                time: NaiveTime::from_hms(14, 00, 0),
                zone: None,
            }))
        );
        assert_eq!(
            parse("5:30 pm pst"),
            Ok(("", TzReq {
                time: NaiveTime::from_hms(17, 30, 0),
                zone: Some(chrono_tz::Etc::GMTMinus8),
            }))
        );
        assert_eq!(
            parse("0801 GMT"),
            Ok(("", TzReq {
                time: NaiveTime::from_hms(8, 1, 0),
                zone: Some(chrono_tz::Etc::GMTPlus0),
            }))
        );
    }
}
<commit_msg>Error validation of the timezone feature<commit_after>use slack_api as slack;
use tokio_tungstenite as tungstenite;

use tokio::sync::mpsc;

use chrono::prelude::{Utc, DateTime, NaiveTime};
use chrono_tz::Tz;
use chrono_tz::OffsetComponents;
use chrono::NaiveDateTime;

use crate::core::cache;

use crate::core::event::MsgId;
use crate::core::event::send_simple_message;

use nom::{
  IResult,
  bytes::complete::{
      tag,
      tag_no_case,
  },
  character::complete::{
      multispace0,
      digit1,
  },
  combinator::{
      opt,
      map,
      recognize,
      eof,
  },
  branch::alt,
  sequence::{
      preceded,
      delimited,
      separated_pair,
  },
  error::{
      Error,
      ErrorKind,
  },
};

const TIME_FORMAT: &str = "%l:%M%P";

pub async fn timezone<R>(
    msg_id: MsgId,
    tx: &mut mpsc::Sender<tungstenite::tungstenite::Message>,
    cache: &cache::Cache<R>,
    channel_id: String,
    thread_ts: Option<String>,
    user_id: String,
    input: Vec<&str>,
)
where
    R: slack::requests::SlackWebRequestSender + std::clone::Clone
{
    // TODO: should check if its within reasonable hours and if its borderline
    // color it yellow, or bad, red, otherwise green.
    if input.is_empty() {
        // !tz --> utc current time + 3 tz (pacific, eastern, uk)
        let utc_time: DateTime<Utc> = Utc::now();
        let pacific = utc_time.with_timezone(&chrono_tz::America::Los_Angeles);
        let eastern = utc_time.with_timezone(&chrono_tz::America::Toronto);
        let london  = utc_time.with_timezone(&chrono_tz::Europe::London);

        let _ = send_simple_message(
            msg_id,
            tx,
            channel_id,
            thread_ts,
            format!(
                "<@{}>: Pacific: {}, Eastern: {}, UK: {}",
                user_id,
                pacific.format(TIME_FORMAT),
                eastern.format(TIME_FORMAT),
                london.format(TIME_FORMAT),
            ),
        ).await;

    } else {
        let input = input.join(" ");
        match parse(&input) {
            Err(e) => {
                eprintln!("ERROR [TZ]: {:?}", e);

                let message = format!(
                    "<@{}>: Usage: `!tz TIME [TZ]`
                    24hr: `!tz 05:00 [TZ]` or `!tz 0500 [TZ]`
                    12hr: `!tz 2:00pm [TZ]` or `!tz 5pm [TZ]`
                    [TZ]: (optional) `PST/PDT`, `EST/EDT`, `BST/GMT`
                    [TZ]: (note) if not specified, will use your slack Timezone",
                    user_id,
                );
                let _ = send_simple_message(
                    msg_id,
                    tx,
                    channel_id,
                    thread_ts,
                    message,
                ).await;
            },
            Ok((_, TzReq { time: nt, zone: None })) => {
                match cache.get_user_tz(&user_id).await {
                    None => {
                        let _ = send_simple_message(
                            msg_id,
                            tx,
                            channel_id,
                            thread_ts,
                            format!("<@{}>: Internal error, unable to get your slack timezone", user_id),
                        ).await;
                    },
                    Some(user_tz) => {
                        match user_tz.tz.parse() {
                            Err(_) => {
                                let _ = send_simple_message(
                                    msg_id,
                                    tx,
                                    channel_id,
                                    thread_ts,
                                    format!("<@{}>: Internal error, unable to parse your slack timezone", user_id),
                                ).await;
                            },
                            Ok(tz) => {
                                // Validate the offset
                                validate_offset(&tz, user_tz.offset);

                                // Convert time
                                match convert_naive_time(nt, tz) {
                                    None => {
                                        let _ = send_simple_message(
                                            msg_id,
                                            tx,
                                            channel_id,
                                            thread_ts,
                                            format!("<@{}>: Internal error, timezone happened!", user_id),
                                        ).await;
                                    },
                                    Some(given_datetime_tz) => {
                                        // Supported locals
                                        let out_tz = convert_to_locales(given_datetime_tz);

                                        let _ = send_simple_message(
                                            msg_id,
                                            tx,
                                            channel_id,
                                            thread_ts,
                                            format!(
                                                "<@{}>: Pacific: {}, Eastern: {}, UK: {}",
                                                user_id,
                                                out_tz.pacific.format(TIME_FORMAT),
                                                out_tz.eastern.format(TIME_FORMAT),
                                                out_tz.london.format(TIME_FORMAT),
                                            ),
                                        ).await;
                                    },
                                }
                            },
                        }
                    },
                }
            },
            Ok((_, TzReq { time: nt, zone: Some(tz_abbv) })) => {
                match convert_naive_time(nt, tz_abbv) {
                    None => {
                        let _ = send_simple_message(
                            msg_id,
                            tx,
                            channel_id,
                            thread_ts,
                            format!("<@{}>: Internal error, timezone happened!", user_id),
                        ).await;
                    },
                    Some(given_datetime_tz) => {
                        // Supported locals
                        let out_tz = convert_to_locales(given_datetime_tz);

                        let _ = send_simple_message(
                            msg_id,
                            tx,
                            channel_id,
                            thread_ts,
                            format!(
                                "<@{}>: Pacific: {}, Eastern: {}, UK: {}",
                                user_id,
                                out_tz.pacific.format(TIME_FORMAT),
                                out_tz.eastern.format(TIME_FORMAT),
                                out_tz.london.format(TIME_FORMAT),
                            ),
                        ).await;
                    },
                }
            },
        }
    }
}

fn validate_offset(tz: &Tz, offset: i64) {
    // Validate and compare the offset
    let utc_time: DateTime<Utc> = Utc::now();
    let tz_time = utc_time.with_timezone(tz);
    let tz_offset = tz_time.offset().base_utc_offset() + tz_time.offset().dst_offset();

    if tz_offset.num_seconds() != offset {
        eprintln!(
            "ERROR [TZ]: Slack offset {}, parsed offset {} does not match!",
            offset,
            tz_offset.num_seconds(),
        );
    }
}

fn convert_naive_time(nt: NaiveTime, tz: Tz) -> Option<DateTime<Tz>> {
    // Convert the given naive time to the given Tz
    let utc_time: DateTime<Utc> = Utc::now();
    let tz_time = utc_time.with_timezone(&tz);
    let naive_datetime = tz_time.naive_local();
    let naive_date = naive_datetime.date();
    let given_datetime = NaiveDateTime::new(naive_date, nt);

    given_datetime.and_local_timezone(tz).earliest()
}

struct OutTz {
    pacific: DateTime<Tz>,
    eastern: DateTime<Tz>,
    london: DateTime<Tz>,
}

fn convert_to_locales(dt: DateTime<Tz>) -> OutTz {
    OutTz {
        pacific: dt.with_timezone(&chrono_tz::America::Los_Angeles),
        eastern: dt.with_timezone(&chrono_tz::America::Toronto),
        london:  dt.with_timezone(&chrono_tz::Europe::London),
    }
}

#[derive(Debug, PartialEq)]
struct TzReq {
    time: NaiveTime,
    zone: Option<Tz>
}

fn parse(input: &str) -> IResult<&str, TzReq> {
    let (input, time) = alt((
        twelve,
        twenty_four,
    ))(input)?;
    let (input, tz) = preceded(multispace0, opt(tz_abbv))(input)?;
    let (input, _) = eof(input)?;

    Ok((input, TzReq {
        time: time,
        zone: tz,
    }))
}

// Note: Nonstandard timezones, for user convience only:
// PST, PDT (standard/Daylight(summer)) - pacific
// EST, EDT (standard/Daylight(summer)) - eastern
// BST, GMT (summer time/gmt) - london (GMT != UTC)
fn tz_abbv(input: &str) -> IResult<&str, Tz> {
    alt((
        map(tag_no_case("PST"), |_| chrono_tz::Etc::GMTMinus8),
        map(tag_no_case("PDT"), |_| chrono_tz::Etc::GMTMinus7),
        map(tag_no_case("EST"), |_| chrono_tz::Etc::GMTMinus5),
        map(tag_no_case("EDT"), |_| chrono_tz::Etc::GMTMinus4),
        map(tag_no_case("BST"), |_| chrono_tz::Etc::GMTPlus1),
        map(tag_no_case("GMT"), |_| chrono_tz::Etc::GMTPlus0),
    ))(input)
}

fn meridiem(input: &str) -> IResult<&str, &str> {
    alt((
        map(tag_no_case("am"), |_| "AM"),
        map(tag_no_case("pm"), |_| "PM"),
    ))(input)
}

fn time(input: &str) -> IResult<&str, &str> {
    alt((
        recognize(delimited(digit1, tag(":"), digit1)),
        digit1,
    ))(input)
}

fn twelve(input: &str) -> IResult<&str, NaiveTime> {
    let (input, (time, meri)) = separated_pair(
        time,
        multispace0,
        meridiem
    )(input)?;

    let time_str = if time.contains(":") {
        format!("{}{}", time, meri)
    } else {
        format!("{}:00{}", time, meri)
    };

    match NaiveTime::parse_from_str(&time_str, "%-I:%M%p") {
        Ok(nt) => Ok((input, nt)),
        Err(_) => Err(nom::Err::Error(Error::new(input, ErrorKind::Fail))),
    }
}

fn twenty_four(input: &str) -> IResult<&str, NaiveTime> {
    let (input, time) = map(time, |t| t.replace(":", ""))(input)?;

    match NaiveTime::parse_from_str(&time, "%H%M") {
        Ok(nt) => Ok((input, nt)),
        Err(_) => Err(nom::Err::Error(Error::new(input, ErrorKind::Fail))),
    }
}

#[cfg(test)]
mod test_parser {
    use super::*;

    #[test]
    fn test_meridiem() {
        assert_eq!(
            meridiem("AM"),
            Ok(("", "AM"))
        );

        assert_eq!(
            meridiem("pm"),
            Ok(("", "PM"))
        );
    }

    #[test]
    fn test_time() {
        assert_eq!(
            time("0200"),
            Ok(("", "0200"))
        );
        assert_eq!(
            time("1700"),
            Ok(("", "1700"))
        );
        assert_eq!(
            time("2"),
            Ok(("", "2"))
        );
        assert_eq!(
            time("12"),
            Ok(("", "12"))
        );
        assert_eq!(
            time("3:03"),
            Ok(("", "3:03"))
        );
        assert_eq!(
            time("12:11"),
            Ok(("", "12:11"))
        );
    }

    #[test]
    fn test_twelve() {
        assert_eq!(
            twelve("1pm"),
            Ok(("", NaiveTime::from_hms(13, 0, 0)))
        );
        assert_eq!(
            twelve("5 AM"),
            Ok(("", NaiveTime::from_hms(5, 0, 0)))
        );
        assert_eq!(
            twelve("5:10pm"),
            Ok(("", NaiveTime::from_hms(17, 10, 0)))
        );
        assert_eq!(
            twelve("11:20 am"),
            Ok(("", NaiveTime::from_hms(11, 20, 0)))
        );
    }

    #[test]
    fn test_twenty_four() {
        assert_eq!(
            twenty_four("0220"),
            Ok(("", NaiveTime::from_hms(2, 20, 0)))
        );
        assert_eq!(
            twenty_four("17:10"),
            Ok(("", NaiveTime::from_hms(17, 10, 0)))
        );
    }

    #[test]
    fn test_parse() {
        assert_eq!(
            parse("2pm"),
            Ok(("", TzReq {
                time: NaiveTime::from_hms(14, 00, 0),
                zone: None,
            }))
        );
        assert_eq!(
            parse("5:30 pm pst"),
            Ok(("", TzReq {
                time: NaiveTime::from_hms(17, 30, 0),
                zone: Some(chrono_tz::Etc::GMTMinus8),
            }))
        );
        assert_eq!(
            parse("0801 GMT"),
            Ok(("", TzReq {
                time: NaiveTime::from_hms(8, 1, 0),
                zone: Some(chrono_tz::Etc::GMTPlus0),
            }))
        );
    }
}
<|endoftext|>


<commit_before>//! A camera object for ggez.
//! Currently ggez has no actual global camera state to use,
//! so this really just does the coordinate transforms for you.

use ggez;
use na;
use super::{Point2, Vector2};
pub struct Camera {
    screen_width: u32,
    screen_height: u32,
    view_width: f64,
    view_height: f64,
    view_center: Vector2,
}

impl Camera {
    pub fn new(screen_width: u32, screen_height: u32, view_width: f64, view_height: f64) -> Self {
        Camera {
            screen_width: screen_width,
            screen_height: screen_height,
            view_width: view_width,
            view_height: view_height,
            view_center: na::zero(),
        }
    }

    pub fn move_by(&mut self, by: Vector2) {
        self.view_center += by;
    }

    pub fn move_to(&mut self, to: Vector2) {
        self.view_center = to;
    }

    pub fn world_to_screen_coords(&self, from: Vector2) -> (u32, u32) {
        let width = self.screen_width as f64;
        let height = self.screen_height as f64;
        let x = from.x + width / 2.0;
        let y = height - (from.y + height / 2.0);
        (x as u32, y as u32)
    }

    pub fn screen_to_world_coords(&self, from: (u32, u32)) -> Vector2 {
        let (sx, sy) = from;
        na::zero()
    }
}
<commit_msg>Added trait to draw things easily with cameras.<commit_after>//! A camera object for ggez.
//! Currently ggez has no actual global camera state to use,
//! so this really just does the coordinate transforms for you.

use ggez;
use ggez::GameResult;
use ggez::graphics;
use ggez::graphics::Drawable;
use na;
use super::{Point2, Vector2};
pub struct Camera {
    screen_width: u32,
    screen_height: u32,
    view_width: f64,
    view_height: f64,
    view_center: Vector2,
}

impl Camera {
    pub fn new(screen_width: u32, screen_height: u32, view_width: f64, view_height: f64) -> Self {
        Camera {
            screen_width: screen_width,
            screen_height: screen_height,
            view_width: view_width,
            view_height: view_height,
            view_center: na::zero(),
        }
    }

    pub fn move_by(&mut self, by: Vector2) {
        self.view_center += by;
    }

    pub fn move_to(&mut self, to: Vector2) {
        self.view_center = to;
    }

    pub fn world_to_screen_coords(&self, from: Vector2) -> (i32, i32) {
        let width = self.screen_width as f64;
        let height = self.screen_height as f64;
        let x = from.x + width / 2.0;
        let y = height - (from.y + height / 2.0);
        (x as i32, y as i32)
    }

    pub fn screen_to_world_coords(&self, from: (i32, i32)) -> Vector2 {
        let (sx, sy) = from;
        na::zero()
    }

    fn calculate_dest_rect(&self, location: Vector2, dst_size: (u32, u32)) -> graphics::Rect {
        let (sx, sy) = self.world_to_screen_coords(location);
        let (sw, sh) = dst_size;
        graphics::Rect::new(sx, sy, sw, sh)
    }
}

trait CameraDraw
    where Self: graphics::Drawable
{
    fn draw_ex_camera(&mut self,
                      camera: &Camera,
                      location: Vector2,
                      context: &mut ggez::Context,
                      src: Option<graphics::Rect>,
                      dst_size: (u32, u32),
                      angle: f64,
                      center: Option<graphics::Point>,
                      flip_horizontal: bool,
                      flip_vertical: bool)
                      -> GameResult<()> {
        let dest_rect = camera.calculate_dest_rect(location, dst_size);
        self.draw_ex(context,
                     src,
                     Some(dest_rect),
                     angle,
                     center,
                     flip_horizontal,
                     flip_vertical)
    }

    fn draw_camera(&mut self,
                   camera: &Camera,
                   location: Vector2,
                   context: &mut ggez::Context,
                   src: Option<graphics::Rect>,
                   dst_size: (u32, u32))
                   -> GameResult<()> {

        let dest_rect = camera.calculate_dest_rect(location, dst_size);
        self.draw(context, src, Some(dest_rect))
    }
}
<|endoftext|>