<commit_before>
use gfx;
use gfx::DeviceHelper;
use graphics::BackEnd;
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
varying vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
out vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
varying vec4 v_Color;
void main() {
    gl_FragColor = v_Color;
}
"
    GLSL_150: b"
#version 150 core
in vec4 v_Color;
out vec4 o_Color;
void main() {
    o_Color = v_Color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
attribute vec2 uv;
uniform sampler2D s_texture;
varying vec4 v_Color;
varying vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
in vec2 uv;
uniform sampler2D s_texture;
out vec4 v_Color;
out vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
varying vec2 v_UV;
varying vec4 v_Color;
void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * v_Color;
}
"
    GLSL_150: b"
#version 150 core
out vec4 o_Color;
uniform sampler2D s_texture;
in vec2 v_UV;
in vec4 v_Color;
void main()
{
    o_Color = texture(s_texture, v_UV) * v_Color;
}
"
};

static POS_COMPONENTS: uint = 2;
static COLOR_COMPONENTS: uint = 4;
static UV_COMPONENTS: uint = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { v: [f32, ..2] }

#[vertex_format]
struct ColorFormat { v: [f32, ..4] }

#[vertex_format]
struct TexCoordsFormat { v: [f32, ..2] }

#[allow(unused_imports)]
#[shader_param(BatchUV, OwnedBatchUV)]
struct ParamsUV {
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct Gfx2d {
    buffer_pos: gfx::BufferHandle<f32>,
    buffer_color: gfx::BufferHandle<f32>,
    buffer_uv: gfx::BufferHandle<f32>,
    batch: gfx::batch::OwnedBatch<(), ()>,
    batch_uv: OwnedBatchUV,
}

impl Gfx2d {
    /// Creates a new Gfx2d object.
    pub fn new<D: gfx::Device<C>,
               C: gfx::CommandBuffer>(device: &mut D) -> Gfx2d {
        let program = device.link_program(
                VERTEX_SHADER.clone(),
                FRAGMENT_SHADER.clone()
            ).unwrap();
        let program_uv = device.link_program(
                VERTEX_SHADER_UV.clone(),
                FRAGMENT_SHADER_UV.clone()
            ).unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_color = device.create_buffer(
            COLOR_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.push_all_move(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ));
        mesh.attributes.push_all_move(gfx::VertexFormat::generate(
            None::<ColorFormat>,
            buffer_color.raw()
        ));

        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.push_all_move(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ));

        let batch = gfx::batch::OwnedBatch::new(mesh, program, ()).unwrap();

        let sampler = device.create_sampler(
                gfx::tex::SamplerInfo::new(gfx::tex::Trilinear,
                                           gfx::tex::Clamp)
            );

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
                [0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            s_texture: (texture, Some(sampler))
        };

        let batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv).unwrap();

        Gfx2d {
            buffer_pos: buffer_pos,
            buffer_color: buffer_color,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }
}

/// Used for rendering 2D graphics.
pub struct RenderContext<'a, C: 'a + gfx::CommandBuffer> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    gfx2d: &'a mut Gfx2d,
}

impl<'a, C: gfx::CommandBuffer> RenderContext<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               gfx2d: &'a mut Gfx2d) -> RenderContext<'a, C> {
        RenderContext {
            renderer: renderer,
            frame: frame,
            gfx2d: gfx2d,
        }
    }
}

impl<'a, C: gfx::CommandBuffer> BackEnd<Texture>
for RenderContext<'a, C> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        let &RenderContext {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: [r, g, b, a],
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::Color,
                frame
            );
    }

    fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::{Normal, Inverse, Factor};

        self.gfx2d.batch.state.blend = Some(gfx::state::Blend {
                value: [1.0, 1.0, 1.0, 1.0],
                color: gfx::state::BlendChannel {
                        equation: gfx::state::FuncAdd,
                        source: Factor(Normal, gfx::state::SourceAlpha),
                        destination: Factor(Inverse, gfx::state::SourceAlpha)
                    },
                alpha: Default::default()
            })
    }

    fn disable_alpha_blend(&mut self) {
        self.gfx2d.batch.state.blend = None;
    }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let &RenderContext {
            ref mut renderer,
            ref frame,
            gfx2d: &Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut batch,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch.slice = gfx::VertexSlice(gfx::TriangleList, 0, n as u32);
        renderer.draw(&*batch, *frame);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let ParamsUV {
            s_texture: (ref mut s_texture, _)
        } = self.gfx2d.batch_uv.param;
        *s_texture = texture.handle;
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        let &RenderContext {
            ref mut renderer,
            ref frame,
            gfx2d: &Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        assert_eq!(
            vertices.len() * UV_COMPONENTS,
            texture_coords.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);
        renderer.update_buffer_vec(*buffer_uv, texture_coords, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch_uv.slice = gfx::VertexSlice(gfx::TriangleList, 0, n as u32);
        renderer.draw(&*batch_uv, *frame);
    }
}
<commit_msg>Fixed vertex format parameter names<commit_after>
use gfx;
use gfx::DeviceHelper;
use graphics::BackEnd;
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
varying vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
out vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
varying vec4 v_Color;
void main() {
    gl_FragColor = v_Color;
}
"
    GLSL_150: b"
#version 150 core
in vec4 v_Color;
out vec4 o_Color;
void main() {
    o_Color = v_Color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
attribute vec2 uv;
uniform sampler2D s_texture;
varying vec4 v_Color;
varying vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
in vec2 uv;
uniform sampler2D s_texture;
out vec4 v_Color;
out vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
varying vec2 v_UV;
varying vec4 v_Color;
void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * v_Color;
}
"
    GLSL_150: b"
#version 150 core
out vec4 o_Color;
uniform sampler2D s_texture;
in vec2 v_UV;
in vec4 v_Color;
void main()
{
    o_Color = texture(s_texture, v_UV) * v_Color;
}
"
};

static POS_COMPONENTS: uint = 2;
static COLOR_COMPONENTS: uint = 4;
static UV_COMPONENTS: uint = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { pos: [f32, ..2] }

#[vertex_format]
struct ColorFormat { color: [f32, ..4] }

#[vertex_format]
struct TexCoordsFormat { uv: [f32, ..2] }

#[allow(unused_imports)]
#[shader_param(BatchUV, OwnedBatchUV)]
struct ParamsUV {
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct Gfx2d {
    buffer_pos: gfx::BufferHandle<f32>,
    buffer_color: gfx::BufferHandle<f32>,
    buffer_uv: gfx::BufferHandle<f32>,
    batch: gfx::batch::OwnedBatch<(), ()>,
    batch_uv: OwnedBatchUV,
}

impl Gfx2d {
    /// Creates a new Gfx2d object.
    pub fn new<D: gfx::Device<C>,
               C: gfx::CommandBuffer>(device: &mut D) -> Gfx2d {
        let program = device.link_program(
                VERTEX_SHADER.clone(),
                FRAGMENT_SHADER.clone()
            ).unwrap();
        let program_uv = device.link_program(
                VERTEX_SHADER_UV.clone(),
                FRAGMENT_SHADER_UV.clone()
            ).unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_color = device.create_buffer(
            COLOR_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.push_all_move(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ));
        mesh.attributes.push_all_move(gfx::VertexFormat::generate(
            None::<ColorFormat>,
            buffer_color.raw()
        ));

        // Reuse parameters from `mesh`.
        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.push_all_move(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ));

        let batch = gfx::batch::OwnedBatch::new(mesh, program, ()).unwrap();

        let sampler = device.create_sampler(
                gfx::tex::SamplerInfo::new(gfx::tex::Trilinear,
                                           gfx::tex::Clamp)
            );

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
                [0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            s_texture: (texture, Some(sampler))
        };

        let batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv).unwrap();

        Gfx2d {
            buffer_pos: buffer_pos,
            buffer_color: buffer_color,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }
}

/// Used for rendering 2D graphics.
pub struct RenderContext<'a, C: 'a + gfx::CommandBuffer> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    gfx2d: &'a mut Gfx2d,
}

impl<'a, C: gfx::CommandBuffer> RenderContext<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               gfx2d: &'a mut Gfx2d) -> RenderContext<'a, C> {
        RenderContext {
            renderer: renderer,
            frame: frame,
            gfx2d: gfx2d,
        }
    }
}

