<commit_before>use std::mem::size_of;
use std::ptr;

use crossfont::RasterizedGlyph;
use log::info;

use alacritty_terminal::term::cell::Flags;

use crate::display::content::RenderableCell;
use crate::display::SizeInfo;
use crate::gl;
use crate::gl::types::*;
use crate::renderer::shader::{ShaderProgram, ShaderVersion};
use crate::renderer::{cstr, Error};

use super::atlas::{Atlas, ATLAS_SIZE};
use super::{
    Glyph, LoadGlyph, LoaderApi, RenderingGlyphFlags, RenderingPass, TextRenderApi,
    TextRenderBatch, TextRenderer, TextShader,
};

// Shader source.
pub static TEXT_SHADER_F: &str = include_str!("../../../res/glsl3/text.f.glsl");
static TEXT_SHADER_V: &str = include_str!("../../../res/glsl3/text.v.glsl");

/// Maximum items to be drawn in a batch.
const BATCH_MAX: usize = 0x1_0000;

#[derive(Debug)]
pub struct Glsl3Renderer {
    program: TextShaderProgram,
    vao: GLuint,
    ebo: GLuint,
    vbo_instance: GLuint,
    atlas: Vec<Atlas>,
    current_atlas: usize,
    active_tex: GLuint,
    batch: Batch,
}

impl Glsl3Renderer {
    pub fn new() -> Result<Self, Error> {
        info!("Using OpenGL 3.3 renderer");

        let program = TextShaderProgram::new(ShaderVersion::Glsl3)?;
        let mut vao: GLuint = 0;
        let mut ebo: GLuint = 0;
        let mut vbo_instance: GLuint = 0;

        unsafe {
            gl::Enable(gl::BLEND);
            gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
            gl::Enable(gl::MULTISAMPLE);

            // Disable depth mask, as the renderer never uses depth tests.
            gl::DepthMask(gl::FALSE);

            gl::GenVertexArrays(1, &mut vao);
            gl::GenBuffers(1, &mut ebo);
            gl::GenBuffers(1, &mut vbo_instance);
            gl::BindVertexArray(vao);

            // ---------------------
            // Set up element buffer
            // ---------------------
            let indices: [u32; 6] = [0, 1, 3, 1, 2, 3];

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
            gl::BufferData(
                gl::ELEMENT_ARRAY_BUFFER,
                (6 * size_of::<u32>()) as isize,
                indices.as_ptr() as *const _,
                gl::STATIC_DRAW,
            );

            // ----------------------------
            // Setup vertex instance buffer
            // ----------------------------
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo_instance);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                (BATCH_MAX * size_of::<InstanceData>()) as isize,
                ptr::null(),
                gl::STREAM_DRAW,
            );

            let mut index = 0;
            let mut size = 0;

            macro_rules! add_attr {
                ($count:expr, $gl_type:expr, $type:ty) => {
                    gl::VertexAttribPointer(
                        index,
                        $count,
                        $gl_type,
                        gl::FALSE,
                        size_of::<InstanceData>() as i32,
                        size as *const _,
                    );
                    gl::EnableVertexAttribArray(index);
                    gl::VertexAttribDivisor(index, 1);

                    #[allow(unused_assignments)]
                    {
                        size += $count * size_of::<$type>();
                        index += 1;
                    }
                };
            }

            // Coords.
            add_attr!(2, gl::UNSIGNED_SHORT, u16);

            // Glyph offset and size.
            add_attr!(4, gl::SHORT, i16);

            // UV offset.
            add_attr!(4, gl::FLOAT, f32);

            // Color and cell flags.
            //
            // These are packed together because of an OpenGL driver issue on macOS, which caused a
            // `vec3(u8)` text color and a `u8` cell flags to increase the rendering time by a
            // huge margin.
            add_attr!(4, gl::UNSIGNED_BYTE, u8);

            // Background color.
            add_attr!(4, gl::UNSIGNED_BYTE, u8);

            // Cleanup.
            gl::BindVertexArray(0);
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
        }

        Ok(Self {
            program,
            vao,
            ebo,
            vbo_instance,
            atlas: vec![Atlas::new(ATLAS_SIZE)],
            current_atlas: 0,
            active_tex: 0,
            batch: Batch::new(),
        })
    }
}

impl<'a> TextRenderer<'a> for Glsl3Renderer {
    type RenderApi = RenderApi<'a>;
    type RenderBatch = Batch;
    type Shader = TextShaderProgram;

    fn with_api<'b: 'a, F, T>(&'b mut self, size_info: &'b SizeInfo, func: F) -> T
    where
        F: FnOnce(Self::RenderApi) -> T,
    {
        unsafe {
            gl::UseProgram(self.program.id());
            self.program.set_term_uniforms(size_info);

            gl::BindVertexArray(self.vao);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);
            gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo_instance);
            gl::ActiveTexture(gl::TEXTURE0);
        }

        let res = func(RenderApi {
            active_tex: &mut self.active_tex,
            batch: &mut self.batch,
            atlas: &mut self.atlas,
            current_atlas: &mut self.current_atlas,
            program: &mut self.program,
        });

        unsafe {
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindVertexArray(0);

            gl::UseProgram(0);
        }

        res
    }

    fn program(&self) -> &Self::Shader {
        &self.program
    }

    fn loader_api(&mut self) -> LoaderApi<'_> {
        LoaderApi {
            active_tex: &mut self.active_tex,
            atlas: &mut self.atlas,
            current_atlas: &mut self.current_atlas,
        }
    }
}

impl Drop for Glsl3Renderer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.vbo_instance);
            gl::DeleteBuffers(1, &self.ebo);
            gl::DeleteVertexArrays(1, &self.vao);
        }
    }
}

#[derive(Debug)]
pub struct RenderApi<'a> {
    active_tex: &'a mut GLuint,
    batch: &'a mut Batch,
    atlas: &'a mut Vec<Atlas>,
    current_atlas: &'a mut usize,
    program: &'a mut TextShaderProgram,
}

impl<'a> TextRenderApi<Batch> for RenderApi<'a> {
    fn batch(&mut self) -> &mut Batch {
        self.batch
    }

    fn render_batch(&mut self) {
        unsafe {
            gl::BufferSubData(
                gl::ARRAY_BUFFER,
                0,
                self.batch.size() as isize,
                self.batch.instances.as_ptr() as *const _,
            );
        }

        // Bind texture if necessary.
        if *self.active_tex != self.batch.tex() {
            unsafe {
                gl::BindTexture(gl::TEXTURE_2D, self.batch.tex());
            }
            *self.active_tex = self.batch.tex();
        }

        unsafe {
            self.program.set_rendering_pass(RenderingPass::Background);
            gl::DrawElementsInstanced(
                gl::TRIANGLES,
                6,
                gl::UNSIGNED_INT,
                ptr::null(),
                self.batch.len() as GLsizei,
            );
            self.program.set_rendering_pass(RenderingPass::SubpixelPass1);
            gl::DrawElementsInstanced(
                gl::TRIANGLES,
                6,
                gl::UNSIGNED_INT,
                ptr::null(),
                self.batch.len() as GLsizei,
            );
        }

        self.batch.clear();
    }
}

impl<'a> LoadGlyph for RenderApi<'a> {
    fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
        Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized)
    }

    fn clear(&mut self) {
        Atlas::clear_atlas(self.atlas, self.current_atlas)
    }
}

impl<'a> Drop for RenderApi<'a> {
    fn drop(&mut self) {
        if !self.batch.is_empty() {
            self.render_batch();
        }
    }
}

#[derive(Debug)]
#[repr(C)]
struct InstanceData {
    // Coords.
    col: u16,
    row: u16,

    // Glyph offset.
    left: i16,
    top: i16,

    // Glyph size.
    width: i16,
    height: i16,

    // UV offset.
    uv_left: f32,
    uv_bot: f32,

    // uv scale.
    uv_width: f32,
    uv_height: f32,

    // Color.
    r: u8,
    g: u8,
    b: u8,

    // Cell flags like multicolor or fullwidth character.
    cell_flags: RenderingGlyphFlags,

    // Background color.
    bg_r: u8,
    bg_g: u8,
    bg_b: u8,
    bg_a: u8,
}

#[derive(Debug, Default)]
pub struct Batch {
    tex: GLuint,
    instances: Vec<InstanceData>,
}

impl TextRenderBatch for Batch {
    #[inline]
    fn tex(&self) -> GLuint {
        self.tex
    }

    #[inline]
    fn full(&self) -> bool {
        self.capacity() == self.len()
    }

    #[inline]
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    fn add_item(&mut self, cell: &RenderableCell, glyph: &Glyph, _: &SizeInfo) {
        if self.is_empty() {
            self.tex = glyph.tex_id;
        }

        let mut cell_flags = RenderingGlyphFlags::empty();
        cell_flags.set(RenderingGlyphFlags::COLORED, glyph.multicolor);
        cell_flags.set(RenderingGlyphFlags::WIDE_CHAR, cell.flags.contains(Flags::WIDE_CHAR));

        self.instances.push(InstanceData {
            col: cell.point.column.0 as u16,
            row: cell.point.line as u16,

            top: glyph.top,
            left: glyph.left,
            width: glyph.width,
            height: glyph.height,

            uv_bot: glyph.uv_bot,
            uv_left: glyph.uv_left,
            uv_width: glyph.uv_width,
            uv_height: glyph.uv_height,

            r: cell.fg.r,
            g: cell.fg.g,
            b: cell.fg.b,
            cell_flags,

            bg_r: cell.bg.r,
            bg_g: cell.bg.g,
            bg_b: cell.bg.b,
            bg_a: (cell.bg_alpha * 255.0) as u8,
        });
    }
}

impl Batch {
    #[inline]
    pub fn new() -> Self {
        Self { tex: 0, instances: Vec::with_capacity(BATCH_MAX) }
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.instances.len()
    }

    #[inline]
    pub fn capacity(&self) -> usize {
        BATCH_MAX
    }

    #[inline]
    pub fn size(&self) -> usize {
        self.len() * size_of::<InstanceData>()
    }

    pub fn clear(&mut self) {
        self.tex = 0;
        self.instances.clear();
    }
}

/// Text drawing program.
///
/// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a".
#[derive(Debug)]
pub struct TextShaderProgram {
    /// Shader program.
    program: ShaderProgram,

    /// Projection scale and offset uniform.
    u_projection: GLint,

    /// Cell dimensions (pixels).
    u_cell_dim: GLint,

    /// Background pass flag.
    ///
    /// Rendering is split into two passes; one for backgrounds, and one for text.
    u_rendering_pass: GLint,
}

impl TextShaderProgram {
    pub fn new(shader_version: ShaderVersion) -> Result<TextShaderProgram, Error> {
        let program = ShaderProgram::new(shader_version, TEXT_SHADER_V, TEXT_SHADER_F)?;
        Ok(Self {
            u_projection: program.get_uniform_location(cstr!("projection"))?,
            u_cell_dim: program.get_uniform_location(cstr!("cellDim"))?,
            u_rendering_pass: program.get_uniform_location(cstr!("renderingPass"))?,
            program,
        })
    }

    fn set_term_uniforms(&self, props: &SizeInfo) {
        unsafe {
            gl::Uniform2f(self.u_cell_dim, props.cell_width(), props.cell_height());
        }
    }

    fn set_rendering_pass(&self, rendering_pass: RenderingPass) {
        let value = match rendering_pass {
            RenderingPass::Background | RenderingPass::SubpixelPass1 => rendering_pass as i32,
            _ => unreachable!("provided pass is not supported in GLSL3 renderer"),
        };

        unsafe {
            gl::Uniform1i(self.u_rendering_pass, value);
        }
    }
}

impl TextShader for TextShaderProgram {
    fn id(&self) -> GLuint {
        self.program.id()
    }

    fn projection_uniform(&self) -> GLint {
        self.u_projection
    }
}
<commit_msg>Don't enable multisampling<commit_after>use std::mem::size_of;
use std::ptr;

use crossfont::RasterizedGlyph;
use log::info;

use alacritty_terminal::term::cell::Flags;

use crate::display::content::RenderableCell;
use crate::display::SizeInfo;
use crate::gl;
use crate::gl::types::*;
use crate::renderer::shader::{ShaderProgram, ShaderVersion};
use crate::renderer::{cstr, Error};

use super::atlas::{Atlas, ATLAS_SIZE};
use super::{
    Glyph, LoadGlyph, LoaderApi, RenderingGlyphFlags, RenderingPass, TextRenderApi,
    TextRenderBatch, TextRenderer, TextShader,
};

// Shader source.
pub static TEXT_SHADER_F: &str = include_str!("../../../res/glsl3/text.f.glsl");
static TEXT_SHADER_V: &str = include_str!("../../../res/glsl3/text.v.glsl");

/// Maximum items to be drawn in a batch.
const BATCH_MAX: usize = 0x1_0000;

#[derive(Debug)]
pub struct Glsl3Renderer {
    program: TextShaderProgram,
    vao: GLuint,
    ebo: GLuint,
    vbo_instance: GLuint,
    atlas: Vec<Atlas>,
    current_atlas: usize,
    active_tex: GLuint,
    batch: Batch,
}

impl Glsl3Renderer {
    pub fn new() -> Result<Self, Error> {
        info!("Using OpenGL 3.3 renderer");

        let program = TextShaderProgram::new(ShaderVersion::Glsl3)?;
        let mut vao: GLuint = 0;
        let mut ebo: GLuint = 0;
        let mut vbo_instance: GLuint = 0;

        unsafe {
            gl::Enable(gl::BLEND);
            gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);

            // Disable depth mask, as the renderer never uses depth tests.
            gl::DepthMask(gl::FALSE);

            gl::GenVertexArrays(1, &mut vao);
            gl::GenBuffers(1, &mut ebo);
            gl::GenBuffers(1, &mut vbo_instance);
            gl::BindVertexArray(vao);

            // ---------------------
            // Set up element buffer
            // ---------------------
            let indices: [u32; 6] = [0, 1, 3, 1, 2, 3];

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
            gl::BufferData(
                gl::ELEMENT_ARRAY_BUFFER,
                (6 * size_of::<u32>()) as isize,
                indices.as_ptr() as *const _,
                gl::STATIC_DRAW,
            );

            // ----------------------------
            // Setup vertex instance buffer
            // ----------------------------
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo_instance);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                (BATCH_MAX * size_of::<InstanceData>()) as isize,
                ptr::null(),
                gl::STREAM_DRAW,
            );

            let mut index = 0;
            let mut size = 0;

            macro_rules! add_attr {
                ($count:expr, $gl_type:expr, $type:ty) => {
                    gl::VertexAttribPointer(
                        index,
                        $count,
                        $gl_type,
                        gl::FALSE,
                        size_of::<InstanceData>() as i32,
                        size as *const _,
                    );
                    gl::EnableVertexAttribArray(index);
                    gl::VertexAttribDivisor(index, 1);

                    #[allow(unused_assignments)]
                    {
                        size += $count * size_of::<$type>();
                        index += 1;
                    }
                };
            }

            // Coords.
            add_attr!(2, gl::UNSIGNED_SHORT, u16);

            // Glyph offset and size.
            add_attr!(4, gl::SHORT, i16);

            // UV offset.
            add_attr!(4, gl::FLOAT, f32);

            // Color and cell flags.
            //
            // These are packed together because of an OpenGL driver issue on macOS, which caused a
            // `vec3(u8)` text color and a `u8` cell flags to increase the rendering time by a
            // huge margin.
            add_attr!(4, gl::UNSIGNED_BYTE, u8);

            // Background color.
            add_attr!(4, gl::UNSIGNED_BYTE, u8);

            // Cleanup.
            gl::BindVertexArray(0);
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
        }

        Ok(Self {
            program,
            vao,
            ebo,
            vbo_instance,
            atlas: vec![Atlas::new(ATLAS_SIZE)],
            current_atlas: 0,
            active_tex: 0,
            batch: Batch::new(),
        })
    }
}