impl<'a, C: gfx::CommandBuffer> BackEnd<Texture>
for RenderContext<'a, C> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        let &RenderContext {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: [r, g, b, a],
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::Color,
                frame
            );
    }

    fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::{Normal, Inverse, Factor};

        self.gfx2d.batch.state.blend = Some(gfx::state::Blend {
                value: [1.0, 1.0, 1.0, 1.0],
                color: gfx::state::BlendChannel {
                        equation: gfx::state::FuncAdd,
                        source: Factor(Normal, gfx::state::SourceAlpha),
                        destination: Factor(Inverse, gfx::state::SourceAlpha)
                    },
                alpha: Default::default()
            })
    }

    fn disable_alpha_blend(&mut self) {
        self.gfx2d.batch.state.blend = None;
    }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let &RenderContext {
            ref mut renderer,
            ref frame,
            gfx2d: &Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut batch,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch.slice = gfx::VertexSlice(gfx::TriangleList, 0, n as u32);
        renderer.draw(&*batch, *frame);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let ParamsUV {
            s_texture: (ref mut s_texture, _)
        } = self.gfx2d.batch_uv.param;
        *s_texture = texture.handle;
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        let &RenderContext {
            ref mut renderer,
            ref frame,
            gfx2d: &Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        assert_eq!(
            vertices.len() * UV_COMPONENTS,
            texture_coords.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);
        renderer.update_buffer_vec(*buffer_uv, texture_coords, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch_uv.slice = gfx::VertexSlice(gfx::TriangleList, 0, n as u32);
        renderer.draw(&*batch_uv, *frame);
    }
}
<|endoftext|>


<commit_before>extern crate rand;
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::cmp::{Ord, Ordering};
use std::fmt;
extern crate crossterm;
use crate::Render;
use crossterm::cursor;

// images in config file start with
pub const CONF_LINE_IDENTIFIER__IMAGE: char = '|';

const BIG_IMAGE: usize = 100; // sort algorithm <-> random algorithm

// first char of image lines must be '|'
const DEFAULT_IMAGES: &[&str] = &[
    r#"
|    ,,,,,
|   (o   o)
|    /. .\
|   (_____)
|     : :
|    ##O##'
|  ,,,: :,,,
| _)\ : : /(____
|{  \     /  ___}
| \/)     ((/
|  (_______)
|    :   :
|    :   :
|   / \ / \
|   """ """
"#,
    r#"
|    |\_|X|_/|
|   /         \
| =(  O     O  )=
|  -\    o    /-
|   / .-----. \
| /_ | o   o |_ \
|(U  |       |  U)
|   _|_     _|_
|  (   )---(   )
"#,
    r#"
|        _.---._    /\\
|     ./'       "--`\//
|   ./              o \
|  /./\  )______   \__ \
| ./  / /\ \   | \ \  \ \
|    / /  \ \  | |\ \  \7
|     "     "    "  "        VK
"#,
    r#"
|       ,.
|      (_|,.
|     ,' /, )_______   _
|  __j o``-'        `.'-)'
| (")                 \'
|  `-j                |
|    `-._(           /
|       |_\  |--^.  /
|      /_]'|_| /_)_/
|         /_]'  /_]'
# Author: hjw
"#,
    r#"
|        _
|       [ ]
|      (   )
|       |>|
|    __/===\__
|   //| o=o |\\
| <]  | o=o |  [>
|     \=====/
|    / / | \ \
|   <_________>
"#,
    r#"
|                          (_)(_)
|                          /     \
|                         /       |
|                        /   \  * |
|          ________     /    /\__/
|  _      /        \   /    /
| / \    /  ____    \_/    /
|//\ \  /  /    \         /
|V  \ \/  /      \       /
|    \___/        \_____/
"#,
    r#"
|         .-.
|        (. .)__,')
|        / V      )
|  ()    \  (   \/
|<)-`\()  `._`._ \
|  <).>=====<<==`'====
|   C-'`(>
# Author: hjw
"#,
    r#"
| >(. )
|  |  (     /)
|  |   \___/ )
|  (   ----- )  >@)_//   >@)_//  >@)_//  >@)_//
|   \_______/    (__)     (__)    (__)    (__)
|~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
"r#,
  r#"
|           __
|           /(`o
|     ,-,  //  \\
|    (,,,) ||   V
|   (,,,,)\//
|   (,,,/w)-'
|   \,,/w)
|   `V/uu
|     / |
|     | |
|     o o
|     \ |
|\,/  ,\|,.  \,/
"#,
    r#"
|o
| \_/\o
|( Oo)                    \|/
|(_=-)  .===O-  ~~Z~A~P~~ -O-
|/   \_/U'                /|\
|||  |_/
|\\  |
|{K ||
| | PP
| | ||
| (__\\
# Author: ac
"#,
    r#"
|      ______
|     /     /\
|    /     /  \
|   /_____/----\_    (
|  "     "          ).
| _ ___          o (:') o
|(@))_))        o ~/~~\~ o
|                o  o  o
"#,
    r#"
|                             _______     |\
|                            |License|    | \
|  _____                     | ~~*~~ |    |  \
| |     |  (((        .--.   |_______|    |
| |DrJRO| ~OvO~ __   (////)               |
| |     | ( _ )|==|   \__/                |
| |o    |  \_/ |_(|  /    \   _______     |
| |     | //|\\   \\//|  |\\  |__o__|     |
| |   __|//\_/\\ __\/ |__|//  |__o__|     |
| |  |==""//=\\""====|||||)   |__o__|     |
|_|__||_|_||_||_____||||||____|__o__|_____|
|    ||  (_) (_)    ||||||                \
|    []             [(_)(_)
"#,
];

#[derive(PartialOrd, Eq, PartialEq, Debug, Copy, Clone)] //omitting Ord
pub struct ImChar {
    pub point: (u8, u8),
    pub code: char,
}

impl fmt::Display for ImChar {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", self.code)
    }
}

// Ord enables us to v.sort()
impl Ord for ImChar {
    fn cmp(&self, other: &Self) -> Ordering {
        fn weight(ic: &ImChar) -> isize {
            let &ImChar { point: (x, y), .. } = ic;
            // points near the lower left corner are light
            x as isize - y as isize
        }
        weight(&self).cmp(&weight(&other))
    }
}

#[derive(Debug)]
pub struct Image {
    pub ichars: Vec<ImChar>,
    pub offset: (usize, usize),
    pub dimension: (u8, u8),
    pub visible_points: usize,
}

impl Render for Image {
    fn render(&self) {
        use std::io;
        use std::io::prelude::*;

        let cursor = cursor();
        for ic in self.ichars.iter().take(self.visible_points) {
            let &ImChar {
                point: (x, y),
                code,
            } = ic;
            cursor
                .goto(
                    (self.offset.1 + (x as usize) + 1) as u16,
                    (self.offset.0 + (y as usize) + 1) as u16,
                )
                .expect("Can not set cursor position.");

            print!("{}", &code);

            // The following flush() is necessary on Windows terminals that do not understand ANSI
            // escape code such as Window 7, 8 and older 10. BTW, in 2016, Microsoft released the
            // Windows 10 Version 1511 update which unexpectedly implemented support for ANSI
            // escape sequences.
            // [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code#Windows)

            io::stdout().flush().ok().expect("Could not flush stdout");
        }
        // after printing the image s, bring the cursor below
        cursor
            .goto(0, (self.dimension.1 as usize + 1 + self.offset.1) as u16)
            .expect("Can not move cursor.");
    }
}

impl Image {
    pub fn new(string: &str, offset: (usize, usize)) -> Self {
        let mut v: Vec<ImChar> = Vec::new();

        for (y, line) in string
            // split in lines
            .lines()
            // consider only lines starting with '|'
            .filter(|&l| l.starts_with(CONF_LINE_IDENTIFIER__IMAGE))
            .enumerate()
        //.inspect(|&(n,l)| println!("line {:?}: {:?} ", n,l))
        {
            let mut ii: Vec<_> = line
                .char_indices()
                // skip first char '|'
                .skip(1)
                // consider only chars != ' '
                .filter(|&(_, c)| c != ' ')
                // save in ImageChar object
                .map(|(x, c)| ImChar {
                    point: (x as u8, y as u8),
                    code: c,
                })
                .collect();
            v.append(&mut ii);
        }

        // find dimensions
        let mut x_max = 0;
        let mut y_max = 0;
        for i in &v {
            let &ImChar { point: (x, y), .. } = i;
            if x > x_max {
                x_max = x
            };
            if y > y_max {
                y_max = y
            };
        }

        // order points
        let v_len = v.len();
        if v_len <= BIG_IMAGE {
            v.sort(); // Sort algorithm, see "impl Ord for ImageChar"
        } else {
            let mut rng = thread_rng();
            (&mut v).shuffle(&mut rng); // points appear randomly.
        }

        if v.is_empty() {
            let mut rng = thread_rng();
            Self::new((&DEFAULT_IMAGES).choose(&mut rng).unwrap(), offset)
        } else {
            Self {
                ichars: v,
                offset,
                dimension: (x_max, y_max),
                visible_points: v_len,
            }
        }
    }

    pub fn disclose(&mut self, frac: (usize, usize)) {
        let l = self.ichars.len();

        let as_points = |(n, d)| (3 * l * (d - n) as usize / d as usize + l) / 4;

        if frac.1 > 0 {
            self.visible_points = as_points(frac);
        };
    }
}
<commit_msg>20 more ASCII-art images<commit_after>extern crate rand;
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::cmp::{Ord, Ordering};
use std::fmt;
extern crate crossterm;
use crate::Render;
use crossterm::cursor;

// images in config file start with
pub const CONF_LINE_IDENTIFIER__IMAGE: char = '|';

const BIG_IMAGE: usize = 100; // sort algorithm <-> random algorithm

// first char of image lines must be '|'
const DEFAULT_IMAGES: &[&str] = &[
    r#"
|    ,,,,,
|   (o   o)
|    /. .\
|   (_____)
|     : :
|    ##O##'
|  ,,,: :,,,
| _)\ : : /(____
|{  \     /  ___}
| \/)     ((/
|  (_______)
|    :   :
|    :   :
|   / \ / \
|   """ """
"#,
    r#"
|    |\_|X|_/|
|   /         \
| =(  O     O  )=
|  -\    o    /-
|   / .-----. \
| /_ | o   o |_ \
|(U  |       |  U)
|   _|_     _|_
|  (   )---(   )
"#,
    r#"
|        _.---._    /\\
|     ./'       "--`\//
|   ./              o \
|  /./\  )______   \__ \
| ./  / /\ \   | \ \  \ \
|    / /  \ \  | |\ \  \7
|     "     "    "  "        VK
"#,
    r#"
|       ,.
|      (_|,.
|     ,' /, )_______   _
|  __j o``-'        `.'-)'
| (")                 \'
|  `-j                |
|    `-._(           /
|       |_\  |--^.  /
|      /_]'|_| /_)_/
|         /_]'  /_]'
# Author: hjw
"#,
    r#"
|        _
|       [ ]
|      (   )
|       |>|
|    __/===\__
|   //| o=o |\\
| <]  | o=o |  [>
|     \=====/
|    / / | \ \
|   <_________>
"#,
    r#"
|                          (_)(_)
|                          /     \
|                         /       |
|                        /   \  * |
|          ________     /    /\__/
|  _      /        \   /    /
| / \    /  ____    \_/    /
|//\ \  /  /    \         /
|V  \ \/  /      \       /
|    \___/        \_____/
"#,
    r#"
|         .-.
|        (. .)__,')
|        / V      )
|  ()    \  (   \/
|<)-`\()  `._`._ \
|  <).>=====<<==`'====
|   C-'`(>
# Author: hjw
"#,
    r#"
| >(. )
|  |  (     /)
|  |   \___/ )
|  (   ----- )  >@)_//   >@)_//  >@)_//  >@)_//
|   \_______/    (__)     (__)    (__)    (__)
|~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
"#,
    r#"
|           __
|           /(`o
|     ,-,  //  \\
|    (,,,) ||   V
|   (,,,,)\//
|   (,,,/w)-'
|   \,,/w)
|   `V/uu
|     / |
|     | |
|     o o
|     \ |
|\,/  ,\|,.  \,/
"#,
    r#"
|o
| \_/\o
|( Oo)                    \|/
|(_=-)  .===O-  ~~Z~A~P~~ -O-
|/   \_/U'                /|\
|||  |_/
|\\  |
|{K ||
| | PP
| | ||
| (__\\
# Author: ac
"#,
    r#"
|      ______
|     /     /\
|    /     /  \
|   /_____/----\_    (
|  "     "          ).
| _ ___          o (:') o
|(@))_))        o ~/~~\~ o
|                o  o  o
"#,
    r#"
|                             _______     |\
|                            |License|    | \
|  _____                     | ~~*~~ |    |  \
| |     |  (((        .--.   |_______|    |
| |DrJRO| ~OvO~ __   (////)               |
| |     | ( _ )|==|   \__/                |
| |o    |  \_/ |_(|  /    \   _______     |
| |     | //|\\   \\//|  |\\  |__o__|     |
| |   __|//\_/\\ __\/ |__|//  |__o__|     |
| |  |==""//=\\""====|||||)   |__o__|     |
|_|__||_|_||_||_____||||||____|__o__|_____|
|    ||  (_) (_)    ||||||                \
|    []             [(_)(_)
"#,
    r#"
|  (o|_+_|o)
|   ( . . )
|  _( (Y) )_
| / /,---.\ \
|/ / | + | \ \
|\_)-"   "-(_/
|  |_______|
|  _)  |  (_
| (___,'.___)  hjw
# Art by Hayley Jane Wakenshaw
"#,
    r#"
|          |
|        \ _ /
|      -= (_) =-
|        /   \         _\/_
|          |           //o\  _\/_
|   _____ _ __ __ ____ _ | __/o\\ _
| =-=-_-__=_-= _=_=-=_,-'|"'""-|-,_
|  =- _=-=- -_=-=_,-"          |
|jgs =- =- -=.--"
# Art by Genoveva Galarza
"#,
    r#"
|        __I__
|   .-'"  .  "'-.
| .'  / . ' . \  '.
|/_.-..-..-..-..-._\ .---------------------------------.
|         #  _,,_   ( I hear it might rain people today )
|         #/`    `\ /'---------------------------------'
|         / / 6 6\ \
|         \/\  Y /\/       /\-/\
|         #/ `'U` \       /a a  \               _
|       , (  \   | \     =\ Y  =/-~~~~~~-,_____/ )
|       |\|\_/#  \_/       '^--'          ______/
|       \/'.  \  /'\         \           /
|        \    /=\  /         ||  |---'\  \
|   jgs  /____)/____)       (_(__|   ((__|
# Art by Joan Stark
"#,
    r#"
| [][][] /""\ [][][]
|  |::| /____\ |::|
|  |[]|_|::::|_|[]|
|  |::::::__::::::|
|  |:::::/||\:::::|
|  |:#:::||||::#::|
| #%*###&*##&*&#*&##
|##%%*####*%%%###*%*#
"#,
    r#"
|  ,-~~-.___.
| / |  '     \
|(  )         0
| \_/-, ,----'
|    ====           //
|   /  \-'~;    /~~~(O)
|  /  __/~|   /       |
|=(  _____| (_________|
"#,
    r#"
|  \,`/ /
| _)..  `_
|( __  -\
|    '`.
|   ( \>_-_,
|   _||_ ~-/    W<
"#,
    r#"
|            __:.__
|           (_:..'"=
|            ::/ o o\         AHAH!
|           ;'-'   (_)     Spaceman Spiff      .
|           '-._  ;-'        wins again !  _'._|\/:
|           .:;  ;                .         '- '   /_
|          :.. ; ;,                \       _/,    "_<
|         :.|..| ;:                 \__   '._____  _)
|         :.|.'| ||                            _/ /
|snd      :.|..| :'                           `;--:
|         '.|..|:':       _               _ _ :|_\:
|      .. _:|__| '.\.''..' ) ___________ ( )_):|_|:
|:....::''::/  | : :|''| "/ /_=_=_=_=_=/ :_[__'_\3_)
| ''''      '-''-'-'.__)-'
# Art by Shanaka Dias
"#,
    r#"
|  _,                          _
|.'  `.                  ___.>"''-..-.
|`-.   ;           .--"""        .-._@;
|   ;  !_.--..._ .'      /     .[_@'`'.
|  ;            /       : .'  ; :_.._  `.
|  :           ;        ;[   _T-"  `.'-. `-.
|   \        .-:      ; `.`-=_,88p.   _.}.-"
|    `-.__.-'   \    /L._ Y",P$T888;  ""
|             .-'_.-'  / ;$$$$$$]8P;
|             \ /     / / "Y$$P" ^"
|     fsc      ;\_    `.\_._
|              ]__\     \___;
"#,
    r#"
|        _
|      _<_/_
|   __/    _>
|  '\  '  |
|    \___/
|    /+++\
| o=|..|..|
|   | o/..|
|0==|+++++|
| 0======/
"#,
    r#"
|        _../|_
|      ='__   _~-.
|           \'  ~-`\._
|                 |/~`
|   .    .    .    .    .
|_.`(._.`(._.`(._.`(._.`(._
"#,
    r#"
|                        ____
|                   .---'-    \
|      .-----------/           \
|     /           (         ^  |   __
|&   (             \        O  /  / .'
|'._/(              '-'  (.   (_.' /
|     \                    \     ./
|      |    |       |    |/ '._.'
|       )   @).____\|  @ |
|   .  /    /       (    | mrf
|  \|, '_:::\  . ..  '_:::\ ..\).
# Art by Morfina
"#,
    r#"
|           __n__n__
|    .------`-\00/-'
|   /  ##  ## (oo)
|  / \## __   ./
|     |//YY \|/
|snd  |||   |||
# Art by Shanaka Dias
"#,
    r#"
|                       .-'~~~-.
|                     .'o  oOOOo`.
|                    :~~~-.oOo   o`.
|                     `. \ ~-.  oOOo.
|                       `.; / ~.  OO:
|                       .'  ;-- `.o.'
|                      ,'  ; ~~--'~
|                      ;  ;
|_______\|/__________\\;_\\//___\|/________
"#,
    r#"
|   (__  '.
|    /_____)
|   ()@ @ )))
|    'C ,()(()
|    ,.'_'.' \
| __/ )   (--'
|'._./     \
|   (_._._._)
|    _|| ||_
|mrf(__.).__)
"#,
    r#"
|        o    .   _     .
|          .     (_)         o
|   o      ____            _       o
|  _   ,-/   /)))  .   o  (_)   .
| (_)  \_\  ( e(     O             _
| o       \/' _/   ,_ ,  o   o    (_)
|  . O    _/ (_   / _/      .  ,        o
|     o8o/    \\_/ / ,-.  ,oO8/( -TT
|    o8o8O | } }  / /   \Oo8OOo8Oo||     O
|   Oo(""o8"""""""""""""""8oo""""""")
|  _   `\`'                  `'   /'   o
| (_)    \                       /    _   .
|      O  \           _         /    (_)
|o   .     `-. .----<(o)_--. .-'
|   --------(_/------(_<_/--\_)--------hjw
"#,
    r#"
|                \||/
|                |  @___oo
|      /\  /\   / (__,,,,|
|     ) /^\) ^\/ _)
|     )   /^\/   _)
|     )   _ /  / _)
| /\  )/\/ ||  | )_)
|<  >      |(,,) )__)
| ||      /    \)___)\
| | \____(      )___) )___
|  \______(_______;;; __;;;
"#,
    r#"
|   (\{\
|   { { \ ,~,
|  { {   \)))  *
|   { {  (((  /
|    {/{/; ,\/
|       (( '
|        \` \
|        (/  \
|ejm     `)  `\
"#,
    r#"
|                    /
|               ,.. /
|             ,'   ';
|  ,,.__    _,' /';  .
| :','  ~~~~    '. '~
|:' (   )         )::,
|'. '. .=----=..-~  .;'
| '  ;'  ::   ':.  '"
|   (:   ':    ;)
|    \\   '"  ./
|     '"      '"
# DR J
"#,
    r#"
|     __/\__
|. _  \\''//
|-( )-/_||_\
| .'. \_()_/
|  |   | . \
|  |mrf| .  \
| .'. ,\_____'.
"#,
    r#"
|         _.-.
|       ,'/ //\
|      /// // /)
|     /// // //|
|    /// // ///
|   /// // ///
|  (`: // ///
|   `;`: ///
|   / /:`:/
|  / /  `'
| / /
|(_/  hh
"#,
    r#"
| _____
||A .  | _____
|| /.\ ||A ^  | _____
||(_._)|| / \ ||A _  | _____
||  |  || \ / || ( ) ||A_ _ |
||____V||  .  ||(_'_)||( v )|
|       |____V||  |  || \ / |
|              |____V||  .  |
|                     |____V| ejm98
"#,
];

#[derive(PartialOrd, Eq, PartialEq, Debug, Copy, Clone)] //omitting Ord
pub struct ImChar {
    pub point: (u8, u8),
    pub code: char,
}

impl fmt::Display for ImChar {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", self.code)
    }
}

// Ord enables us to v.sort()
impl Ord for ImChar {
    fn cmp(&self, other: &Self) -> Ordering {
        fn weight(ic: &ImChar) -> isize {
            let &ImChar { point: (x, y), .. } = ic;
            // points near the lower left corner are light
            x as isize - y as isize
        }
        weight(&self).cmp(&weight(&other))
    }
}

#[derive(Debug)]
pub struct Image {
    pub ichars: Vec<ImChar>,
    pub offset: (usize, usize),
    pub dimension: (u8, u8),
    pub visible_points: usize,
}

impl Render for Image {
    fn render(&self) {
        use std::io;
        use std::io::prelude::*;

        let cursor = cursor();
        for ic in self.ichars.iter().take(self.visible_points) {
            let &ImChar {
                point: (x, y),
                code,
            } = ic;
            cursor
                .goto(
                    (self.offset.1 + (x as usize) + 1) as u16,
                    (self.offset.0 + (y as usize) + 1) as u16,
                )
                .expect("Can not set cursor position.");

            print!("{}", &code);

            // The following flush() is necessary on Windows terminals that do not understand ANSI
            // escape code such as Window 7, 8 and older 10. BTW, in 2016, Microsoft released the
            // Windows 10 Version 1511 update which unexpectedly implemented support for ANSI
            // escape sequences.
            // [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code#Windows)

            io::stdout().flush().ok().expect("Could not flush stdout");
        }
        // after printing the image s, bring the cursor below
        cursor
            .goto(0, (self.dimension.1 as usize + 1 + self.offset.1) as u16)
            .expect("Can not move cursor.");
    }
}

impl Image {
    pub fn new(string: &str, offset: (usize, usize)) -> Self {
        let mut v: Vec<ImChar> = Vec::new();

        for (y, line) in string
            // split in lines
            .lines()
            // consider only lines starting with '|'
            .filter(|&l| l.starts_with(CONF_LINE_IDENTIFIER__IMAGE))
            .enumerate()
        //.inspect(|&(n,l)| println!("line {:?}: {:?} ", n,l))
        {
            let mut ii: Vec<_> = line
                .char_indices()
                // skip first char '|'
                .skip(1)
                // consider only chars != ' '
                .filter(|&(_, c)| c != ' ')
                // save in ImageChar object
                .map(|(x, c)| ImChar {
                    point: (x as u8, y as u8),
                    code: c,
                })
                .collect();
            v.append(&mut ii);
        }

        // find dimensions
        let mut x_max = 0;
        let mut y_max = 0;
        for i in &v {
            let &ImChar { point: (x, y), .. } = i;
            if x > x_max {
                x_max = x
            };
            if y > y_max {
                y_max = y
            };
        }

        // order points
        let v_len = v.len();
        if v_len <= BIG_IMAGE {
            v.sort(); // Sort algorithm, see "impl Ord for ImageChar"
        } else {
            let mut rng = thread_rng();
            (&mut v).shuffle(&mut rng); // points appear randomly.
        }

        if v.is_empty() {
            let mut rng = thread_rng();
            Self::new((&DEFAULT_IMAGES).choose(&mut rng).unwrap(), offset)
        } else {
            Self {
                ichars: v,
                offset,
                dimension: (x_max, y_max),
                visible_points: v_len,
            }
        }
    }

    pub fn disclose(&mut self, frac: (usize, usize)) {
        let l = self.ichars.len();

        let as_points = |(n, d)| (3 * l * (d - n) as usize / d as usize + l) / 4;

        if frac.1 > 0 {
            self.visible_points = as_points(frac);
        };
    }
}
<|endoftext|>


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

use token::Token;

use std::cell::Cell;
use std::rc::Rc;
use regex::Regex;
use context::Context;
use token::Posn;

pub trait ESCharExt {
    fn is_es_newline(self) -> bool;
    fn is_es_whitespace(self) -> bool;
}

impl ESCharExt for char {
    fn is_es_newline(self) -> bool {
        match self {
            '\u{000a}' | '\u{000d}' | '\u{2028}' | '\u{2029}' => true,
            _ => false
        }
    }

    fn is_es_whitespace(self) -> bool {
        match self {
              '\u{0009}' | '\u{000b}' | '\u{000c}' | '\u{0020}' | '\u{00a0}'
            | '\u{1680}' | '\u{2000}' | '\u{2001}' | '\u{2002}' | '\u{2003}' | '\u{2004}'
            | '\u{2005}' | '\u{2006}' | '\u{2009}' | '\u{200a}' | '\u{202f}' | '\u{205f}'
            | '\u{3000}' | '\u{feff}' => true,
            _ => false
        }
    }
}

struct LineOrientedReader<I> {
    chars: I,
    curr_char: Option<char>,
    next_char: Option<char>,
    curr_posn: Posn
}

impl<I> LineOrientedReader<I> where I: Iterator<Item=char> {
    pub fn new(mut chars: I) -> LineOrientedReader<I> {
        let curr_char = chars.next();
        let next_char = if curr_char.is_some() { chars.next() } else { None };
        LineOrientedReader {
            chars: chars,
            curr_char: curr_char,
            next_char: next_char,
            curr_posn: Posn {
                offset: 0,
                line: 0,
                column: 0
            }
        }
    }

    pub fn curr_char(&mut self) -> Option<char> { self.curr_char }
    pub fn curr_posn(&mut self) -> Posn { self.curr_posn }
    pub fn next_char(&mut self) -> Option<char> { self.next_char }

    pub fn bump(&mut self) {
        let curr_char = self.next_char;
        let next_char = if curr_char.is_some() { self.chars.next() } else { None };

        self.curr_char = curr_char;
        self.next_char = next_char;

        if (curr_char == Some('\r') && next_char != Some('\n')) ||
           curr_char == Some('\n') ||
           curr_char == Some('\u{2028}') ||
           curr_char == Some('\u{2029}') {
            self.curr_posn.line += 1;
            self.curr_posn.column = 0;
        } else {
            self.curr_posn.column += 1;
        }

        self.curr_posn.offset += 1;
    }
}

struct TokenBuffer {
    tokens: LinkedList<Token>
}

impl TokenBuffer {
    fn new() -> TokenBuffer {
        TokenBuffer {
            tokens: LinkedList::new()
        }
    }

    fn is_empty(&mut self) -> bool {
        self.tokens.len() == 0
    }

    fn push_token(&mut self, token: Token) {
        assert!(self.tokens.len() == 0);
        self.tokens.push_back(token);
    }

    fn read_token(&mut self) -> Token {
        assert!(self.tokens.len() > 0);
        self.tokens.pop_front().unwrap()
    }

    fn peek_token(&mut self) -> &Token {
        assert!(self.tokens.len() > 0);
        self.tokens.front().unwrap()
    }

    fn unread_token(&mut self, token: Token) {
        assert!(self.tokens.len() >= 0);
        assert!(self.tokens.len() < 3);
        self.tokens.push_front(token);
    }
}

pub struct Lexer<I> {
    reader: LineOrientedReader<I>,
    cx: Rc<Cell<Context>>,
    lookahead: TokenBuffer
}

impl<I> Lexer<I> where I: Iterator<Item=char> {
    // constructor

    pub fn new(chars: I, cx: Rc<Cell<Context>>) -> Lexer<I> {
        Lexer {
            reader: LineOrientedReader::new(chars),
            cx: cx,
            lookahead: TokenBuffer::new()
        }
    }

    // public methods

    pub fn is_eof(&mut self) -> bool {
        match *self.peek_token() {
            Token::EOF => true,
            _ => false
        }
    }

    pub fn peek_token(&mut self) -> &Token {
        if self.lookahead.is_empty() {
            let token = self.read_next_token();
            self.lookahead.push_token(token);
        }
        self.lookahead.peek_token()
    }

    pub fn read_token(&mut self) -> Token {
        if self.lookahead.is_empty() {
            self.read_next_token()
        } else {
            self.lookahead.read_token()
        }
    }

    pub fn unread_token(&mut self, token: Token) {
        self.lookahead.unread_token(token);
    }

    // private methods

    fn skip_line_comment(&mut self) {
    }

    fn skip_block_comment(&mut self) {
    }

    fn div_or_regexp(&mut self) -> Token {
        unimplemented!()
    }

    fn read_next_token(&mut self) -> Token {
        self.skip_whitespace();
        loop {
            match self.reader.curr_char() {
                None => Token::EOF,
                Some(ch) => {
                    if ch == '/' {
                        match self.reader.next_char() {
                            Some('/') => self.skip_line_comment(),
                            Some('*') => self.skip_block_comment(),
                            _ => { return self.div_or_regexp() }
                        }
                    }
                    unimplemented!()
                }
            }
        }
    }

    fn is_whitespace(&mut self) -> bool {
        match self.reader.curr_char() {
            Some(ch) => ch.is_es_whitespace(),
            None => false
        }
    }

    fn eat(&mut self) -> Option<char> {
        let ch = self.reader.curr_char();
        self.reader.bump();
        ch
    }

    fn skip_whitespace(&mut self) {
        while self.is_whitespace() {
            self.reader.bump();
        }
    }
}

impl<I> Iterator for Lexer<I> where I: Iterator<Item=char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.skip_whitespace();
        self.eat()
            .map(|ch| {
                match ch {
                    '1' => Token::DecimalInt(String::from_str("1")),
                    '+' => Token::Plus,
                    _ => Token::Error(ch)
                }
            })
    }
}
<commit_msg>added missing return, typechecks now<commit_after>use std::collections::LinkedList;

use token::Token;

use std::cell::Cell;
use std::rc::Rc;
use regex::Regex;
use context::Context;
use token::Posn;

pub trait ESCharExt {
    fn is_es_newline(self) -> bool;
    fn is_es_whitespace(self) -> bool;
}

impl ESCharExt for char {
    fn is_es_newline(self) -> bool {
        match self {
            '\u{000a}' | '\u{000d}' | '\u{2028}' | '\u{2029}' => true,
            _ => false
        }
    }

    fn is_es_whitespace(self) -> bool {
        match self {
              '\u{0009}' | '\u{000b}' | '\u{000c}' | '\u{0020}' | '\u{00a0}'
            | '\u{1680}' | '\u{2000}' | '\u{2001}' | '\u{2002}' | '\u{2003}' | '\u{2004}'
            | '\u{2005}' | '\u{2006}' | '\u{2009}' | '\u{200a}' | '\u{202f}' | '\u{205f}'
            | '\u{3000}' | '\u{feff}' => true,
            _ => false
        }
    }
}

struct LineOrientedReader<I> {
    chars: I,
    curr_char: Option<char>,
    next_char: Option<char>,
    curr_posn: Posn
}

impl<I> LineOrientedReader<I> where I: Iterator<Item=char> {
    pub fn new(mut chars: I) -> LineOrientedReader<I> {
        let curr_char = chars.next();
        let next_char = if curr_char.is_some() { chars.next() } else { None };
        LineOrientedReader {
            chars: chars,
            curr_char: curr_char,
            next_char: next_char,
            curr_posn: Posn {
                offset: 0,
                line: 0,
                column: 0
            }
        }
    }

    pub fn curr_char(&mut self) -> Option<char> { self.curr_char }
    pub fn curr_posn(&mut self) -> Posn { self.curr_posn }
    pub fn next_char(&mut self) -> Option<char> { self.next_char }

    pub fn bump(&mut self) {
        let curr_char = self.next_char;
        let next_char = if curr_char.is_some() { self.chars.next() } else { None };

        self.curr_char = curr_char;
        self.next_char = next_char;

        if (curr_char == Some('\r') && next_char != Some('\n')) ||
           curr_char == Some('\n') ||
           curr_char == Some('\u{2028}') ||
           curr_char == Some('\u{2029}') {
            self.curr_posn.line += 1;
            self.curr_posn.column = 0;
        } else {
            self.curr_posn.column += 1;
        }

        self.curr_posn.offset += 1;
    }
}

struct TokenBuffer {
    tokens: LinkedList<Token>
}

impl TokenBuffer {
    fn new() -> TokenBuffer {
        TokenBuffer {
            tokens: LinkedList::new()
        }
    }

    fn is_empty(&mut self) -> bool {
        self.tokens.len() == 0
    }

    fn push_token(&mut self, token: Token) {
        assert!(self.tokens.len() == 0);
        self.tokens.push_back(token);
    }

    fn read_token(&mut self) -> Token {
        assert!(self.tokens.len() > 0);
        self.tokens.pop_front().unwrap()
    }

    fn peek_token(&mut self) -> &Token {
        assert!(self.tokens.len() > 0);
        self.tokens.front().unwrap()
    }

    fn unread_token(&mut self, token: Token) {
        assert!(self.tokens.len() >= 0);
        assert!(self.tokens.len() < 3);
        self.tokens.push_front(token);
    }
}

pub struct Lexer<I> {
    reader: LineOrientedReader<I>,
    cx: Rc<Cell<Context>>,
    lookahead: TokenBuffer
}

impl<I> Lexer<I> where I: Iterator<Item=char> {
    // constructor

    pub fn new(chars: I, cx: Rc<Cell<Context>>) -> Lexer<I> {
        Lexer {
            reader: LineOrientedReader::new(chars),
            cx: cx,
            lookahead: TokenBuffer::new()
        }
    }

    // public methods

    pub fn is_eof(&mut self) -> bool {
        match *self.peek_token() {
            Token::EOF => true,
            _ => false
        }
    }

    pub fn peek_token(&mut self) -> &Token {
        if self.lookahead.is_empty() {
            let token = self.read_next_token();
            self.lookahead.push_token(token);
        }
        self.lookahead.peek_token()
    }

    pub fn read_token(&mut self) -> Token {
        if self.lookahead.is_empty() {
            self.read_next_token()
        } else {
            self.lookahead.read_token()
        }
    }

    pub fn unread_token(&mut self, token: Token) {
        self.lookahead.unread_token(token);
    }

    // private methods

    fn skip_line_comment(&mut self) {
    }

    fn skip_block_comment(&mut self) {
    }

    fn div_or_regexp(&mut self) -> Token {
        unimplemented!()
    }

    fn read_next_token(&mut self) -> Token {
        self.skip_whitespace();
        loop {
            match self.reader.curr_char() {
                None => return Token::EOF,
                Some(ch) => {
                    if ch == '/' {
                        match self.reader.next_char() {
                            Some('/') => self.skip_line_comment(),
                            Some('*') => self.skip_block_comment(),
                            _ => return self.div_or_regexp()
                        }
                    }
                    unimplemented!()
                }
            }
        }
    }

    fn is_whitespace(&mut self) -> bool {
        match self.reader.curr_char() {
            Some(ch) => ch.is_es_whitespace(),
            None => false
        }
    }

    fn eat(&mut self) -> Option<char> {
        let ch = self.reader.curr_char();
        self.reader.bump();
        ch
    }

    fn skip_whitespace(&mut self) {
        while self.is_whitespace() {
            self.reader.bump();
        }
    }
}

impl<I> Iterator for Lexer<I> where I: Iterator<Item=char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.skip_whitespace();
        self.eat()
            .map(|ch| {
                match ch {
                    '1' => Token::DecimalInt(String::from_str("1")),
                    '+' => Token::Plus,
                    _ => Token::Error(ch)
                }
            })
    }
}
<|endoftext|>


<commit_before>#![crate_name="json_macros"]
#![crate_type="dylib"]
#![feature(phase, plugin_registrar, macro_rules, quote)]

#[phase(plugin, link)] extern crate log;
extern crate rustc;
extern crate syntax;
extern crate serialize;

use syntax::ast::TokenTree;
use syntax::codemap::Span;
use syntax::ptr::P;

use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, DummyResult};
use syntax::parse::token;
use syntax::print::pprust;
use rustc::plugin::Registry;

type PExpr = P<ast::Expr>;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("json", expand);
}

fn expand<'cx>(cx: &'cx mut ExtCtxt, sp: Span,
               tts: &[TokenTree]) -> Box<MacResult + 'cx> {
    debug!("JSON token tree {}", tts);

    let tt = match tts.get(0) {
        Some(tt) => tt,
        None => {
            cx.span_err(sp, "expected JSON literal");
            return DummyResult::expr(sp);
        }
    };

    let expr = match tt_to_expr(cx, tt) {
        Some(e) => e,
        None => return DummyResult::expr(sp)
    };
    MacExpr::new(expr)
}

fn tt_to_expr(cx: &ExtCtxt, tt: &TokenTree) -> Option<PExpr> {
    use syntax::ext::build::AstBuilder;

    match *tt {
        ast::TtToken(sp, ref tok) => token_to_expr(cx, sp, tok),
        ast::TtDelimited(sp, ref d) => {
            let ref toks = d.tts;
            match d.delim {
                // array
                token::Bracket => {
                    let exprs = match parse_array(cx, sp, toks.as_slice()) {
                        Some(e) => e,
                        None => return None
                    };
                    let exprs = cx.expr_vec(sp, exprs);
                    Some(quote_expr!(cx, {
                        {
                            use std::slice::BoxedSlicePrelude;
                            let xs: ::std::boxed::Box<[_]> = box $exprs;
                            ::serialize::json::Json::Array(xs.into_vec())
                        }
                    }))
                }
                // object
                token::Brace => {
                    let items = match parse_object(cx, sp, toks.as_slice()) {
                        Some(i) => i,
                        None => return None
                    };
                    let ob = quote_expr!(cx, _ob);
                    let mut stmts = vec![];
                    for &(ref key, ref value) in items.iter() {
                        stmts.push(quote_stmt!(cx, $ob.insert($key, $value)));
                    }

                    Some(quote_expr!(cx, {
                        {
                            let mut $ob = ::std::collections::TreeMap::new();
                            $stmts;
                            ::serialize::json::Json::Object($ob)
                        }
                    }))
                }
                token::Paren => {
                    let mut parser = cx.new_parser_from_tts(toks.as_slice());
                    let expr = parser.parse_expr();

                    Some(quote_expr!(cx, {
                        use serialize::json::ToJson;
                        ($expr).to_json()
                    }))
                }
            }
        }
        ast::TtSequence(sp, _) => {
            cx.span_err(sp, "`json!` unexpected TtSequence");
            None
        }
    }
}

fn parse_array(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> Option<Vec<PExpr>> {
    let mut exprs = Vec::with_capacity(tts.len() / 2);
    for (i, tt) in tts.iter().enumerate() {
        if i % 2 == 1 {
            match tt {
                &ast::TtToken(_, token::Comma) => {
                    continue;
                }
                _ => {
                    expected_but_found(cx, sp, "`,`", tt);
                    return None;
                }
            }
        }
        let expr = tt_to_expr(cx, tt);
        let expr = match expr {
            Some(e) => e,
            None => return None,
        };
        exprs.push(expr);
    }
    Some(exprs)
}

fn parse_object(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> Option<Vec<(PExpr, PExpr)>> {
    use syntax::ast::TtToken;

    macro_rules! comma {
        () => {
            ::syntax::ast::TtToken(_, ::syntax::parse::token::Comma)
        }
    }

    macro_rules! colon {
        () => {
            ::syntax::ast::TtToken(_, ::syntax::parse::token::Colon)
        };
        ($sp:ident) => {
            ::syntax::ast::TtToken($sp, ::syntax::parse::token::Colon)
        }
    }

    let mut items = Vec::with_capacity(tts.len() / 4);
    if tts.len() == 0 {
        return Some(items);
    }

    // horrible
    for entry in tts.chunks(4) {
        use syntax::parse::token::{Lit, Literal};
        let item = match entry {
            // "foo": VALUE | "foo": VALUE,
            [TtToken(_, Literal(Lit::Str_(ref n), _)), colon!(), ref v] |
            [TtToken(_, Literal(Lit::Str_(ref n), _)), colon!(), ref v, comma!()] => {
                let k = n.as_str();
                let v = tt_to_expr(cx, v);
                if v.is_none() {
                    return None;
                }
                let k = quote_expr!(cx, $k.into_string());
                let v = quote_expr!(cx, $v);
                (k, v)
            }
            // "foo": VALUE X
            [TtToken(_, Literal(Lit::Str_(_), _)), colon!(), _, ref tt] => {
                expected_but_found(cx, sp, "`,`", tt);
                return None;
            }
            [TtToken(_, Literal(Lit::Str_(_), _)), colon!(sp)] => {
                cx.span_err(sp, "found `:` but no value afterwards");
                return None;
            }
            [TtToken(_, Literal(Lit::Str_(_) ,_)), ref tt, ..] => {
                expected_but_found(cx, sp, "`:`", tt);
                return None;
            }
            [TtToken(sp, Literal(Lit::Str_(_), _))] => {
                cx.span_err(sp, "found name but no colon-value afterwards");
                return None;
            }
            [ref tt, ..] => {
                expected_but_found(cx, sp, "string literal", tt);
                return None;
            }
            [] => unreachable!(), // chunks() never returns an empty slice
        };
        items.push(item);
    }

    Some(items)
}

fn token_to_expr(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> Option<PExpr> {
    use syntax::print::pprust;
    use syntax::parse::token::{Lit, Literal};

    match *tok {
        Literal(Lit::Str_(ref n), _) => {
            let s = n.as_str();
            Some(quote_expr!(cx, {
                ::serialize::json::Json::String($s.into_string())
            }))
        }
        // FIXME: handle suffixed literals (i.e. u64) correctly
        // FIXME: handle negative numbers
        Literal(Lit::Integer(_), _)=> {
            let tt = ast::TtToken(sp, tok.clone());
            Some(quote_expr!(cx, {
                ::serialize::json::Json::I64($tt as i64)
            }))
        }
        Literal(Lit::Float(_), _) => {
            let tt = ast::TtToken(sp, tok.clone());
            Some(quote_expr!(cx, {
                ::serialize::json::Json::F64($tt)
            }))
        }
        token::Ident(ref id, token::Plain) if id.as_str() == "null" => {
            Some(quote_expr!(cx, {
                ::serialize::json::Json::Null
            }))
        }
        ref t @ token::Ident(..) if t.is_keyword(token::keywords::True) => {
            Some(quote_expr!(cx, { ::serialize::json::Json::Boolean(true) }))
        }
        ref t @ token::Ident(..) if t.is_keyword(token::keywords::False) => {
            Some(quote_expr!(cx, { ::serialize::json::Json::Boolean(false) }))
        }
        _ => {
            let tt = ast::TtToken(sp, tok.clone());
            let s = pprust::tt_to_string(&tt);
            cx.span_err(sp, format!("unexpected `{}` in JSON", s).as_slice());
            None
        }
    }
}

fn best_span(sp: Span, tt: &TokenTree) -> Span {
    let sp = match *tt {
        ast::TtToken(tok_sp, _) => tok_sp,
        _ => sp // the span passed into the function!
    };
    sp
}

fn expected_but_found(cx: &ExtCtxt, sp: Span, expected: &str, found: &TokenTree) {
    let pp = pprust::tt_to_string(found);
    let err = format!("expected {} but found: `{}`", expected, pp);
    cx.span_err(best_span(sp, found), err.as_slice());
}
<commit_msg>rustup: BoxedSlicePrelude -> BoxedSliceExt<commit_after>#![crate_name="json_macros"]
#![crate_type="dylib"]
#![feature(phase, plugin_registrar, macro_rules, quote)]

#[phase(plugin, link)] extern crate log;
extern crate rustc;
extern crate syntax;
extern crate serialize;

use syntax::ast::TokenTree;
use syntax::codemap::Span;
use syntax::ptr::P;

use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, DummyResult};
use syntax::parse::token;
use syntax::print::pprust;
use rustc::plugin::Registry;

type PExpr = P<ast::Expr>;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("json", expand);
}

fn expand<'cx>(cx: &'cx mut ExtCtxt, sp: Span,
               tts: &[TokenTree]) -> Box<MacResult + 'cx> {
    debug!("JSON token tree {}", tts);

    let tt = match tts.get(0) {
        Some(tt) => tt,
        None => {
            cx.span_err(sp, "expected JSON literal");
            return DummyResult::expr(sp);
        }
    };

    let expr = match tt_to_expr(cx, tt) {
        Some(e) => e,
        None => return DummyResult::expr(sp)
    };
    MacExpr::new(expr)
}

fn tt_to_expr(cx: &ExtCtxt, tt: &TokenTree) -> Option<PExpr> {
    use syntax::ext::build::AstBuilder;

    match *tt {
        ast::TtToken(sp, ref tok) => token_to_expr(cx, sp, tok),
        ast::TtDelimited(sp, ref d) => {
            let ref toks = d.tts;
            match d.delim {
                // array
                token::Bracket => {
                    let exprs = match parse_array(cx, sp, toks.as_slice()) {
                        Some(e) => e,
                        None => return None
                    };
                    let exprs = cx.expr_vec(sp, exprs);
                    Some(quote_expr!(cx, {
                        {
                            use std::slice::BoxedSliceExt;
                            let xs: ::std::boxed::Box<[_]> = box $exprs;
                            ::serialize::json::Json::Array(xs.into_vec())
                        }
                    }))
                }
                // object
                token::Brace => {
                    let items = match parse_object(cx, sp, toks.as_slice()) {
                        Some(i) => i,
                        None => return None
                    };
                    let ob = quote_expr!(cx, _ob);
                    let mut stmts = vec![];
                    for &(ref key, ref value) in items.iter() {
                        stmts.push(quote_stmt!(cx, $ob.insert($key, $value)));
                    }

                    Some(quote_expr!(cx, {
                        {
                            let mut $ob = ::std::collections::TreeMap::new();
                            $stmts;
                            ::serialize::json::Json::Object($ob)
                        }
                    }))
                }
                token::Paren => {
                    let mut parser = cx.new_parser_from_tts(toks.as_slice());
                    let expr = parser.parse_expr();

                    Some(quote_expr!(cx, {
                        use serialize::json::ToJson;
                        ($expr).to_json()
                    }))
                }
            }
        }
        ast::TtSequence(sp, _) => {
            cx.span_err(sp, "`json!` unexpected TtSequence");
            None
        }
    }
}

fn parse_array(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> Option<Vec<PExpr>> {
    let mut exprs = Vec::with_capacity(tts.len() / 2);
    for (i, tt) in tts.iter().enumerate() {
        if i % 2 == 1 {
            match tt {
                &ast::TtToken(_, token::Comma) => {
                    continue;
                }
                _ => {
                    expected_but_found(cx, sp, "`,`", tt);
                    return None;
                }
            }
        }
        let expr = tt_to_expr(cx, tt);
        let expr = match expr {
            Some(e) => e,
            None => return None,
        };
        exprs.push(expr);
    }
    Some(exprs)
}

fn parse_object(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> Option<Vec<(PExpr, PExpr)>> {
    use syntax::ast::TtToken;

    macro_rules! comma {
        () => {
            ::syntax::ast::TtToken(_, ::syntax::parse::token::Comma)
        }
    }

    macro_rules! colon {
        () => {
            ::syntax::ast::TtToken(_, ::syntax::parse::token::Colon)
        };
        ($sp:ident) => {
            ::syntax::ast::TtToken($sp, ::syntax::parse::token::Colon)
        }
    }

    let mut items = Vec::with_capacity(tts.len() / 4);
    if tts.len() == 0 {
        return Some(items);
    }

    // horrible
    for entry in tts.chunks(4) {
        use syntax::parse::token::{Lit, Literal};
        let item = match entry {
            // "foo": VALUE | "foo": VALUE,
            [TtToken(_, Literal(Lit::Str_(ref n), _)), colon!(), ref v] |
            [TtToken(_, Literal(Lit::Str_(ref n), _)), colon!(), ref v, comma!()] => {
                let k = n.as_str();
                let v = tt_to_expr(cx, v);
                if v.is_none() {
                    return None;
                }
                let k = quote_expr!(cx, $k.into_string());
                let v = quote_expr!(cx, $v);
                (k, v)
            }
            // "foo": VALUE X
            [TtToken(_, Literal(Lit::Str_(_), _)), colon!(), _, ref tt] => {
                expected_but_found(cx, sp, "`,`", tt);
                return None;
            }
            [TtToken(_, Literal(Lit::Str_(_), _)), colon!(sp)] => {
                cx.span_err(sp, "found `:` but no value afterwards");
                return None;
            }
            [TtToken(_, Literal(Lit::Str_(_) ,_)), ref tt, ..] => {
                expected_but_found(cx, sp, "`:`", tt);
                return None;
            }
            [TtToken(sp, Literal(Lit::Str_(_), _))] => {
                cx.span_err(sp, "found name but no colon-value afterwards");
                return None;
            }
            [ref tt, ..] => {
                expected_but_found(cx, sp, "string literal", tt);
                return None;
            }
            [] => unreachable!(), // chunks() never returns an empty slice
        };
        items.push(item);
    }

    Some(items)
}

fn token_to_expr(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> Option<PExpr> {
    use syntax::print::pprust;
    use syntax::parse::token::{Lit, Literal};

    match *tok {
        Literal(Lit::Str_(ref n), _) => {
            let s = n.as_str();
            Some(quote_expr!(cx, {
                ::serialize::json::Json::String($s.into_string())
            }))
        }
        // FIXME: handle suffixed literals (i.e. u64) correctly
        // FIXME: handle negative numbers
        Literal(Lit::Integer(_), _)=> {
            let tt = ast::TtToken(sp, tok.clone());
            Some(quote_expr!(cx, {
                ::serialize::json::Json::I64($tt as i64)
            }))
        }
        Literal(Lit::Float(_), _) => {
            let tt = ast::TtToken(sp, tok.clone());
            Some(quote_expr!(cx, {
                ::serialize::json::Json::F64($tt)
            }))
        }
        token::Ident(ref id, token::Plain) if id.as_str() == "null" => {
            Some(quote_expr!(cx, {
                ::serialize::json::Json::Null
            }))
        }
        ref t @ token::Ident(..) if t.is_keyword(token::keywords::True) => {
            Some(quote_expr!(cx, { ::serialize::json::Json::Boolean(true) }))
        }
        ref t @ token::Ident(..) if t.is_keyword(token::keywords::False) => {
            Some(quote_expr!(cx, { ::serialize::json::Json::Boolean(false) }))
        }
        _ => {
            let tt = ast::TtToken(sp, tok.clone());
            let s = pprust::tt_to_string(&tt);
            cx.span_err(sp, format!("unexpected `{}` in JSON", s).as_slice());
            None
        }
    }
}

fn best_span(sp: Span, tt: &TokenTree) -> Span {
    let sp = match *tt {
        ast::TtToken(tok_sp, _) => tok_sp,
        _ => sp // the span passed into the function!
    };
    sp
}

fn expected_but_found(cx: &ExtCtxt, sp: Span, expected: &str, found: &TokenTree) {
    let pp = pprust::tt_to_string(found);
    let err = format!("expected {} but found: `{}`", expected, pp);
    cx.span_err(best_span(sp, found), err.as_slice());
}
<|endoftext|>


<commit_before>use std::{collections::BTreeMap, convert::TryInto, fmt, panic};

use quickcheck::{Arbitrary, Gen, RngCore};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand_distr::{Distribution, Gamma};

use sled::*;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Key(pub Vec<u8>);

impl fmt::Debug for Key {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.0.len() > 0 {
            write!(
                f,
                "Key(vec![{}; {}])",
                self.0.get(0).copied().unwrap_or(0),
                self.0.len()
            )
        } else {
            write!(f, "Key(vec!{:?})", self.0)
        }
    }
}

struct SledGen {
    r: StdRng,
    size: usize,
}

impl Gen for SledGen {
    fn size(&self) -> usize {
        self.size
    }
}

impl RngCore for SledGen {
    fn next_u32(&mut self) -> u32 {
        self.r.gen::<u32>()
    }

    fn next_u64(&mut self) -> u64 {
        self.r.gen::<u64>()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.r.fill_bytes(dest)
    }

    fn try_fill_bytes(
        &mut self,
        dest: &mut [u8],
    ) -> std::result::Result<(), rand::Error> {
        self.r.try_fill_bytes(dest)
    }
}

pub fn fuzz_then_shrink(buf: &[u8]) {
    let use_compression =
        cfg!(feature = "compression") && buf.get(0).unwrap_or(&0) % 2 == 0;

    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0_u8; 32];
            seed[0..chunk.len()].copy_from_slice(chunk);
            let rng: StdRng = SeedableRng::from_seed(seed);
            let mut sled_rng = SledGen { r: rng, size: 2 };

            Op::arbitrary(&mut sled_rng)
        })
        .collect();

    let cache_bits = *buf.get(1).unwrap_or(&0);
    let segment_size_bits = *buf.get(2).unwrap_or(&0);

    match panic::catch_unwind(move || {
        prop_tree_matches_btreemap(
            ops,
            false,
            use_compression,
            cache_bits,
            segment_size_bits,
        )
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    #![allow(clippy::cast_possible_truncation)]
    #![allow(clippy::cast_precision_loss)]
    #![allow(clippy::cast_sign_loss)]

    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen::<bool>() {
            let gs = g.size();
            let gamma = Gamma::new(0.3, gs as f64).unwrap();
            let v = gamma.sample(&mut rand::thread_rng());
            let len = if v > 3000.0 { 10000 } else { (v % 300.) as usize };

            let space = g.gen_range(0, gs) + 1;

            let inner = (0..len).map(|_| g.gen_range(0, space) as u8).collect();

            Self(inner)
        } else {
            let len = g.gen_range(0, 2);
            let mut inner = vec![];

            for _ in 0..len {
                inner.push(g.gen::<u8>());
            }

            Self(inner)
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        // we only want to shrink on length, not byte values
        Box::new(
            self.0
                .len()
                .shrink()
                .zip(std::iter::repeat(self.0.clone()))
                .map(|(len, underlying)| Self(underlying[..len].to_vec())),
        )
    }
}

#[derive(Debug, Clone)]
pub enum Op {
    Set(Key, u8),
    Merge(Key, u8),
    Get(Key),
    GetLt(Key),
    GetGt(Key),
    Del(Key),
    Cas(Key, u8, u8),
    Scan(Key, isize),
    Restart,
}

use self::Op::{Cas, Del, Get, GetGt, GetLt, Merge, Restart, Scan, Set};

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen_bool(1. / 10.) {
            return Restart;
        }

        let choice = g.gen_range(0, 8);

        match choice {
            0 => Set(Key::arbitrary(g), g.gen::<u8>()),
            1 => Merge(Key::arbitrary(g), g.gen::<u8>()),
            2 => Get(Key::arbitrary(g)),
            3 => GetLt(Key::arbitrary(g)),
            4 => GetGt(Key::arbitrary(g)),
            5 => Del(Key::arbitrary(g)),
            6 => Cas(Key::arbitrary(g), g.gen::<u8>(), g.gen::<u8>()),
            7 => Scan(Key::arbitrary(g), g.gen_range(-40, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        match *self {
            Set(ref k, v) => Box::new(k.shrink().map(move |sk| Set(sk, v))),
            Merge(ref k, v) => Box::new(k.shrink().flat_map(move |k| {
                vec![Set(k.clone(), v.clone()), Merge(k, v)]
            })),
            Get(ref k) => Box::new(k.shrink().map(Get)),
            GetLt(ref k) => Box::new(k.shrink().map(GetLt)),
            GetGt(ref k) => Box::new(k.shrink().map(GetGt)),
            Cas(ref k, old, new) => {
                Box::new(k.shrink().map(move |k| Cas(k, old, new)))
            }
            Scan(ref k, len) => Box::new(k.shrink().map(move |k| Scan(k, len))),
            Del(ref k) => Box::new(k.shrink().map(Del)),
            Restart => Box::new(vec![].into_iter()),
        }
    }
}

fn bytes_to_u16(v: &[u8]) -> u16 {
    assert_eq!(v.len(), 2);
    (u16::from(v[0]) << 8) + u16::from(v[1])
}

fn u16_to_bytes(u: u16) -> Vec<u8> {
    u.to_be_bytes().to_vec()
}

// just adds up values as if they were u16's
fn test_merge_operator(
    _k: &[u8],
    old: Option<&[u8]>,
    to_merge: &[u8],
) -> Option<Vec<u8>> {
    let base = old.unwrap_or(&[0, 0]);
    let base_n = bytes_to_u16(base);
    let new_n = base_n + u16::from(to_merge[0]);
    let ret = u16_to_bytes(new_n);
    Some(ret)
}

pub fn prop_tree_matches_btreemap(
    ops: Vec<Op>,
    flusher: bool,
    use_compression: bool,
    cache_bits: u8,
    segment_size_bits: u8,
) -> bool {
    if let Err(e) = prop_tree_matches_btreemap_inner(
        ops,
        flusher,
        use_compression,
        cache_bits,
        segment_size_bits,
    ) {
        eprintln!("hit error while running quickcheck on tree: {:?}", e);
        false
    } else {
        true
    }
}

fn prop_tree_matches_btreemap_inner(
    ops: Vec<Op>,
    flusher: bool,
    use_compression: bool,
    cache_bits: u8,
    segment_size_bits: u8,
) -> Result<()> {
    use self::*;

    super::common::setup_logger();

    let use_compression = cfg!(feature = "compression") && use_compression;

    let config = Config::new()
        .temporary(true)
        .use_compression(use_compression)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .cache_capacity(256 * (1 << (cache_bits as usize % 16)))
        .idgen_persist_interval(1)
        .segment_size(256 * (1 << (segment_size_bits as usize % 16)));

    let mut tree = config.open().unwrap();
    tree.set_merge_operator(test_merge_operator);

    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops {
        match op {
            Set(k, v) => {
                let old_actual = tree.insert(&k.0, vec![0, v]).unwrap();
                let old_reference = reference.insert(k.clone(), u16::from(v));
                assert_eq!(
                    old_actual.map(|v| bytes_to_u16(&*v)),
                    old_reference,
                    "when setting key {:?}, expected old returned value to be {:?}\n{:?}",
                    k,
                    old_reference,
                    tree
                );
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let entry = reference.entry(k).or_insert(0_u16);
                *entry += u16::from(v);
            }
            Get(k) => {
                let res1 = tree.get(&*k.0).unwrap().map(|v| bytes_to_u16(&*v));
                let res2 = reference.get(&k).cloned();
                assert_eq!(res1, res2);
            }
            GetLt(k) => {
                let res1 = tree.get_lt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .rev()
                    .filter(|(key, _)| **key < k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_lt({:?}) should have returned {:?} \
                     but it returned {:?} instead. \
                     \n Db: {:?}",
                    k, res2, res1, tree
                );
            }
            GetGt(k) => {
                let res1 = tree.get_gt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .filter(|(key, _)| **key > k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_gt({:?}) expected {:?} in tree {:?}",
                    k, res2, tree
                );
            }
            Del(k) => {
                tree.remove(&*k.0).unwrap();
                reference.remove(&k);
            }
            Cas(k, old, new) => {
                let tree_old = tree.get(&*k.0).unwrap();
                if let Some(old_tree) = tree_old {
                    if old_tree == *vec![0, old] {
                        tree.insert(&k.0, vec![0, new]).unwrap();
                    }
                }

                let ref_old = reference.get(&k).cloned();
                if ref_old == Some(u16::from(old)) {
                    reference.insert(k, u16::from(new));
                }
            }
            Scan(k, len) => {
                if len > 0 {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                } else {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .rev()
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .rev()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while reverse iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                }
            }
            Restart => {
                drop(tree);
                tree = config.open().unwrap();
                tree.set_merge_operator(test_merge_operator);
            }
        }
        if let Err(e) = config.global_error() {
            eprintln!("quickcheck test encountered error: {:?}", e);
            return Err(e);
        }
    }

    let space_amplification = tree
        .space_amplification()
        .expect("should be able to read files and pages");

    assert!(
        space_amplification < MAX_SPACE_AMPLIFICATION,
        "space amplification was measured to be {}, \
         which is higher than the maximum of {}",
        space_amplification,
        MAX_SPACE_AMPLIFICATION
    );

    drop(tree);
    config.global_error()
}

#[test]
fn test_fuzz_test() {
    let seed = [0; 32];
    fuzz_then_shrink(&seed);
    let seed = [0; 31];
    fuzz_then_shrink(&seed);
    let seed = [0; 33];
    fuzz_then_shrink(&seed);
    fuzz_then_shrink(&[]);
}
<commit_msg>Exclude compression in tests<commit_after>use std::{collections::BTreeMap, convert::TryInto, fmt, panic};

use quickcheck::{Arbitrary, Gen, RngCore};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand_distr::{Distribution, Gamma};

use sled::*;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Key(pub Vec<u8>);

impl fmt::Debug for Key {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.0.len() > 0 {
            write!(
                f,
                "Key(vec![{}; {}])",
                self.0.get(0).copied().unwrap_or(0),
                self.0.len()
            )
        } else {
            write!(f, "Key(vec!{:?})", self.0)
        }
    }
}

struct SledGen {
    r: StdRng,
    size: usize,
}

impl Gen for SledGen {
    fn size(&self) -> usize {
        self.size
    }
}

impl RngCore for SledGen {
    fn next_u32(&mut self) -> u32 {
        self.r.gen::<u32>()
    }

    fn next_u64(&mut self) -> u64 {
        self.r.gen::<u64>()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.r.fill_bytes(dest)
    }

    fn try_fill_bytes(
        &mut self,
        dest: &mut [u8],
    ) -> std::result::Result<(), rand::Error> {
        self.r.try_fill_bytes(dest)
    }
}

pub fn fuzz_then_shrink(buf: &[u8]) {
    let use_compression =
        cfg!(feature = "compression") && !cfg!(miri) && buf.get(0).unwrap_or(&0) % 2 == 0;

    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0_u8; 32];
            seed[0..chunk.len()].copy_from_slice(chunk);
            let rng: StdRng = SeedableRng::from_seed(seed);
            let mut sled_rng = SledGen { r: rng, size: 2 };

            Op::arbitrary(&mut sled_rng)
        })
        .collect();

    let cache_bits = *buf.get(1).unwrap_or(&0);
    let segment_size_bits = *buf.get(2).unwrap_or(&0);

    match panic::catch_unwind(move || {
        prop_tree_matches_btreemap(
            ops,
            false,
            use_compression,
            cache_bits,
            segment_size_bits,
        )
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    #![allow(clippy::cast_possible_truncation)]
    #![allow(clippy::cast_precision_loss)]
    #![allow(clippy::cast_sign_loss)]

    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen::<bool>() {
            let gs = g.size();
            let gamma = Gamma::new(0.3, gs as f64).unwrap();
            let v = gamma.sample(&mut rand::thread_rng());
            let len = if v > 3000.0 { 10000 } else { (v % 300.) as usize };

            let space = g.gen_range(0, gs) + 1;

            let inner = (0..len).map(|_| g.gen_range(0, space) as u8).collect();

            Self(inner)
        } else {
            let len = g.gen_range(0, 2);
            let mut inner = vec![];

            for _ in 0..len {
                inner.push(g.gen::<u8>());
            }

            Self(inner)
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        // we only want to shrink on length, not byte values
        Box::new(
            self.0
                .len()
                .shrink()
                .zip(std::iter::repeat(self.0.clone()))
                .map(|(len, underlying)| Self(underlying[..len].to_vec())),
        )
    }
}

#[derive(Debug, Clone)]
pub enum Op {
    Set(Key, u8),
    Merge(Key, u8),
    Get(Key),
    GetLt(Key),
    GetGt(Key),
    Del(Key),
    Cas(Key, u8, u8),
    Scan(Key, isize),
    Restart,
}

use self::Op::{Cas, Del, Get, GetGt, GetLt, Merge, Restart, Scan, Set};

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen_bool(1. / 10.) {
            return Restart;
        }

        let choice = g.gen_range(0, 8);

        match choice {
            0 => Set(Key::arbitrary(g), g.gen::<u8>()),
            1 => Merge(Key::arbitrary(g), g.gen::<u8>()),
            2 => Get(Key::arbitrary(g)),
            3 => GetLt(Key::arbitrary(g)),
            4 => GetGt(Key::arbitrary(g)),
            5 => Del(Key::arbitrary(g)),
            6 => Cas(Key::arbitrary(g), g.gen::<u8>(), g.gen::<u8>()),
            7 => Scan(Key::arbitrary(g), g.gen_range(-40, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        match *self {
            Set(ref k, v) => Box::new(k.shrink().map(move |sk| Set(sk, v))),
            Merge(ref k, v) => Box::new(k.shrink().flat_map(move |k| {
                vec![Set(k.clone(), v.clone()), Merge(k, v)]
            })),
            Get(ref k) => Box::new(k.shrink().map(Get)),
            GetLt(ref k) => Box::new(k.shrink().map(GetLt)),
            GetGt(ref k) => Box::new(k.shrink().map(GetGt)),
            Cas(ref k, old, new) => {
                Box::new(k.shrink().map(move |k| Cas(k, old, new)))
            }
            Scan(ref k, len) => Box::new(k.shrink().map(move |k| Scan(k, len))),
            Del(ref k) => Box::new(k.shrink().map(Del)),
            Restart => Box::new(vec![].into_iter()),
        }
    }
}

fn bytes_to_u16(v: &[u8]) -> u16 {
    assert_eq!(v.len(), 2);
    (u16::from(v[0]) << 8) + u16::from(v[1])
}

fn u16_to_bytes(u: u16) -> Vec<u8> {
    u.to_be_bytes().to_vec()
}

// just adds up values as if they were u16's
fn test_merge_operator(
    _k: &[u8],
    old: Option<&[u8]>,
    to_merge: &[u8],
) -> Option<Vec<u8>> {
    let base = old.unwrap_or(&[0, 0]);
    let base_n = bytes_to_u16(base);
    let new_n = base_n + u16::from(to_merge[0]);
    let ret = u16_to_bytes(new_n);
    Some(ret)
}

pub fn prop_tree_matches_btreemap(
    ops: Vec<Op>,
    flusher: bool,
    use_compression: bool,
    cache_bits: u8,
    segment_size_bits: u8,
) -> bool {
    if let Err(e) = prop_tree_matches_btreemap_inner(
        ops,
        flusher,
        use_compression,
        cache_bits,
        segment_size_bits,
    ) {
        eprintln!("hit error while running quickcheck on tree: {:?}", e);
        false
    } else {
        true
    }
}

fn prop_tree_matches_btreemap_inner(
    ops: Vec<Op>,
    flusher: bool,
    use_compression: bool,
    cache_bits: u8,
    segment_size_bits: u8,
) -> Result<()> {
    use self::*;

    super::common::setup_logger();

    let use_compression = cfg!(feature = "compression") && use_compression;

    let config = Config::new()
        .temporary(true)
        .use_compression(use_compression)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .cache_capacity(256 * (1 << (cache_bits as usize % 16)))
        .idgen_persist_interval(1)
        .segment_size(256 * (1 << (segment_size_bits as usize % 16)));

    let mut tree = config.open().unwrap();
    tree.set_merge_operator(test_merge_operator);

    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops {
        match op {
            Set(k, v) => {
                let old_actual = tree.insert(&k.0, vec![0, v]).unwrap();
                let old_reference = reference.insert(k.clone(), u16::from(v));
                assert_eq!(
                    old_actual.map(|v| bytes_to_u16(&*v)),
                    old_reference,
                    "when setting key {:?}, expected old returned value to be {:?}\n{:?}",
                    k,
                    old_reference,
                    tree
                );
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let entry = reference.entry(k).or_insert(0_u16);
                *entry += u16::from(v);
            }
            Get(k) => {
                let res1 = tree.get(&*k.0).unwrap().map(|v| bytes_to_u16(&*v));
                let res2 = reference.get(&k).cloned();
                assert_eq!(res1, res2);
            }
            GetLt(k) => {
                let res1 = tree.get_lt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .rev()
                    .filter(|(key, _)| **key < k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_lt({:?}) should have returned {:?} \
                     but it returned {:?} instead. \
                     \n Db: {:?}",
                    k, res2, res1, tree
                );
            }
            GetGt(k) => {
                let res1 = tree.get_gt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .filter(|(key, _)| **key > k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_gt({:?}) expected {:?} in tree {:?}",
                    k, res2, tree
                );
            }
            Del(k) => {
                tree.remove(&*k.0).unwrap();
                reference.remove(&k);
            }
            Cas(k, old, new) => {
                let tree_old = tree.get(&*k.0).unwrap();
                if let Some(old_tree) = tree_old {
                    if old_tree == *vec![0, old] {
                        tree.insert(&k.0, vec![0, new]).unwrap();
                    }
                }

                let ref_old = reference.get(&k).cloned();
                if ref_old == Some(u16::from(old)) {
                    reference.insert(k, u16::from(new));
                }
            }
            Scan(k, len) => {
                if len > 0 {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                } else {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .rev()
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .rev()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while reverse iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                }
            }
            Restart => {
                drop(tree);
                tree = config.open().unwrap();
                tree.set_merge_operator(test_merge_operator);
            }
        }
        if let Err(e) = config.global_error() {
            eprintln!("quickcheck test encountered error: {:?}", e);
            return Err(e);
        }
    }

    let space_amplification = tree
        .space_amplification()
        .expect("should be able to read files and pages");

    assert!(
        space_amplification < MAX_SPACE_AMPLIFICATION,
        "space amplification was measured to be {}, \
         which is higher than the maximum of {}",
        space_amplification,
        MAX_SPACE_AMPLIFICATION
    );

    drop(tree);
    config.global_error()
}

#[test]
fn test_fuzz_test() {
    let seed = [0; 32];
    fuzz_then_shrink(&seed);
    let seed = [0; 31];
    fuzz_then_shrink(&seed);
    let seed = [0; 33];
    fuzz_then_shrink(&seed);
    fuzz_then_shrink(&[]);
}
<|endoftext|>