impl<'a> TextRenderer<'a> for Glsl3Renderer {
    type RenderApi = RenderApi<'a>;
    type RenderBatch = Batch;
    type Shader = TextShaderProgram;

    fn with_api<'b: 'a, F, T>(&'b mut self, size_info: &'b SizeInfo, func: F) -> T
    where
        F: FnOnce(Self::RenderApi) -> T,
    {
        unsafe {
            gl::UseProgram(self.program.id());
            self.program.set_term_uniforms(size_info);

            gl::BindVertexArray(self.vao);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);
            gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo_instance);
            gl::ActiveTexture(gl::TEXTURE0);
        }

        let res = func(RenderApi {
            active_tex: &mut self.active_tex,
            batch: &mut self.batch,
            atlas: &mut self.atlas,
            current_atlas: &mut self.current_atlas,
            program: &mut self.program,
        });

        unsafe {
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindVertexArray(0);

            gl::UseProgram(0);
        }

        res
    }

    fn program(&self) -> &Self::Shader {
        &self.program
    }

    fn loader_api(&mut self) -> LoaderApi<'_> {
        LoaderApi {
            active_tex: &mut self.active_tex,
            atlas: &mut self.atlas,
            current_atlas: &mut self.current_atlas,
        }
    }
}

impl Drop for Glsl3Renderer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.vbo_instance);
            gl::DeleteBuffers(1, &self.ebo);
            gl::DeleteVertexArrays(1, &self.vao);
        }
    }
}

#[derive(Debug)]
pub struct RenderApi<'a> {
    active_tex: &'a mut GLuint,
    batch: &'a mut Batch,
    atlas: &'a mut Vec<Atlas>,
    current_atlas: &'a mut usize,
    program: &'a mut TextShaderProgram,
}

impl<'a> TextRenderApi<Batch> for RenderApi<'a> {
    fn batch(&mut self) -> &mut Batch {
        self.batch
    }

    fn render_batch(&mut self) {
        unsafe {
            gl::BufferSubData(
                gl::ARRAY_BUFFER,
                0,
                self.batch.size() as isize,
                self.batch.instances.as_ptr() as *const _,
            );
        }

        // Bind texture if necessary.
        if *self.active_tex != self.batch.tex() {
            unsafe {
                gl::BindTexture(gl::TEXTURE_2D, self.batch.tex());
            }
            *self.active_tex = self.batch.tex();
        }

        unsafe {
            self.program.set_rendering_pass(RenderingPass::Background);
            gl::DrawElementsInstanced(
                gl::TRIANGLES,
                6,
                gl::UNSIGNED_INT,
                ptr::null(),
                self.batch.len() as GLsizei,
            );
            self.program.set_rendering_pass(RenderingPass::SubpixelPass1);
            gl::DrawElementsInstanced(
                gl::TRIANGLES,
                6,
                gl::UNSIGNED_INT,
                ptr::null(),
                self.batch.len() as GLsizei,
            );
        }

        self.batch.clear();
    }
}

impl<'a> LoadGlyph for RenderApi<'a> {
    fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
        Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized)
    }

    fn clear(&mut self) {
        Atlas::clear_atlas(self.atlas, self.current_atlas)
    }
}

impl<'a> Drop for RenderApi<'a> {
    fn drop(&mut self) {
        if !self.batch.is_empty() {
            self.render_batch();
        }
    }
}

#[derive(Debug)]
#[repr(C)]
struct InstanceData {
    // Coords.
    col: u16,
    row: u16,

    // Glyph offset.
    left: i16,
    top: i16,

    // Glyph size.
    width: i16,
    height: i16,

    // UV offset.
    uv_left: f32,
    uv_bot: f32,

    // uv scale.
    uv_width: f32,
    uv_height: f32,

    // Color.
    r: u8,
    g: u8,
    b: u8,

    // Cell flags like multicolor or fullwidth character.
    cell_flags: RenderingGlyphFlags,

    // Background color.
    bg_r: u8,
    bg_g: u8,
    bg_b: u8,
    bg_a: u8,
}

#[derive(Debug, Default)]
pub struct Batch {
    tex: GLuint,
    instances: Vec<InstanceData>,
}

impl TextRenderBatch for Batch {
    #[inline]
    fn tex(&self) -> GLuint {
        self.tex
    }

    #[inline]
    fn full(&self) -> bool {
        self.capacity() == self.len()
    }

    #[inline]
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    fn add_item(&mut self, cell: &RenderableCell, glyph: &Glyph, _: &SizeInfo) {
        if self.is_empty() {
            self.tex = glyph.tex_id;
        }

        let mut cell_flags = RenderingGlyphFlags::empty();
        cell_flags.set(RenderingGlyphFlags::COLORED, glyph.multicolor);
        cell_flags.set(RenderingGlyphFlags::WIDE_CHAR, cell.flags.contains(Flags::WIDE_CHAR));

        self.instances.push(InstanceData {
            col: cell.point.column.0 as u16,
            row: cell.point.line as u16,

            top: glyph.top,
            left: glyph.left,
            width: glyph.width,
            height: glyph.height,

            uv_bot: glyph.uv_bot,
            uv_left: glyph.uv_left,
            uv_width: glyph.uv_width,
            uv_height: glyph.uv_height,

            r: cell.fg.r,
            g: cell.fg.g,
            b: cell.fg.b,
            cell_flags,

            bg_r: cell.bg.r,
            bg_g: cell.bg.g,
            bg_b: cell.bg.b,
            bg_a: (cell.bg_alpha * 255.0) as u8,
        });
    }
}

impl Batch {
    #[inline]
    pub fn new() -> Self {
        Self { tex: 0, instances: Vec::with_capacity(BATCH_MAX) }
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.instances.len()
    }

    #[inline]
    pub fn capacity(&self) -> usize {
        BATCH_MAX
    }

    #[inline]
    pub fn size(&self) -> usize {
        self.len() * size_of::<InstanceData>()
    }

    pub fn clear(&mut self) {
        self.tex = 0;
        self.instances.clear();
    }
}

/// Text drawing program.
///
/// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a".
#[derive(Debug)]
pub struct TextShaderProgram {
    /// Shader program.
    program: ShaderProgram,

    /// Projection scale and offset uniform.
    u_projection: GLint,

    /// Cell dimensions (pixels).
    u_cell_dim: GLint,

    /// Background pass flag.
    ///
    /// Rendering is split into two passes; one for backgrounds, and one for text.
    u_rendering_pass: GLint,
}

impl TextShaderProgram {
    pub fn new(shader_version: ShaderVersion) -> Result<TextShaderProgram, Error> {
        let program = ShaderProgram::new(shader_version, TEXT_SHADER_V, TEXT_SHADER_F)?;
        Ok(Self {
            u_projection: program.get_uniform_location(cstr!("projection"))?,
            u_cell_dim: program.get_uniform_location(cstr!("cellDim"))?,
            u_rendering_pass: program.get_uniform_location(cstr!("renderingPass"))?,
            program,
        })
    }

    fn set_term_uniforms(&self, props: &SizeInfo) {
        unsafe {
            gl::Uniform2f(self.u_cell_dim, props.cell_width(), props.cell_height());
        }
    }

    fn set_rendering_pass(&self, rendering_pass: RenderingPass) {
        let value = match rendering_pass {
            RenderingPass::Background | RenderingPass::SubpixelPass1 => rendering_pass as i32,
            _ => unreachable!("provided pass is not supported in GLSL3 renderer"),
        };

        unsafe {
            gl::Uniform1i(self.u_rendering_pass, value);
        }
    }
}

impl TextShader for TextShaderProgram {
    fn id(&self) -> GLuint {
        self.program.id()
    }

    fn projection_uniform(&self) -> GLint {
        self.u_projection
    }
}
<|endoftext|>


<commit_before>//	MIT License
//
//  Copyright © 2017 Michael J Simms. All rights reserved.
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in all
//	copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//	SOFTWARE.

extern crate rand;
use rand::distributions::IndependentSample;
use std::collections::HashMap;

/// Each feature has a name and value.
pub struct Feature {
    name: String,
    value: u64,
}

impl Feature {
    pub fn new (name: &str, value: u64) -> Feature {
        Feature { name: name.to_string(), value: value }
    }
}

pub type FeatureList = Vec<Feature>;
pub type Uint64Vec = Vec<u64>;
pub type FeatureNameToValuesMap<'a> = HashMap<&'a String, Uint64Vec>;

/// This class represents a sample.
/// Each sample has a name and list of features.
pub struct Sample {
    name: String,
    features: FeatureList,
}

impl Sample {
    pub fn new (name: &str) -> Sample {
        Sample { name: name.to_string(), features: Sample::create_feature_list() }
    }

    fn create_feature_list() -> FeatureList {
        let v: FeatureList = vec![];
        v
    }

    pub fn add_features(&mut self, features: &mut FeatureList) {
        self.features.append(features);
    }

    pub fn add_feature(&mut self, feature: Feature) {
        self.features.push(feature);
    }
}

pub type SampleList = Vec<Sample>;

/// Tree node, used internally.
struct Node {
    feature_name: String,
    split_value: u64,
    left: NodeLink,
    right: NodeLink,
}

impl Node {
    pub fn new (feature_name: &str, split_value: u64) -> Node {
        Node { feature_name: feature_name.to_string(), split_value: split_value, left: None, right: None }
    }

	fn set_left_subtree(&mut self, subtree: NodeBox) {
		self.left = Some(subtree);
	}

	fn set_right_subtree(&mut self, subtree: NodeBox) {
		self.right = Some(subtree);
	}
}

type NodeBox = Box<Node>;
type NodeLink = Option<Box<Node>>;
type NodeList = Vec<Box<Node>>;

/// Isolation Forest implementation.
pub struct Forest<'a> {
    feature_values: FeatureNameToValuesMap<'a>, // Lists each feature and maps it to all unique values in the training set
    trees: NodeList, // The decision trees that comprise the forest
    num_trees_to_create: u32, // The maximum number of trees to create
    sub_sampling_size: u32, // The maximum depth of a tree
    rng: rand::ThreadRng,
}

impl<'a> Forest<'a> {
    pub fn new (num_trees_to_create: u32, sub_sampling_size: u32) -> Forest<'a> {
        Forest { num_trees_to_create: num_trees_to_create, sub_sampling_size: sub_sampling_size, trees: Forest::initialize_trees(), feature_values: Forest::create_feature_name_to_values_map(), rng: rand::thread_rng() }
    }

    fn initialize_trees() -> NodeList {
        let v: NodeList = vec![];
        v
    }

    fn create_feature_name_to_values_map() -> FeatureNameToValuesMap<'a> {
        let m = FeatureNameToValuesMap::new();
        m
    }

    pub fn add_sample(&mut self, sample: Sample) {
		// Add each of this sample's features to the list of known features
		// with the corresponding set of unique values.

        for feature in &sample.features {
            if self.feature_values.contains_key(&feature.name) {
                let mut feature_value_set = &mut self.feature_values[&feature.name];
                feature_value_set.push(feature.value);
            }
            else {
                let mut feature_value_set = Vec::new();
                feature_value_set.push(feature.value);
                self.feature_values.insert(&feature.name, feature_value_set);
            }
        }
    }

    fn create_tree(&mut self, feature_values: FeatureNameToValuesMap, depth: u32) -> NodeLink {
        // Creates and returns a single tree. As this is a recursive function, depth indicates the current depth of the recursion.

		// Sanity check.
		if feature_values.len() <= 1 {
			return None;
		}

		// If we've exceeded the maximum desired depth, then stop.
		if (self.sub_sampling_size > 0) && (depth >= self.sub_sampling_size) {
			return None;
		}

		// Randomly select a feature.
        let range = rand::distributions::Range::new(0.0, (feature_values.len() as f32) - 1.0);
		let selected_feature_index = range.ind_sample(&mut self.rng) as usize;
        let selected_feature_name = feature_values.keys().nth(selected_feature_index);
        match selected_feature_name {
            None => {
                return None;
            }
            Some(ref name) => {
        		// Randomly select a split value.
                let feature_value_set = &feature_values[*name];
                range = rand::distributions::Range::new(0.0, (feature_value_set.len() - 1) as f32);
                let split_value_index = range.ind_sample(&mut self.rng) as usize;
                let split_value = feature_value_set[split_value_index];

                // Create a tree node to hold the split value.
                let mut tree = Some(Box::new(Node::new(name, split_value)));

                // Create two versions of the feature value set that we just used,
                // one for the left side of the tree and one for the right.
                let temp_feature_values = feature_values.clone();

                // Create the left subtree.

                // Create the right subtree.

                tree
            }
        }
    }

    pub fn create(&mut self) {
        // Creates a forest containing the number of trees specified to the constructor.

    	for _i in 0..self.num_trees_to_create {
            let temp_feature_values = self.feature_values.clone();
            let tree = self.create_tree(temp_feature_values, 0);
            match tree {
                None => {
                }
                Some(ref new_tree) => {
                    self.trees.push(*new_tree);
                }
            }
        }
    }

    fn score_tree(&self, sample: &Sample, tree: &NodeBox) -> f64 {
        // Scores the sample against the specified tree.

        let mut depth = 0.0;
        let mut current_node = tree;
        let mut done = false;

        while !done {
            let mut found_feature = false;

            for feature in &sample.features {
                if feature.name == current_node.feature_name {
					if feature.value < current_node.split_value {
                        match current_node.left {
                            None => {
                                done = true;
                            }
                            Some(ref next_node) => {
                                current_node = next_node;
                            }
                        }
                    } else {
                        match current_node.right {
                            None => {
                                done = true;
                            }
                            Some(ref next_node) => {
                                current_node = next_node;
                            }
                        }
                    }

                    depth = depth + 1.0;
                    found_feature = true;
                }
            }

			// If the tree contained a feature not in the sample then take
			// both sides of the tree and average the scores together.
			if found_feature == false {
                let left_tree = &current_node.left;
                let right_tree = &current_node.right;
                let mut left_depth = depth;
                let mut right_depth = depth;

                match left_tree {
                    &None => {
                    }
                    &Some(ref left_tree) => {
        			    left_depth = left_depth + self.score_tree(sample, left_tree);
                    }
                }
                match right_tree {
                    &None => {
                    }
                    &Some(ref right_tree) => {
        			    right_depth = right_depth + self.score_tree(sample, right_tree);
                    }
                }
				return (left_depth + right_depth) / 2.0;
            }
        }
        depth
    }

    pub fn score(&self, sample: &Sample) -> f64 {
        // Scores the sample against the entire forest of trees.

        let mut score = 0.0;

        if self.trees.len() > 0 {
            for tree in &self.trees {
                score += self.score_tree(sample, tree);
            }
            score /= self.trees.len() as f64;
        }
        score
    }
}
<commit_msg>Backup commit before updating my computer.<commit_after>//	MIT License
//
//  Copyright © 2017 Michael J Simms. All rights reserved.
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in all
//	copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//	SOFTWARE.

extern crate rand;
use rand::distributions::IndependentSample;
use std::collections::HashMap;

/// Each feature has a name and value.
pub struct Feature {
    name: String,
    value: u64,
}

impl Feature {
    pub fn new (name: &str, value: u64) -> Feature {
        Feature { name: name.to_string(), value: value }
    }
}

pub type FeatureList = Vec<Feature>;
pub type Uint64Vec = Vec<u64>;
pub type FeatureNameToValuesMap<'a> = HashMap<&'a String, Uint64Vec>;

/// This class represents a sample.
/// Each sample has a name and list of features.
pub struct Sample {
    name: String,
    features: FeatureList,
}

impl Sample {
    pub fn new (name: &str) -> Sample {
        Sample { name: name.to_string(), features: Sample::create_feature_list() }
    }

    fn create_feature_list() -> FeatureList {
        let v: FeatureList = vec![];
        v
    }

    pub fn add_features(&mut self, features: &mut FeatureList) {
        self.features.append(features);
    }

    pub fn add_feature(&mut self, feature: Feature) {
        self.features.push(feature);
    }
}

pub type SampleList = Vec<Sample>;

/// Tree node, used internally.
struct Node {
    feature_name: String,
    split_value: u64,
    left: NodeLink,
    right: NodeLink,
}

impl Node {
    pub fn new (feature_name: &str, split_value: u64) -> Node {
        Node { feature_name: feature_name.to_string(), split_value: split_value, left: None, right: None }
    }

	fn set_left_subtree(&mut self, subtree: NodeBox) {
		self.left = Some(subtree);
	}

	fn set_right_subtree(&mut self, subtree: NodeBox) {
		self.right = Some(subtree);
	}
}

type NodeBox = Box<Node>;
type NodeLink = Option<Box<Node>>;
type NodeList = Vec<Box<Node>>;

/// Isolation Forest implementation.
pub struct Forest<'a> {
    feature_values: FeatureNameToValuesMap<'a>, // Lists each feature and maps it to all unique values in the training set
    trees: NodeList, // The decision trees that comprise the forest
    num_trees_to_create: u32, // The maximum number of trees to create
    sub_sampling_size: u32, // The maximum depth of a tree
    rng: rand::ThreadRng,
}

impl<'a> Forest<'a> {
    pub fn new (num_trees_to_create: u32, sub_sampling_size: u32) -> Forest<'a> {
        Forest { num_trees_to_create: num_trees_to_create, sub_sampling_size: sub_sampling_size, trees: Forest::initialize_trees(), feature_values: Forest::create_feature_name_to_values_map(), rng: rand::thread_rng() }
    }

    fn initialize_trees() -> NodeList {
        let v: NodeList = vec![];
        v
    }

    fn create_feature_name_to_values_map() -> FeatureNameToValuesMap<'a> {
        let m = FeatureNameToValuesMap::new();
        m
    }

    pub fn add_sample(&mut self, sample: Sample) {
		// Add each of this sample's features to the list of known features
		// with the corresponding set of unique values.

        for feature in &sample.features {
            if self.feature_values.contains_key(&feature.name) {
                let mut feature_value_set = &mut self.feature_values[&feature.name];
                feature_value_set.push(feature.value);
            }
            else {
                let mut feature_value_set = Vec::new();
                feature_value_set.push(feature.value);
                self.feature_values.insert(&feature.name, feature_value_set);
            }
        }
    }

    fn create_tree(&mut self, feature_values: FeatureNameToValuesMap, depth: u32) -> NodeLink {
        // Creates and returns a single tree. As this is a recursive function, depth indicates the current depth of the recursion.

		// Sanity check.
		if feature_values.len() <= 1 {
			return None;
		}

		// If we've exceeded the maximum desired depth, then stop.
		if (self.sub_sampling_size > 0) && (depth >= self.sub_sampling_size) {
			return None;
		}

		// Randomly select a feature.
        let mut range = rand::distributions::Range::new(0.0, (feature_values.len() as f32) - 1.0);
		let selected_feature_index = range.ind_sample(&mut self.rng) as usize;
        let selected_feature_name = feature_values.keys().nth(selected_feature_index);
        match selected_feature_name {
            None => {
                return None;
            }
            Some(ref name) => {
        		// Randomly select a split value.
                let feature_value_set = &feature_values[*name];
                range = rand::distributions::Range::new(0.0, (feature_value_set.len() - 1) as f32);
                let split_value_index = range.ind_sample(&mut self.rng) as usize;
                let split_value = feature_value_set[split_value_index];

                // Create a tree node to hold the split value.
                let mut tree = Some(Box::new(Node::new(name, split_value)));

                // Create two versions of the feature value set that we just used,
                // one for the left side of the tree and one for the right.
                let mut temp_feature_values = feature_values.clone();
                let (left_features, right_features) = feature_value_set.split_at(split_value_index);

                // Create the left subtree.
                temp_feature_values.insert(name, left_features.to_vec());
                let left_subtree = self.create_tree(temp_feature_values, depth + 1);
                tree.set_left_subtree(left_subtree);

                // Create the right subtree.
                temp_feature_values.insert(name, right_features.to_vec());
                let right_subtree = self.create_tree(temp_feature_values, depth + 1);

                tree
            }
        }
    }

    pub fn create(&mut self) {
        // Creates a forest containing the number of trees specified to the constructor.

    	for _i in 0..self.num_trees_to_create {
            let temp_feature_values = self.feature_values.clone();
            let tree = self.create_tree(temp_feature_values, 0);
            match tree {
                None => {
                }
                Some(ref new_tree) => {
                    self.trees.push(*new_tree);
                }
            }
        }
    }

    fn score_tree(&self, sample: &Sample, tree: &NodeBox) -> f64 {
        // Scores the sample against the specified tree.

        let mut depth = 0.0;
        let mut current_node = tree;
        let mut done = false;

        while !done {
            let mut found_feature = false;

            for feature in &sample.features {
                if feature.name == current_node.feature_name {
					if feature.value < current_node.split_value {
                        match current_node.left {
                            None => {
                                done = true;
                            }
                            Some(ref next_node) => {
                                current_node = next_node;
                            }
                        }
                    } else {
                        match current_node.right {
                            None => {
                                done = true;
                            }
                            Some(ref next_node) => {
                                current_node = next_node;
                            }
                        }
                    }

                    depth = depth + 1.0;
                    found_feature = true;
                }
            }

			// If the tree contained a feature not in the sample then take
			// both sides of the tree and average the scores together.
			if found_feature == false {
                let left_tree = &current_node.left;
                let right_tree = &current_node.right;
                let mut left_depth = depth;
                let mut right_depth = depth;

                match left_tree {
                    &None => {
                    }
                    &Some(ref left_tree) => {
        			    left_depth = left_depth + self.score_tree(sample, left_tree);
                    }
                }
                match right_tree {
                    &None => {
                    }
                    &Some(ref right_tree) => {
        			    right_depth = right_depth + self.score_tree(sample, right_tree);
                    }
                }
				return (left_depth + right_depth) / 2.0;
            }
        }
        depth
    }

    pub fn score(&self, sample: &Sample) -> f64 {
        // Scores the sample against the entire forest of trees.

        let mut score = 0.0;

        if self.trees.len() > 0 {
            for tree in &self.trees {
                score += self.score_tree(sample, tree);
            }
            score /= self.trees.len() as f64;
        }
        score
    }
}
<|endoftext|>


<commit_before>use webcore::value::Reference;
use webcore::try_from::TryInto;
use private::TODO;

/// The `Location` interface represents the location (URL) of the object it
/// is linked to. Changes done on it are reflected on the object it relates
/// to. Both the [Document](struct.Document.html) and [Window](struct.Window.html)
/// interface have such a linked `Location`, accessible via [Document::location](struct.Document.html#method.location)
/// and [Window::location](struct.Window.html#method.location) respectively.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location)
// https://html.spec.whatwg.org/#location
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Location")]
pub struct Location( Reference );

impl Location {
    /// The entire URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/href)
    // https://html.spec.whatwg.org/#dom-location-href
    pub fn href( &self ) -> Result< String, TODO > {
        Ok( js!(
            return @{self}.href;
        ).try_into().unwrap() )
    }

    /// Returns a `String` containing a '#' followed by the fragment
    /// identifier of the URL. The fragment is not percent-decoded.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/hash)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-hash
    pub fn hash( &self ) -> Result< String, TODO > {
        Ok( js!(
            return @{self}.hash;
        ).try_into().unwrap() )
    }
}
<commit_msg>Extend `Location` (#192)<commit_after>use webcore::value::Reference;
use webcore::try_from::TryInto;
use webapi::dom_exception::SecurityError;

/// The `Location` interface represents the location (URL) of the object it
/// is linked to. Changes done on it are reflected on the object it relates
/// to. Both the [Document](struct.Document.html) and [Window](struct.Window.html)
/// interface have such a linked `Location`, accessible via [Document::location](struct.Document.html#method.location)
/// and [Window::location](struct.Window.html#method.location) respectively.
///
/// Note that all `Location` methods can return a `SecurityError` if the `Location` object's
/// relevant `Document`'s origin is not same origin-domain with the entry settings object's origin.
/// See: https://html.spec.whatwg.org/#dom-location-href
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location)
// https://html.spec.whatwg.org/#location
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Location")]
pub struct Location( Reference );

impl Location {
    /// The entire URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/href)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-href
    pub fn href( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.href; ).unwrap()
    }

    /// Returns a `String` containing the Unicode serialization of the origin of the represented
    /// URL, that is:
    ///
    /// - For URL using the http or https, the scheme followed by `'://'`, followed by the domain,
    ///   followed by `':'`, followed by the port (the default port, 80 and 443 respectively, if
    ///   explicitely specified);
    /// - For URL using `file: scheme`, the value is browser dependant.
    /// - For URL using the blob: scheme, the origin of the URL following blob:. E.g
    ///   "blob:https://mozilla.org" will have "https://mozilla.org".
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/origin)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-origin
    pub fn origin( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.origin; ).unwrap()
    }

    /// Returns a `String` representing the protocol scheme of the URL, including the final ':'.
    ///
    /// Example: `http:`
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/protocol)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-protocol
    pub fn protocol( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.protocol; ).unwrap()
    }

    /// Returns a `String` containing the host (i.e. hostname) and then, if the port of the
    /// URL is nonempty, a ':', and the port of the URL.
    ///
    /// Example: `hitchhikers.com:4242`
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/host)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-host
    pub fn host( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.host; ).unwrap()
    }

    /// Returns a `String` which is the domain of the URL
    ///
    /// Example: `mozilla.com`
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/hostname)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-hostname
    pub fn hostname( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.hostname; ).unwrap()
    }

    /// Returns a `String` containing the port number or `""` if there is no port.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/port)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-port
    pub fn port( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.port; ).unwrap()
    }

    /// Returns a `String` containing an initial '/' followed by the path of the URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-pathname
    pub fn pathname( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.pathname; ).unwrap()
    }

    /// Returns a `String` which is a search string, also called a query string, that is a `String`
    /// containing a '?' followed by the parameters of the URL.
    ///
    /// These can then be further parsed via another library.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/search)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-search
    pub fn search( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.search; ).unwrap()
    }

    /// Returns a `String` containing a '#' followed by the fragment
    /// identifier of the URL. The fragment is not percent-decoded.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/hash)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-hash
    pub fn hash( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.hash; ).unwrap()
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem;
use std::cell::UnsafeCell;

pub struct ReentrantMutex { inner: UnsafeCell<ffi::pthread_mutex_t> }

unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

impl ReentrantMutex {
    pub unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: mem::uninitialized() }
    }

    pub unsafe fn init(&mut self) {
        let mut attr: ffi::pthread_mutexattr_t = mem::uninitialized();
        let result = ffi::pthread_mutexattr_init(&mut attr as *mut _);
        debug_assert_eq!(result, 0);
        let result = ffi::pthread_mutexattr_settype(&mut attr as *mut _,
                                                    ffi::PTHREAD_MUTEX_RECURSIVE);
        debug_assert_eq!(result, 0);
        let result = ffi::pthread_mutex_init(self.inner.get(), &attr as *const _);
        debug_assert_eq!(result, 0);
        let result = ffi::pthread_mutexattr_destroy(&mut attr as *mut _);
        debug_assert_eq!(result, 0);
    }

    pub unsafe fn lock(&self) {
        let result = ffi::pthread_mutex_lock(self.inner.get());
        debug_assert_eq!(result, 0);
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        ffi::pthread_mutex_trylock(self.inner.get()) == 0
    }

    pub unsafe fn unlock(&self) {
        let result = ffi::pthread_mutex_unlock(self.inner.get());
        debug_assert_eq!(result, 0);
    }

    pub unsafe fn destroy(&self) {
        let result = ffi::pthread_mutex_destroy(self.inner.get());
        debug_assert_eq!(result, 0);
    }
}

mod ffi {
    use libc;
    pub use self::os::{pthread_mutex_t, pthread_mutexattr_t, PTHREAD_MUTEX_RECURSIVE};

    extern {
        pub fn pthread_mutex_init(lock: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t)
                                 -> libc::c_int;
        pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
        pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
        pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
        pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;

        pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> libc::c_int;
        pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> libc::c_int;
        pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: libc::c_int)
                                        -> libc::c_int;
    }

    #[cfg(any(target_os = "freebsd", target_os = "dragonfly",
              target_os = "bitrig",  target_os = "openbsd"))]
    mod os {
        use libc;

        pub type pthread_mutex_t = *mut libc::c_void;
        pub type pthread_mutexattr_t = *mut libc::c_void;
        pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    mod os {
        use libc;

        #[cfg(any(target_arch = "x86_64",
                  target_arch = "aarch64"))]
        const __PTHREAD_MUTEX_SIZE__: usize = 56;
        #[cfg(any(target_arch = "x86",
                  target_arch = "arm"))]
        const __PTHREAD_MUTEX_SIZE__: usize = 40;

        #[repr(C)]
        pub struct pthread_mutex_t {
            __sig: libc::c_long,
            __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
        }
        #[repr(C)]
        pub struct pthread_mutexattr_t {
            __sig: libc::c_long,
            __opaque: [u8; 16],
        }
        pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
    }

    #[cfg(target_os = "linux")]
    mod os {
        use libc;

        #[repr(C)]
        pub struct pthread_mutex_t {
            __align: libc::c_longlong,
            size: [u8; __SIZEOF_PTHREAD_MUTEX_T],
        }
        #[repr(C)]
        pub struct pthread_mutexattr_t {
            __align: libc::c_longlong,
            size: [u8; 16],
        }
        pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
    }

    #[cfg(target_os = "android")]
    mod os {
        use libc;

        #[repr(C)]
        pub struct pthread_mutex_t { value: libc::c_int }
        pub type pthread_mutexattr_t = libc::c_long;
        pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
    }
}
<commit_msg>Add a missing constant in remutex::unix for Linux build<commit_after>// Copyright 2015 The Rust Project Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem;
use std::cell::UnsafeCell;

pub struct ReentrantMutex { inner: UnsafeCell<ffi::pthread_mutex_t> }

unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

impl ReentrantMutex {
    pub unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: mem::uninitialized() }
    }

    pub unsafe fn init(&mut self) {
        let mut attr: ffi::pthread_mutexattr_t = mem::uninitialized();
        let result = ffi::pthread_mutexattr_init(&mut attr as *mut _);
        debug_assert_eq!(result, 0);
        let result = ffi::pthread_mutexattr_settype(&mut attr as *mut _,
                                                    ffi::PTHREAD_MUTEX_RECURSIVE);
        debug_assert_eq!(result, 0);
        let result = ffi::pthread_mutex_init(self.inner.get(), &attr as *const _);
        debug_assert_eq!(result, 0);
        let result = ffi::pthread_mutexattr_destroy(&mut attr as *mut _);
        debug_assert_eq!(result, 0);
    }

    pub unsafe fn lock(&self) {
        let result = ffi::pthread_mutex_lock(self.inner.get());
        debug_assert_eq!(result, 0);
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        ffi::pthread_mutex_trylock(self.inner.get()) == 0
    }

    pub unsafe fn unlock(&self) {
        let result = ffi::pthread_mutex_unlock(self.inner.get());
        debug_assert_eq!(result, 0);
    }

    pub unsafe fn destroy(&self) {
        let result = ffi::pthread_mutex_destroy(self.inner.get());
        debug_assert_eq!(result, 0);
    }
}

mod ffi {
    use libc;
    pub use self::os::{pthread_mutex_t, pthread_mutexattr_t, PTHREAD_MUTEX_RECURSIVE};

    extern {
        pub fn pthread_mutex_init(lock: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t)
                                 -> libc::c_int;
        pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
        pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
        pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
        pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;

        pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> libc::c_int;
        pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> libc::c_int;
        pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: libc::c_int)
                                        -> libc::c_int;
    }

    #[cfg(any(target_os = "freebsd", target_os = "dragonfly",
              target_os = "bitrig",  target_os = "openbsd"))]
    mod os {
        use libc;

        pub type pthread_mutex_t = *mut libc::c_void;
        pub type pthread_mutexattr_t = *mut libc::c_void;
        pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    mod os {
        use libc;

        #[cfg(any(target_arch = "x86_64",
                  target_arch = "aarch64"))]
        const __PTHREAD_MUTEX_SIZE__: usize = 56;
        #[cfg(any(target_arch = "x86",
                  target_arch = "arm"))]
        const __PTHREAD_MUTEX_SIZE__: usize = 40;

        #[repr(C)]
        pub struct pthread_mutex_t {
            __sig: libc::c_long,
            __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
        }
        #[repr(C)]
        pub struct pthread_mutexattr_t {
            __sig: libc::c_long,
            __opaque: [u8; 16],
        }
        pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
    }

    #[cfg(target_os = "linux")]
    mod os {
        use libc;

        #[cfg(target_arch = "x86_64")]
        const __SIZEOF_PTHREAD_MUTEX_T: usize = 40 - 8;
        #[cfg(any(target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "mips",
                  target_arch = "mipsel",
                  target_arch = "powerpc"))]
        const __SIZEOF_PTHREAD_MUTEX_T: usize = 24 - 8;
        #[cfg(target_arch = "aarch64")]
        const __SIZEOF_PTHREAD_MUTEX_T: usize = 48 - 8;

        #[repr(C)]
        pub struct pthread_mutex_t {
            __align: libc::c_longlong,
            size: [u8; __SIZEOF_PTHREAD_MUTEX_T],
        }
        #[repr(C)]
        pub struct pthread_mutexattr_t {
            __align: libc::c_longlong,
            size: [u8; 16],
        }
        pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
    }

    #[cfg(target_os = "android")]
    mod os {
        use libc;

        #[repr(C)]
        pub struct pthread_mutex_t { value: libc::c_int }
        pub type pthread_mutexattr_t = libc::c_long;
        pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
    }
}
<|endoftext|>


<commit_before>extern crate actix;
extern crate actix_web;
extern crate bytes;
extern crate futures;
extern crate flate2;
extern crate rand;

use std::io::Read;

use bytes::Bytes;
use futures::Future;
use futures::stream::once;
use flate2::read::GzDecoder;
use rand::Rng;

use actix_web::*;

const STR: &str =
    "Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World";

#[test]
fn test_simple() {
    let mut srv = test::TestServer::new(
        |app| app.handler(|_| httpcodes::HTTPOk.build().body(STR)));

    let request = srv.get().header("x-test", "111").finish().unwrap();
    let repr = format!("{:?}", request);
    assert!(repr.contains("ClientRequest"));
    assert!(repr.contains("x-test"));

    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));

    let request = srv.post().finish().unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_no_decompress() {
    let mut srv = test::TestServer::new(
        |app| app.handler(|_| httpcodes::HTTPOk.build().body(STR)));

    let request = srv.get().disable_decompress().finish().unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();

    let mut e = GzDecoder::new(&bytes[..]);
    let mut dec = Vec::new();
    e.read_to_end(&mut dec).unwrap();
    assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));

    // POST
    let request = srv.post().disable_decompress().finish().unwrap();
    let response = srv.execute(request.send()).unwrap();

    let bytes = srv.execute(response.body()).unwrap();
    let mut e = GzDecoder::new(&bytes[..]);
    let mut dec = Vec::new();
    e.read_to_end(&mut dec).unwrap();
    assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_gzip_encoding() {
    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Deflate)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Gzip)
        .body(STR).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_gzip_encoding_large() {
    let data = STR.repeat(10);

    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Deflate)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Gzip)
        .body(data.clone()).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from(data));
}

#[test]
fn test_client_gzip_encoding_large_random() {
    let data = rand::thread_rng()
        .gen_ascii_chars()
        .take(100_000)
        .collect::<String>();

    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Deflate)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Gzip)
        .body(data.clone()).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from(data));
}

#[test]
fn test_client_brotli_encoding() {
    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Gzip)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.client(Method::POST, "/")
        .content_encoding(headers::ContentEncoding::Br)
        .body(STR).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_brotli_encoding_large_random() {
    let data = rand::thread_rng()
        .gen_ascii_chars()
        .take(70_000)
        .collect::<String>();

    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(move |bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Gzip)
                   .body(bytes))
            }).responder()}
        ));

    // client request
    let request = srv.client(Method::POST, "/")
        .content_encoding(headers::ContentEncoding::Br)
        .body(data.clone()).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes.len(), data.len());
    assert_eq!(bytes, Bytes::from(data));
}

#[test]
fn test_client_deflate_encoding() {
    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Br)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Deflate)
        .body(STR).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_deflate_encoding_large_random() {
    let data = rand::thread_rng()
        .gen_ascii_chars()
        .take(70_000)
        .collect::<String>();

    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Br)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Deflate)
        .body(data.clone()).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from(data));
}

#[test]
fn test_client_streaming_explicit() {
    let mut srv = test::TestServer::new(
        |app| app.handler(
            |req: HttpRequest| req.body()
                .map_err(Error::from)
                .and_then(|body| {
                    Ok(httpcodes::HTTPOk.build()
                       .chunked()
                       .content_encoding(headers::ContentEncoding::Identity)
                       .body(body)?)})
                .responder()));

    let body = once(Ok(Bytes::from_static(STR.as_ref())));

    let request = srv.get().body(Body::Streaming(Box::new(body))).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_body_streaming_implicit() {
    let mut srv = test::TestServer::new(
        |app| app.handler(|_| {
            let body = once(Ok(Bytes::from_static(STR.as_ref())));
            httpcodes::HTTPOk.build()
                .content_encoding(headers::ContentEncoding::Gzip)
                .body(Body::Streaming(Box::new(body)))}));

    let request = srv.get().finish().unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_cookie_handling() {
    use actix_web::header::Cookie;
    fn err() -> Error {
        use std::io::{ErrorKind, Error as IoError};
        // stub some generic error
        Error::from(IoError::from(ErrorKind::NotFound))
    }
    let cookie1 = Cookie::build("cookie1", "value1").finish();
    let cookie2 = Cookie::build("cookie2", "value2")
        .domain("www.example.org")
        .path("/")
        .secure(true)
        .http_only(true)
        .finish();
    // Q: are all these clones really necessary? A: Yes, possibly
    let cookie1b = cookie1.clone();
    let cookie2b = cookie2.clone();
    let mut srv = test::TestServer::new(
        move |app| {
            let cookie1 = cookie1b.clone();
            let cookie2 = cookie2b.clone();
            app.handler(move |req: HttpRequest| {
                // Check cookies were sent correctly
                req.cookie("cookie1").ok_or_else(err)
                    .and_then(|c1| if c1.value() == "value1" {
                        Ok(())
                    } else {
                        Err(err())
                    })
                    .and_then(|()| req.cookie("cookie2").ok_or_else(err))
                    .and_then(|c2| if c2.value() == "value2" {
                        Ok(())
                    } else {
                        Err(err())
                    })
                    // Send some cookies back
                    .map(|_|
                         httpcodes::HTTPOk.build()
                         .cookie(cookie1.clone())
                         .cookie(cookie2.clone())
                         .finish()
                    )
            })
        });

    let request = srv.get()
        .cookie(cookie1.clone())
        .cookie(cookie2.clone())
        .finish()
        .unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());
    let c1 = response.cookie("cookie1").expect("Missing cookie1");
    assert_eq!(c1, &cookie1);
    let c2 = response.cookie("cookie2").expect("Missing cookie2");
    assert_eq!(c2, &cookie2);
}
<commit_msg>test for query parameters in client<commit_after>extern crate actix;
extern crate actix_web;
extern crate bytes;
extern crate futures;
extern crate flate2;
extern crate rand;

use std::io::Read;

use bytes::Bytes;
use futures::Future;
use futures::stream::once;
use flate2::read::GzDecoder;
use rand::Rng;

use actix_web::*;

const STR: &str =
    "Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World \
     Hello World Hello World Hello World Hello World Hello World";

#[test]
fn test_simple() {
    let mut srv = test::TestServer::new(
        |app| app.handler(|_| httpcodes::HTTPOk.build().body(STR)));

    let request = srv.get().header("x-test", "111").finish().unwrap();
    let repr = format!("{:?}", request);
    assert!(repr.contains("ClientRequest"));
    assert!(repr.contains("x-test"));

    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));

    let request = srv.post().finish().unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_with_query_parameter() {
    let mut srv = test::TestServer::new(
        |app| app.handler(|req: HttpRequest| match req.query().get("qp") {
            Some(_) => httpcodes::HTTPOk.build().finish(),
            None => httpcodes::HTTPBadRequest.build().finish(),
        }));

    let request = srv.get().uri(srv.url("/?qp=5").as_str()).finish().unwrap();

    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());
}

#[test]
fn test_no_decompress() {
    let mut srv = test::TestServer::new(
        |app| app.handler(|_| httpcodes::HTTPOk.build().body(STR)));

    let request = srv.get().disable_decompress().finish().unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();

    let mut e = GzDecoder::new(&bytes[..]);
    let mut dec = Vec::new();
    e.read_to_end(&mut dec).unwrap();
    assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));

    // POST
    let request = srv.post().disable_decompress().finish().unwrap();
    let response = srv.execute(request.send()).unwrap();

    let bytes = srv.execute(response.body()).unwrap();
    let mut e = GzDecoder::new(&bytes[..]);
    let mut dec = Vec::new();
    e.read_to_end(&mut dec).unwrap();
    assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_gzip_encoding() {
    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Deflate)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Gzip)
        .body(STR).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_gzip_encoding_large() {
    let data = STR.repeat(10);

    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Deflate)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Gzip)
        .body(data.clone()).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from(data));
}

#[test]
fn test_client_gzip_encoding_large_random() {
    let data = rand::thread_rng()
        .gen_ascii_chars()
        .take(100_000)
        .collect::<String>();

    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Deflate)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Gzip)
        .body(data.clone()).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from(data));
}

#[test]
fn test_client_brotli_encoding() {
    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Gzip)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.client(Method::POST, "/")
        .content_encoding(headers::ContentEncoding::Br)
        .body(STR).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_brotli_encoding_large_random() {
    let data = rand::thread_rng()
        .gen_ascii_chars()
        .take(70_000)
        .collect::<String>();

    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(move |bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Gzip)
                   .body(bytes))
            }).responder()}
        ));

    // client request
    let request = srv.client(Method::POST, "/")
        .content_encoding(headers::ContentEncoding::Br)
        .body(data.clone()).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes.len(), data.len());
    assert_eq!(bytes, Bytes::from(data));
}

#[test]
fn test_client_deflate_encoding() {
    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Br)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Deflate)
        .body(STR).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_deflate_encoding_large_random() {
    let data = rand::thread_rng()
        .gen_ascii_chars()
        .take(70_000)
        .collect::<String>();

    let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| {
        req.body()
            .and_then(|bytes: Bytes| {
                Ok(httpcodes::HTTPOk
                   .build()
                   .content_encoding(headers::ContentEncoding::Br)
                   .body(bytes))
            }).responder()}
    ));

    // client request
    let request = srv.post()
        .content_encoding(headers::ContentEncoding::Deflate)
        .body(data.clone()).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from(data));
}

#[test]
fn test_client_streaming_explicit() {
    let mut srv = test::TestServer::new(
        |app| app.handler(
            |req: HttpRequest| req.body()
                .map_err(Error::from)
                .and_then(|body| {
                    Ok(httpcodes::HTTPOk.build()
                       .chunked()
                       .content_encoding(headers::ContentEncoding::Identity)
                       .body(body)?)})
                .responder()));

    let body = once(Ok(Bytes::from_static(STR.as_ref())));

    let request = srv.get().body(Body::Streaming(Box::new(body))).unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_body_streaming_implicit() {
    let mut srv = test::TestServer::new(
        |app| app.handler(|_| {
            let body = once(Ok(Bytes::from_static(STR.as_ref())));
            httpcodes::HTTPOk.build()
                .content_encoding(headers::ContentEncoding::Gzip)
                .body(Body::Streaming(Box::new(body)))}));

    let request = srv.get().finish().unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());

    // read response
    let bytes = srv.execute(response.body()).unwrap();
    assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}

#[test]
fn test_client_cookie_handling() {
    use actix_web::header::Cookie;
    fn err() -> Error {
        use std::io::{ErrorKind, Error as IoError};
        // stub some generic error
        Error::from(IoError::from(ErrorKind::NotFound))
    }
    let cookie1 = Cookie::build("cookie1", "value1").finish();
    let cookie2 = Cookie::build("cookie2", "value2")
        .domain("www.example.org")
        .path("/")
        .secure(true)
        .http_only(true)
        .finish();
    // Q: are all these clones really necessary? A: Yes, possibly
    let cookie1b = cookie1.clone();
    let cookie2b = cookie2.clone();
    let mut srv = test::TestServer::new(
        move |app| {
            let cookie1 = cookie1b.clone();
            let cookie2 = cookie2b.clone();
            app.handler(move |req: HttpRequest| {
                // Check cookies were sent correctly
                req.cookie("cookie1").ok_or_else(err)
                    .and_then(|c1| if c1.value() == "value1" {
                        Ok(())
                    } else {
                        Err(err())
                    })
                    .and_then(|()| req.cookie("cookie2").ok_or_else(err))
                    .and_then(|c2| if c2.value() == "value2" {
                        Ok(())
                    } else {
                        Err(err())
                    })
                    // Send some cookies back
                    .map(|_|
                         httpcodes::HTTPOk.build()
                         .cookie(cookie1.clone())
                         .cookie(cookie2.clone())
                         .finish()
                    )
            })
        });

    let request = srv.get()
        .cookie(cookie1.clone())
        .cookie(cookie2.clone())
        .finish()
        .unwrap();
    let response = srv.execute(request.send()).unwrap();
    assert!(response.status().is_success());
    let c1 = response.cookie("cookie1").expect("Missing cookie1");
    assert_eq!(c1, &cookie1);
    let c2 = response.cookie("cookie2").expect("Missing cookie2");
    assert_eq!(c2, &cookie2);
}
<|endoftext|>


<commit_before>#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(slice_patterns)]
#![feature(use_extern_macros)]

extern crate alto;
extern crate any_cache;
extern crate cgmath;
extern crate cheddar;
extern crate chrono;
extern crate clap;
extern crate image;
pub extern crate luminance;
extern crate luminance_glfw;
extern crate luminance_windowing;
extern crate num_traits;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate vorbis;
extern crate wavefront_obj;
extern crate warmy;

// re-exported macros
pub use clap::{crate_authors, crate_name, crate_version};
pub use luminance::{gtup, uniform_interface, uniform_interface_build_struct,
                    uniform_interface_impl_trait, uniform_interface_impl_trait_map};

#[macro_use]
pub mod report;
#[macro_use]
pub mod sys;

pub mod audio;
//pub mod gui;
pub mod linear;
//pub mod overlay;
//pub mod text;

pub mod anim;
pub mod render;
pub mod scene;
<commit_msg>Remove the const_fn feature.<commit_after>#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(slice_patterns)]
#![feature(use_extern_macros)]

extern crate alto;
extern crate any_cache;
extern crate cgmath;
extern crate cheddar;
extern crate chrono;
extern crate clap;
extern crate image;
pub extern crate luminance;
extern crate luminance_glfw;
extern crate luminance_windowing;
extern crate num_traits;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate vorbis;
extern crate wavefront_obj;
extern crate warmy;

// re-exported macros
pub use clap::{crate_authors, crate_name, crate_version};
pub use luminance::{gtup, uniform_interface, uniform_interface_build_struct,
                    uniform_interface_impl_trait, uniform_interface_impl_trait_map};

#[macro_use]
pub mod report;
#[macro_use]
pub mod sys;

pub mod audio;
//pub mod gui;
pub mod linear;
//pub mod overlay;
//pub mod text;

pub mod anim;
pub mod render;
pub mod scene;
<|endoftext|>