<commit_before>use std::{convert};
use std::io::{Cursor, Read};

use byteorder::{self, ReadBytesExt};

#[derive(Debug, PartialEq, Eq)]
pub enum DeserializationError {
    UnexpectedTag,
    ShortData,
    ExtraData,
    IntegerOverflow,
}

impl convert::From<byteorder::Error> for DeserializationError {
    fn from(e: byteorder::Error) -> DeserializationError {
        return match e {
            byteorder::Error::UnexpectedEOF => DeserializationError::ShortData,
            _ => panic!("Unexpected error!"),
        }
    }
}

pub type DeserializationResult<T> = Result<T, DeserializationError>;

pub struct Deserializer {
    reader: Cursor<Vec<u8>>,
}

impl Deserializer {
    pub fn new(data: Vec<u8>) -> Deserializer {
        return Deserializer{
            reader: Cursor::new(data),
        }
    }

    fn _read_length(&mut self) -> DeserializationResult<usize> {
        let b = try!(self.reader.read_u8());
        // TODO: handle lengths greater than 128
        assert!(b & 0x80 == 0);
        return Ok((b & 0x7f) as usize);
    }

    fn _read_with_tag<T, F>(&mut self, expected_tag: u8, body: F) -> DeserializationResult<T>
            where F: Fn(Vec<u8>) -> DeserializationResult<T> {
        let tag = try!(self.reader.read_u8());
        // TODO: only some of the bits in the first byte are for the tag
        if tag != expected_tag {
            return Err(DeserializationError::UnexpectedTag);
        }
        let length = try!(self._read_length());
        let mut data = vec![0; length];
        let n = self.reader.read(&mut data).unwrap();
        if n != length {
            return Err(DeserializationError::ShortData);
        }
        return body(data);
    }

    pub fn finish(self) -> DeserializationResult<()> {
        if self.reader.position() as usize != self.reader.get_ref().len() {
            return Err(DeserializationError::ExtraData);
        }
        return Ok(());
    }

    pub fn read_int(&mut self) -> DeserializationResult<i64> {
        return self._read_with_tag(2, |data| {
            if data.len() > 8 {
                return Err(DeserializationError::IntegerOverflow);
            }
            let mut ret = 0;
            for b in data.iter() {
                ret <<= 8;
                ret |= *b as i64;
            }
            // Shift up and down in order to sign extend the result.
            ret <<= 64 - data.len() * 8;
            ret >>= 64 - data.len() * 8;
            return Ok(ret);
        });
    }
}

pub fn from_vec<F, T>(data: Vec<u8>, f: F) -> DeserializationResult<T>
        where F: Fn(&mut Deserializer) -> DeserializationResult<T> {
    let mut deserializer = Deserializer::new(data);
    let result = try!(f(&mut deserializer));
    try!(deserializer.finish());
    return Ok(result);
}

#[cfg(test)]
mod tests {
    use std::{fmt};

    use super::{Deserializer, DeserializationError, DeserializationResult, from_vec};

    fn assert_deserializes<T, F>(values: Vec<(DeserializationResult<T>, Vec<u8>)>, f: F)
            where T: Eq + fmt::Debug, F: Fn(&mut Deserializer) -> DeserializationResult<T> {
        for (expected, value) in values {
            let result = from_vec(value, &f);
            assert_eq!(result, expected);
        }
    }
    #[test]
    fn test_read_extra_data() {
        assert_deserializes(vec![
            (Err(DeserializationError::ExtraData), b"\x00".to_vec()),
        ], |_| {
            return Ok(());
        });
    }

    #[test]
    fn test_read_int() {
        assert_deserializes(vec![
            (Ok(0), b"\x02\x01\x00".to_vec()),
            (Ok(127), b"\x02\x01\x7f".to_vec()),
            (Ok(128), b"\x02\x02\x00\x80".to_vec()),
            (Ok(256), b"\x02\x02\x01\x00".to_vec()),
            (Ok(-128), b"\x02\x01\x80".to_vec()),
            (Ok(-129), b"\x02\x02\xff\x7f".to_vec()),
            (Err(DeserializationError::UnexpectedTag), b"\x03".to_vec()),
            (Err(DeserializationError::ShortData), b"\x02\x02\x00".to_vec()),
            (Err(DeserializationError::ShortData), b"".to_vec()),
            (Err(DeserializationError::ShortData), b"\x02".to_vec()),
            (
                Err(DeserializationError::IntegerOverflow),
                b"\x02\x09\x02\x00\x00\x00\x00\x00\x00\x00\x00".to_vec()
            ),
        ], |deserializer| {
            return deserializer.read_int();
        });
    }
}
<commit_msg>added support for reading bools<commit_after>use std::{convert};
use std::io::{Cursor, Read};

use byteorder::{self, ReadBytesExt};

#[derive(Debug, PartialEq, Eq)]
pub enum DeserializationError {
    UnexpectedTag,
    ShortData,
    ExtraData,
    IntegerOverflow,
    InvalidValue,
}

impl convert::From<byteorder::Error> for DeserializationError {
    fn from(e: byteorder::Error) -> DeserializationError {
        return match e {
            byteorder::Error::UnexpectedEOF => DeserializationError::ShortData,
            _ => panic!("Unexpected error!"),
        }
    }
}

pub type DeserializationResult<T> = Result<T, DeserializationError>;

pub struct Deserializer {
    reader: Cursor<Vec<u8>>,
}

impl Deserializer {
    pub fn new(data: Vec<u8>) -> Deserializer {
        return Deserializer{
            reader: Cursor::new(data),
        }
    }

    fn _read_length(&mut self) -> DeserializationResult<usize> {
        let b = try!(self.reader.read_u8());
        // TODO: handle lengths greater than 128
        assert!(b & 0x80 == 0);
        return Ok((b & 0x7f) as usize);
    }

    fn _read_with_tag<T, F>(&mut self, expected_tag: u8, body: F) -> DeserializationResult<T>
            where F: Fn(Vec<u8>) -> DeserializationResult<T> {
        let tag = try!(self.reader.read_u8());
        // TODO: only some of the bits in the first byte are for the tag
        if tag != expected_tag {
            return Err(DeserializationError::UnexpectedTag);
        }
        let length = try!(self._read_length());
        let mut data = vec![0; length];
        let n = self.reader.read(&mut data).unwrap();
        if n != length {
            return Err(DeserializationError::ShortData);
        }
        return body(data);
    }

    pub fn finish(self) -> DeserializationResult<()> {
        if self.reader.position() as usize != self.reader.get_ref().len() {
            return Err(DeserializationError::ExtraData);
        }
        return Ok(());
    }

    pub fn read_bool(&mut self) -> DeserializationResult<bool> {
        return self._read_with_tag(1, |data| {
            if data == b"\x00" {
                return Ok(false);
            } else if data == b"\xff" {
                return Ok(true)
            } else {
                return Err(DeserializationError::InvalidValue);
            }
        });
    }

    pub fn read_int(&mut self) -> DeserializationResult<i64> {
        return self._read_with_tag(2, |data| {
            if data.len() > 8 {
                return Err(DeserializationError::IntegerOverflow);
            }
            let mut ret = 0;
            for b in data.iter() {
                ret <<= 8;
                ret |= *b as i64;
            }
            // Shift up and down in order to sign extend the result.
            ret <<= 64 - data.len() * 8;
            ret >>= 64 - data.len() * 8;
            return Ok(ret);
        });
    }
}

pub fn from_vec<F, T>(data: Vec<u8>, f: F) -> DeserializationResult<T>
        where F: Fn(&mut Deserializer) -> DeserializationResult<T> {
    let mut deserializer = Deserializer::new(data);
    let result = try!(f(&mut deserializer));
    try!(deserializer.finish());
    return Ok(result);
}

#[cfg(test)]
mod tests {
    use std::{fmt};

    use super::{Deserializer, DeserializationError, DeserializationResult, from_vec};

    fn assert_deserializes<T, F>(values: Vec<(DeserializationResult<T>, Vec<u8>)>, f: F)
            where T: Eq + fmt::Debug, F: Fn(&mut Deserializer) -> DeserializationResult<T> {
        for (expected, value) in values {
            let result = from_vec(value, &f);
            assert_eq!(result, expected);
        }
    }
    #[test]
    fn test_read_extra_data() {
        assert_deserializes(vec![
            (Err(DeserializationError::ExtraData), b"\x00".to_vec()),
        ], |_| {
            return Ok(());
        });
    }

    #[test]
    fn test_read_bool() {
        assert_deserializes(vec![
            (Ok(true), b"\x01\x01\xff".to_vec()),
            (Ok(false), b"\x01\x01\x00".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x00".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x01\x01".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x02\x01\x01".to_vec()),
        ], |deserializer| {
            return deserializer.read_bool();
        });
    }

    #[test]
    fn test_read_int() {
        assert_deserializes(vec![
            (Ok(0), b"\x02\x01\x00".to_vec()),
            (Ok(127), b"\x02\x01\x7f".to_vec()),
            (Ok(128), b"\x02\x02\x00\x80".to_vec()),
            (Ok(256), b"\x02\x02\x01\x00".to_vec()),
            (Ok(-128), b"\x02\x01\x80".to_vec()),
            (Ok(-129), b"\x02\x02\xff\x7f".to_vec()),
            (Err(DeserializationError::UnexpectedTag), b"\x03".to_vec()),
            (Err(DeserializationError::ShortData), b"\x02\x02\x00".to_vec()),
            (Err(DeserializationError::ShortData), b"".to_vec()),
            (Err(DeserializationError::ShortData), b"\x02".to_vec()),
            (
                Err(DeserializationError::IntegerOverflow),
                b"\x02\x09\x02\x00\x00\x00\x00\x00\x00\x00\x00".to_vec()
            ),
        ], |deserializer| {
            return deserializer.read_int();
        });
    }
}
<|endoftext|>


<commit_before>use glium::{
    index, program, texture, vertex,
    DrawError, DrawParameters, IndexBuffer, Program, Rect, Surface, Texture2d, VertexBuffer
};
use glium::backend::{Context, Facade};
use glium::draw_parameters::{BlendingFunction, LinearBlendingFactor};
use glium::index::PrimitiveType;
use glium::texture::{ClientFormat, RawImage2d};
use glium::vertex::{Attribute, AttributeType, Vertex, VertexFormat};
use libc::c_float;
use std::borrow::Cow;
use std::mem;
use std::rc::Rc;

use super::{DrawList, Frame, ImDrawIdx, ImDrawVert, ImGui, ImVec2, ImVec4};

pub type RendererResult<T> = Result<T, RendererError>;

pub enum RendererError {
    Vertex(vertex::BufferCreationError),
    Index(index::BufferCreationError),
    Program(program::ProgramCreationError),
    Texture(texture::TextureCreationError),
    Draw(DrawError)
}

impl From<vertex::BufferCreationError> for RendererError {
    fn from(e: vertex::BufferCreationError) -> RendererError {
        RendererError::Vertex(e)
    }
}

impl From<index::BufferCreationError> for RendererError {
    fn from(e: index::BufferCreationError) -> RendererError {
        RendererError::Index(e)
    }
}

impl From<program::ProgramCreationError> for RendererError {
    fn from(e: program::ProgramCreationError) -> RendererError {
        RendererError::Program(e)
    }
}

impl From<texture::TextureCreationError> for RendererError {
    fn from(e: texture::TextureCreationError) -> RendererError {
        RendererError::Texture(e)
    }
}

impl From<DrawError> for RendererError {
    fn from(e: DrawError) -> RendererError {
        RendererError::Draw(e)
    }
}

unsafe impl Attribute for ImVec2 {
    fn get_type() -> AttributeType { <(c_float, c_float) as Attribute>::get_type() }
}

unsafe impl Attribute for ImVec4 {
    fn get_type() -> AttributeType {
        <(c_float, c_float, c_float, c_float) as Attribute>::get_type()
    }
}

impl Vertex for ImDrawVert {
    fn build_bindings() -> VertexFormat {
        unsafe {
            let dummy: &ImDrawVert = mem::transmute(0usize);
            Cow::Owned(vec![
                       ("pos".into(), mem::transmute(&dummy.pos), <ImVec2 as Attribute>::get_type()),
                       ("uv".into(), mem::transmute(&dummy.uv), <ImVec2 as Attribute>::get_type()),
                       ("col".into(), mem::transmute(&dummy.col), AttributeType::U8U8U8U8)
            ])
        }
    }
}

pub struct Renderer {
    ctx: Rc<Context>,
    device_objects: DeviceObjects
}

impl Renderer {
    pub fn init<F: Facade>(imgui: &mut ImGui, ctx: &F) -> RendererResult<Renderer> {
        let device_objects = try!(DeviceObjects::init(imgui, ctx));
        Ok(Renderer {
            ctx: ctx.get_context().clone(),
            device_objects: device_objects
        })
    }
    pub fn render<'a, S: Surface>(&mut self, surface: &mut S,
                                  frame: Frame<'a>) -> RendererResult<()> {
        frame.render(|draw_list| self.render_draw_list(surface, draw_list))
    }
    fn render_draw_list<'a, S: Surface>(&mut self, surface: &mut S,
                                        draw_list: DrawList<'a>) -> RendererResult<()> {
        try!(self.device_objects.upload_vertex_buffer(&self.ctx, draw_list.vtx_buffer));
        try!(self.device_objects.upload_index_buffer(&self.ctx, draw_list.idx_buffer));

        let (width, height) = surface.get_dimensions();

        let mut idx_start = 0;
        for cmd in draw_list.cmd_buffer {
            let matrix = [
                [ 2.0 / (width as f32), 0.0, 0.0, 0.0 ],
                [ 0.0, 2.0 / -(height as f32), 0.0, 0.0 ],
                [ 0.0, 0.0, -1.0, 0.0 ],
                    [ -1.0, 1.0, 0.0, 1.0 ]
            ];
            let uniforms = uniform! {
                matrix: matrix,
                texture: self.device_objects.texture.sampled()
            };
            let draw_params = DrawParameters {
                blending_function: Some(BlendingFunction::Addition {
                    source: LinearBlendingFactor::SourceAlpha,
                    destination: LinearBlendingFactor::OneMinusSourceAlpha
                }),
                scissor: Some(Rect {
                    left: cmd.clip_rect.x as u32,
                    bottom: (height as f32 - cmd.clip_rect.w) as u32,
                    width: (cmd.clip_rect.z - cmd.clip_rect.x) as u32,
                    height: (cmd.clip_rect.w - cmd.clip_rect.y) as u32
                }),
                .. Default::default()
            };
            let idx_end = idx_start + cmd.elem_count as usize;
            try!(surface.draw(&self.device_objects.vertex_buffer,
                              &self.device_objects.index_buffer.slice(idx_start ..idx_end)
                                  .expect("Invalid index buffer range"),
                              &self.device_objects.program,
                              &uniforms,
                              &draw_params));
            idx_start = idx_end;
        }
        Ok(())
    }
}

pub struct DeviceObjects {
    vertex_buffer: VertexBuffer<ImDrawVert>,
    index_buffer: IndexBuffer<ImDrawIdx>,
    program: Program,
    texture: Texture2d
}

fn compile_default_program<F: Facade>(ctx: &F) -> Result<Program, program::ProgramCreationError> {
    program!(
        ctx,
        140 => {
            vertex: include_str!("shader/vert_140.glsl"),
            fragment: include_str!("shader/frag_140.glsl"),
            outputs_srgb: true
        },
        110 => {
            vertex: include_str!("shader/vert_110.glsl"),
            fragment: include_str!("shader/frag_110.glsl"),
            outputs_srgb: true
        }
    )
}

impl DeviceObjects {
    pub fn init<F: Facade>(im_gui: &mut ImGui, ctx: &F) -> RendererResult<DeviceObjects> {
        let vertex_buffer = try!(VertexBuffer::empty_dynamic(ctx, 0));
        let index_buffer = try!(IndexBuffer::empty_dynamic(ctx, PrimitiveType::TrianglesList, 0));

        let program = try!(compile_default_program(ctx));
        let texture = try!(im_gui.prepare_texture(|handle| {
            let data = RawImage2d {
                data: Cow::Borrowed(handle.pixels),
                width: handle.width,
                height: handle.height,
                format: ClientFormat::U8U8U8U8
            };
            Texture2d::new(ctx, data)
        }));

        Ok(DeviceObjects {
            vertex_buffer: vertex_buffer,
            index_buffer: index_buffer,
            program: program,
            texture: texture
        })
    }
    pub fn upload_vertex_buffer<F: Facade>(&mut self, ctx: &F,
                                           vtx_buffer: &[ImDrawVert]) -> RendererResult<()> {
        self.vertex_buffer.invalidate();
        if let Some(slice) = self.vertex_buffer.slice_mut(0 .. vtx_buffer.len()) {
            slice.write(vtx_buffer);
            return Ok(());
        }
        self.vertex_buffer = try!(VertexBuffer::dynamic(ctx, vtx_buffer));
        Ok(())
    }
    pub fn upload_index_buffer<F: Facade>(&mut self, ctx: &F,
                                          idx_buffer: &[ImDrawIdx]) -> RendererResult<()> {
        self.index_buffer.invalidate();
        if let Some(slice) = self.index_buffer.slice_mut(0 .. idx_buffer.len()) {
            slice.write(idx_buffer);
            return Ok(());
        }
        self.index_buffer =
            try!(IndexBuffer::dynamic(ctx, PrimitiveType::TrianglesList, idx_buffer));
        Ok(())
    }
}
<commit_msg>RendererError should implement Display<commit_after>use glium::{
    index, program, texture, vertex,
    DrawError, DrawParameters, IndexBuffer, Program, Rect, Surface, Texture2d, VertexBuffer
};
use glium::backend::{Context, Facade};
use glium::draw_parameters::{BlendingFunction, LinearBlendingFactor};
use glium::index::PrimitiveType;
use glium::texture::{ClientFormat, RawImage2d};
use glium::vertex::{Attribute, AttributeType, Vertex, VertexFormat};
use libc::c_float;
use std::borrow::Cow;
use std::fmt;
use std::mem;
use std::rc::Rc;

use super::{DrawList, Frame, ImDrawIdx, ImDrawVert, ImGui, ImVec2, ImVec4};

pub type RendererResult<T> = Result<T, RendererError>;

#[derive(Clone, Debug)]
pub enum RendererError {
    Vertex(vertex::BufferCreationError),
    Index(index::BufferCreationError),
    Program(program::ProgramCreationError),
    Texture(texture::TextureCreationError),
    Draw(DrawError)
}

impl fmt::Display for RendererError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::RendererError::*;
        match *self {
            Vertex(_) => write!(f, "Vertex buffer creation failed"),
            Index(_) => write!(f, "Index buffer creation failed"),
            Program(ref e) => write!(f, "Program creation failed: {}", e),
            Texture(_) => write!(f, "Texture creation failed"),
            Draw(ref e) => write!(f, "Drawing failed: {}", e)
        }
    }
}

impl From<vertex::BufferCreationError> for RendererError {
    fn from(e: vertex::BufferCreationError) -> RendererError {
        RendererError::Vertex(e)
    }
}

impl From<index::BufferCreationError> for RendererError {
    fn from(e: index::BufferCreationError) -> RendererError {
        RendererError::Index(e)
    }
}

impl From<program::ProgramCreationError> for RendererError {
    fn from(e: program::ProgramCreationError) -> RendererError {
        RendererError::Program(e)
    }
}

impl From<texture::TextureCreationError> for RendererError {
    fn from(e: texture::TextureCreationError) -> RendererError {
        RendererError::Texture(e)
    }
}

impl From<DrawError> for RendererError {
    fn from(e: DrawError) -> RendererError {
        RendererError::Draw(e)
    }
}

unsafe impl Attribute for ImVec2 {
    fn get_type() -> AttributeType { <(c_float, c_float) as Attribute>::get_type() }
}

unsafe impl Attribute for ImVec4 {
    fn get_type() -> AttributeType {
        <(c_float, c_float, c_float, c_float) as Attribute>::get_type()
    }
}

impl Vertex for ImDrawVert {
    fn build_bindings() -> VertexFormat {
        unsafe {
            let dummy: &ImDrawVert = mem::transmute(0usize);
            Cow::Owned(vec![
                       ("pos".into(), mem::transmute(&dummy.pos), <ImVec2 as Attribute>::get_type()),
                       ("uv".into(), mem::transmute(&dummy.uv), <ImVec2 as Attribute>::get_type()),
                       ("col".into(), mem::transmute(&dummy.col), AttributeType::U8U8U8U8)
            ])
        }
    }
}

pub struct Renderer {
    ctx: Rc<Context>,
    device_objects: DeviceObjects
}

impl Renderer {
    pub fn init<F: Facade>(imgui: &mut ImGui, ctx: &F) -> RendererResult<Renderer> {
        let device_objects = try!(DeviceObjects::init(imgui, ctx));
        Ok(Renderer {
            ctx: ctx.get_context().clone(),
            device_objects: device_objects
        })
    }
    pub fn render<'a, S: Surface>(&mut self, surface: &mut S,
                                  frame: Frame<'a>) -> RendererResult<()> {
        frame.render(|draw_list| self.render_draw_list(surface, draw_list))
    }
    fn render_draw_list<'a, S: Surface>(&mut self, surface: &mut S,
                                        draw_list: DrawList<'a>) -> RendererResult<()> {
        try!(self.device_objects.upload_vertex_buffer(&self.ctx, draw_list.vtx_buffer));
        try!(self.device_objects.upload_index_buffer(&self.ctx, draw_list.idx_buffer));

        let (width, height) = surface.get_dimensions();

        let mut idx_start = 0;
        for cmd in draw_list.cmd_buffer {
            let matrix = [
                [ 2.0 / (width as f32), 0.0, 0.0, 0.0 ],
                [ 0.0, 2.0 / -(height as f32), 0.0, 0.0 ],
                [ 0.0, 0.0, -1.0, 0.0 ],
                    [ -1.0, 1.0, 0.0, 1.0 ]
            ];
            let uniforms = uniform! {
                matrix: matrix,
                texture: self.device_objects.texture.sampled()
            };
            let draw_params = DrawParameters {
                blending_function: Some(BlendingFunction::Addition {
                    source: LinearBlendingFactor::SourceAlpha,
                    destination: LinearBlendingFactor::OneMinusSourceAlpha
                }),
                scissor: Some(Rect {
                    left: cmd.clip_rect.x as u32,
                    bottom: (height as f32 - cmd.clip_rect.w) as u32,
                    width: (cmd.clip_rect.z - cmd.clip_rect.x) as u32,
                    height: (cmd.clip_rect.w - cmd.clip_rect.y) as u32
                }),
                .. Default::default()
            };
            let idx_end = idx_start + cmd.elem_count as usize;
            try!(surface.draw(&self.device_objects.vertex_buffer,
                              &self.device_objects.index_buffer.slice(idx_start ..idx_end)
                                  .expect("Invalid index buffer range"),
                              &self.device_objects.program,
                              &uniforms,
                              &draw_params));
            idx_start = idx_end;
        }
        Ok(())
    }
}

pub struct DeviceObjects {
    vertex_buffer: VertexBuffer<ImDrawVert>,
    index_buffer: IndexBuffer<ImDrawIdx>,
    program: Program,
    texture: Texture2d
}

fn compile_default_program<F: Facade>(ctx: &F) -> Result<Program, program::ProgramCreationError> {
    program!(
        ctx,
        140 => {
            vertex: include_str!("shader/vert_140.glsl"),
            fragment: include_str!("shader/frag_140.glsl"),
            outputs_srgb: true
        },
        110 => {
            vertex: include_str!("shader/vert_110.glsl"),
            fragment: include_str!("shader/frag_110.glsl"),
            outputs_srgb: true
        }
    )
}

impl DeviceObjects {
    pub fn init<F: Facade>(im_gui: &mut ImGui, ctx: &F) -> RendererResult<DeviceObjects> {
        let vertex_buffer = try!(VertexBuffer::empty_dynamic(ctx, 0));
        let index_buffer = try!(IndexBuffer::empty_dynamic(ctx, PrimitiveType::TrianglesList, 0));

        let program = try!(compile_default_program(ctx));
        let texture = try!(im_gui.prepare_texture(|handle| {
            let data = RawImage2d {
                data: Cow::Borrowed(handle.pixels),
                width: handle.width,
                height: handle.height,
                format: ClientFormat::U8U8U8U8
            };
            Texture2d::new(ctx, data)
        }));

        Ok(DeviceObjects {
            vertex_buffer: vertex_buffer,
            index_buffer: index_buffer,
            program: program,
            texture: texture
        })
    }
    pub fn upload_vertex_buffer<F: Facade>(&mut self, ctx: &F,
                                           vtx_buffer: &[ImDrawVert]) -> RendererResult<()> {
        self.vertex_buffer.invalidate();
        if let Some(slice) = self.vertex_buffer.slice_mut(0 .. vtx_buffer.len()) {
            slice.write(vtx_buffer);
            return Ok(());
        }
        self.vertex_buffer = try!(VertexBuffer::dynamic(ctx, vtx_buffer));
        Ok(())
    }
    pub fn upload_index_buffer<F: Facade>(&mut self, ctx: &F,
                                          idx_buffer: &[ImDrawIdx]) -> RendererResult<()> {
        self.index_buffer.invalidate();
        if let Some(slice) = self.index_buffer.slice_mut(0 .. idx_buffer.len()) {
            slice.write(idx_buffer);
            return Ok(());
        }
        self.index_buffer =
            try!(IndexBuffer::dynamic(ctx, PrimitiveType::TrianglesList, idx_buffer));
        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::{Change, Index};
use git_repository as git;
use git_repository::prelude::{FindExt, ObjectIdExt, TreeIterExt};
use git_repository::refs::transaction::PreviousValue;
use std::convert::TryFrom;

mod delegate;
use delegate::Delegate;

/// The error returned by methods dealing with obtaining index changes.
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
    #[error(transparent)]
    Fetch(#[from] git2::Error),
    #[error(transparent)]
    ReferenceEdit(#[from] git::reference::edit::Error),
    #[error(transparent)]
    RevParse(#[from] git::revision::spec::parse::Error),
    #[error(transparent)]
    FindObject(#[from] git::object::find::existing::Error),
    #[error(transparent)]
    PeelToTree(#[from] git::object::peel::to_kind::Error),
    #[error(transparent)]
    Diff(#[from] git::diff::tree::changes::Error),
    #[error(transparent)]
    VersionDecode(#[from] serde_json::Error),
}

/// Find changes without modifying the underling repository
impl Index {
    /// As `peek_changes_with_options`, but without the options.
    pub fn peek_changes(&self) -> Result<(Vec<Change>, git::hash::ObjectId), Error> {
        self.peek_changes_with_options(None)
    }

    /// Return all `Change`s that are observed between the last time `fetch_changes(…)` was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will not be created or updated.
    /// The second field in the returned tuple is the commit object to which the changes were provided.
    /// If one would set the `last_seen_reference()` to that object, the effect is exactly the same
    /// as if `fetch_changes(…)` had been called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn peek_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<(Vec<Change>, git::hash::ObjectId), Error> {
        let repo = &self.repo;
        let from = repo
            .find_reference(self.seen_ref_name)
            .ok()
            .and_then(|r| r.try_id().map(|id| id.detach()))
            .unwrap_or_else(|| git::hash::ObjectId::empty_tree(repo.object_hash()));
        let to = {
            let repo = git2::Repository::open(repo.git_dir())?;
            repo.find_remote("origin").and_then(|mut r| {
                r.fetch(
                    &[format!(
                        "refs/heads/{branch}:refs/remotes/origin/{branch}",
                        branch = self.branch_name
                    )],
                    options,
                    None,
                )
            })?;
            git::hash::ObjectId::try_from(
                repo.refname_to_id(&format!("refs/remotes/origin/{}", self.branch_name))?
                    .as_bytes(),
            )
            .expect("valid oid")
        };

        Ok((self.changes_between_commits(from, to)?, to))
    }

    /// Similar to `changes()`, but requires `from` and `to` objects to be provided. They may point
    /// to either `Commit`s or `Tree`s.
    pub fn changes_between_commits(
        &self,
        from: impl Into<git::hash::ObjectId>,
        to: impl Into<git::hash::ObjectId>,
    ) -> Result<Vec<Change>, Error> {
        let into_tree = |id: git::hash::ObjectId| -> Result<git::Tree<'_>, Error> {
            Ok(id
                .attach(&self.repo)
                .object()?
                .peel_to_kind(git::object::Kind::Tree)?
                .into_tree())
        };
        let from = into_tree(from.into())?;
        let to = into_tree(to.into())?;
        let mut delegate = Delegate::from_repo(&self.repo);
        let file_changes = git::objs::TreeRefIter::from_bytes(&from.data).changes_needed(
            git::objs::TreeRefIter::from_bytes(&to.data),
            git::diff::tree::State::default(),
            |id, buf| self.repo.objects.find_tree_iter(id, buf).ok(),
            &mut delegate,
        );
        match file_changes.err() {
            None | Some(git::diff::tree::changes::Error::Cancelled) => { /*error in delegate*/ }
            Some(err) => return Err(err.into()),
        }
        delegate.into_result()
    }
}

/// Find changes while changing the underlying repository in one way or another.
impl Index {
    /// As `fetch_changes_with_options`, but without the options.
    pub fn fetch_changes(&self) -> Result<Vec<Change>, Error> {
        self.fetch_changes_with_options(None)
    }

    /// Return all `Change`s that are observed between the last time this method was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will be created or adjusted to point to the latest fetched
    /// state, which causes this method to have a different result each time it is called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn fetch_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<Vec<Change>, Error> {
        let (changes, to) = self.peek_changes_with_options(options)?;
        self.set_last_seen_reference(to)?;
        Ok(changes)
    }

    /// Set the last seen reference to the given Oid. It will be created if it does not yet exists.
    pub fn set_last_seen_reference(&self, to: git::hash::ObjectId) -> Result<(), Error> {
        let repo = self.repository();
        repo.reference(
            self.seen_ref_name,
            to,
            PreviousValue::Any,
            "updating seen-ref head to latest fetched commit",
        )?;
        Ok(())
    }

    /// Return all `CreateVersion`s observed between `from` and `to`. Both parameter are ref-specs
    /// pointing to either a commit or a tree.
    /// Learn more about specifying revisions
    /// in the
    /// [official documentation](https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html)
    pub fn changes(
        &self,
        from: impl AsRef<str>,
        to: impl AsRef<str>,
    ) -> Result<Vec<Change>, Error> {
        let repo = self.repository();
        let from = repo
            .rev_parse(from.as_ref())?
            .single()
            .expect("revspec was not a range")
            .detach();
        let to = repo
            .rev_parse(to.as_ref())?
            .single()
            .expect("revspec was not a range")
            .detach();
        self.changes_between_commits(from, to)
    }
}
<commit_msg>adapt to changes in git-repository (#16)<commit_after>use crate::{Change, Index};
use git_repository as git;
use git_repository::prelude::{FindExt, ObjectIdExt};
use git_repository::refs::transaction::PreviousValue;
use std::convert::TryFrom;

mod delegate;
use delegate::Delegate;

/// The error returned by methods dealing with obtaining index changes.
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
    #[error(transparent)]
    Fetch(#[from] git2::Error),
    #[error(transparent)]
    ReferenceEdit(#[from] git::reference::edit::Error),
    #[error(transparent)]
    RevParse(#[from] git::revision::spec::parse::Error),
    #[error(transparent)]
    FindObject(#[from] git::object::find::existing::Error),
    #[error(transparent)]
    PeelToTree(#[from] git::object::peel::to_kind::Error),
    #[error(transparent)]
    Diff(#[from] git::diff::tree::changes::Error),
    #[error(transparent)]
    VersionDecode(#[from] serde_json::Error),
}

/// Find changes without modifying the underling repository
impl Index {
    /// As `peek_changes_with_options`, but without the options.
    pub fn peek_changes(&self) -> Result<(Vec<Change>, git::hash::ObjectId), Error> {
        self.peek_changes_with_options(None)
    }

    /// Return all `Change`s that are observed between the last time `fetch_changes(…)` was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will not be created or updated.
    /// The second field in the returned tuple is the commit object to which the changes were provided.
    /// If one would set the `last_seen_reference()` to that object, the effect is exactly the same
    /// as if `fetch_changes(…)` had been called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn peek_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<(Vec<Change>, git::hash::ObjectId), Error> {
        let repo = &self.repo;
        let from = repo
            .find_reference(self.seen_ref_name)
            .ok()
            .and_then(|r| r.try_id().map(|id| id.detach()))
            .unwrap_or_else(|| git::hash::ObjectId::empty_tree(repo.object_hash()));
        let to = {
            let repo = git2::Repository::open(repo.git_dir())?;
            repo.find_remote("origin").and_then(|mut r| {
                r.fetch(
                    &[format!(
                        "refs/heads/{branch}:refs/remotes/origin/{branch}",
                        branch = self.branch_name
                    )],
                    options,
                    None,
                )
            })?;
            git::hash::ObjectId::try_from(
                repo.refname_to_id(&format!("refs/remotes/origin/{}", self.branch_name))?
                    .as_bytes(),
            )
            .expect("valid oid")
        };

        Ok((self.changes_between_commits(from, to)?, to))
    }

    /// Similar to `changes()`, but requires `from` and `to` objects to be provided. They may point
    /// to either `Commit`s or `Tree`s.
    pub fn changes_between_commits(
        &self,
        from: impl Into<git::hash::ObjectId>,
        to: impl Into<git::hash::ObjectId>,
    ) -> Result<Vec<Change>, Error> {
        let into_tree = |id: git::hash::ObjectId| -> Result<git::Tree<'_>, Error> {
            Ok(id
                .attach(&self.repo)
                .object()?
                .peel_to_kind(git::object::Kind::Tree)?
                .into_tree())
        };
        let from = into_tree(from.into())?;
        let to = into_tree(to.into())?;
        let mut delegate = Delegate::from_repo(&self.repo);
        let file_changes =
            git::diff::tree::Changes::from(git::objs::TreeRefIter::from_bytes(&from.data))
                .needed_to_obtain(
                    git::objs::TreeRefIter::from_bytes(&to.data),
                    git::diff::tree::State::default(),
                    |id, buf| self.repo.objects.find_tree_iter(id, buf),
                    &mut delegate,
                );
        match file_changes.err() {
            None | Some(git::diff::tree::changes::Error::Cancelled) => { /*error in delegate*/ }
            Some(err) => return Err(err.into()),
        }
        delegate.into_result()
    }
}

/// Find changes while changing the underlying repository in one way or another.
impl Index {
    /// As `fetch_changes_with_options`, but without the options.
    pub fn fetch_changes(&self) -> Result<Vec<Change>, Error> {
        self.fetch_changes_with_options(None)
    }

    /// Return all `Change`s that are observed between the last time this method was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will be created or adjusted to point to the latest fetched
    /// state, which causes this method to have a different result each time it is called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn fetch_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<Vec<Change>, Error> {
        let (changes, to) = self.peek_changes_with_options(options)?;
        self.set_last_seen_reference(to)?;
        Ok(changes)
    }

    /// Set the last seen reference to the given Oid. It will be created if it does not yet exists.
    pub fn set_last_seen_reference(&self, to: git::hash::ObjectId) -> Result<(), Error> {
        let repo = self.repository();
        repo.reference(
            self.seen_ref_name,
            to,
            PreviousValue::Any,
            "updating seen-ref head to latest fetched commit",
        )?;
        Ok(())
    }

    /// Return all `CreateVersion`s observed between `from` and `to`. Both parameter are ref-specs
    /// pointing to either a commit or a tree.
    /// Learn more about specifying revisions
    /// in the
    /// [official documentation](https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html)
    pub fn changes(
        &self,
        from: impl AsRef<str>,
        to: impl AsRef<str>,
    ) -> Result<Vec<Change>, Error> {
        let repo = self.repository();
        let from = repo
            .rev_parse(from.as_ref())?
            .single()
            .expect("revspec was not a range")
            .detach();
        let to = repo
            .rev_parse(to.as_ref())?
            .single()
            .expect("revspec was not a range")
            .detach();
        self.changes_between_commits(from, to)
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate lib;
extern crate serde_json;

use clap::{Arg, ArgMatches};
use std::fs::File;

use lib::CompileVariablePlugin;

pub struct JsonPlugin;

impl CompileVariablePlugin for JsonPlugin {
    type RenderValue = serde_json::value::Value;

    fn plugin_name() -> &'static str {
        "json"
    }

    fn arg_full_name() -> &'static str {
        "json"
    }

    fn arg_help() -> &'static str {
        "Assign variable to contents of JSON value"
    }

    fn additional_args() -> Vec<Arg<'static, 'static>> {
        vec![]
    }

    fn from_args<'a>(_: &'a ArgMatches<'a>) -> JsonPlugin {
        JsonPlugin
    }

    fn read_file(&self, mut file: File) -> Result<Self::RenderValue, String> {
        match serde_json::from_reader(&mut file) {
            Ok(obj) => Ok(obj),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}
<commit_msg>fix typo<commit_after>extern crate clap;
extern crate lib;
extern crate serde_json;

use clap::{Arg, ArgMatches};
use std::fs::File;

use lib::CompileVariablePlugin;

pub struct JsonPlugin;

impl CompileVariablePlugin for JsonPlugin {
    type RenderValue = serde_json::value::Value;

    fn plugin_name() -> &'static str {
        "json"
    }

    fn arg_full_name() -> &'static str {
        "json"
    }

    fn arg_help() -> &'static str {
        "Assign variable to contents of JSON file"
    }

    fn additional_args() -> Vec<Arg<'static, 'static>> {
        vec![]
    }

    fn from_args<'a>(_: &'a ArgMatches<'a>) -> JsonPlugin {
        JsonPlugin
    }

    fn read_file(&self, mut file: File) -> Result<Self::RenderValue, String> {
        match serde_json::from_reader(&mut file) {
            Ok(obj) => Ok(obj),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{hash_map, HashMap};

use game::InputEvent;
use direction::Direction;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Control {
    Direction(Direction),
    Close,
    Fire,
    NextTarget,
    PrevTarget,
    Wait,
    DisplayMessageLog,
    Examine,
    Select,
    Quit,
    Help,
}

pub type ControlMapIter<'a> = hash_map::Iter<'a, InputEvent, Control>;

#[derive(Clone, Serialize, Deserialize)]
pub struct ControlMap {
    map: HashMap<InputEvent, Control>,
}

impl ControlMap {
    pub fn control(&self, event: InputEvent) -> Option<Control> {
        self.map.get(&event).map(|r| *r)
    }

    pub fn iter(&self) -> ControlMapIter {
        self.map.iter()
    }
}

impl Default for ControlMap {
    fn default() -> Self {
        let mut map = HashMap::new();

        map.insert(InputEvent::Up, Control::Direction(Direction::North));
        map.insert(InputEvent::Down, Control::Direction(Direction::South));
        map.insert(InputEvent::Left, Control::Direction(Direction::West));
        map.insert(InputEvent::Right, Control::Direction(Direction::East));

        map.insert(InputEvent::Char('c'), Control::Close);
        map.insert(InputEvent::Char('f'), Control::Fire);
        map.insert(InputEvent::Char('n'), Control::NextTarget);
        map.insert(InputEvent::Char('m'), Control::PrevTarget);
        map.insert(InputEvent::Char('t'), Control::DisplayMessageLog);
        map.insert(InputEvent::Char('x'), Control::Examine);

        map.insert(InputEvent::Char('.'), Control::Wait);

        map.insert(InputEvent::Char('q'), Control::Quit);
        map.insert(InputEvent::Char('?'), Control::Help);
        map.insert(InputEvent::Quit, Control::Quit);
        map.insert(InputEvent::Return, Control::Select);

        ControlMap {
            map: map,
        }
    }
}
<commit_msg>Access menu with escape rather than q<commit_after>use std::collections::{hash_map, HashMap};

use game::InputEvent;
use direction::Direction;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Control {
    Direction(Direction),
    Close,
    Fire,
    NextTarget,
    PrevTarget,
    Wait,
    DisplayMessageLog,
    Examine,
    Select,
    Quit,
    Help,
}

pub type ControlMapIter<'a> = hash_map::Iter<'a, InputEvent, Control>;

#[derive(Clone, Serialize, Deserialize)]
pub struct ControlMap {
    map: HashMap<InputEvent, Control>,
}

impl ControlMap {
    pub fn control(&self, event: InputEvent) -> Option<Control> {
        self.map.get(&event).map(|r| *r)
    }

    pub fn iter(&self) -> ControlMapIter {
        self.map.iter()
    }
}

impl Default for ControlMap {
    fn default() -> Self {
        let mut map = HashMap::new();

        map.insert(InputEvent::Up, Control::Direction(Direction::North));
        map.insert(InputEvent::Down, Control::Direction(Direction::South));
        map.insert(InputEvent::Left, Control::Direction(Direction::West));
        map.insert(InputEvent::Right, Control::Direction(Direction::East));

        map.insert(InputEvent::Char('c'), Control::Close);
        map.insert(InputEvent::Char('f'), Control::Fire);
        map.insert(InputEvent::Char('n'), Control::NextTarget);
        map.insert(InputEvent::Char('m'), Control::PrevTarget);
        map.insert(InputEvent::Char('t'), Control::DisplayMessageLog);
        map.insert(InputEvent::Char('x'), Control::Examine);

        map.insert(InputEvent::Char('.'), Control::Wait);

        map.insert(InputEvent::Char('?'), Control::Help);
        map.insert(InputEvent::Quit, Control::Quit);
        map.insert(InputEvent::Return, Control::Select);
        map.insert(InputEvent::Escape, Control::Quit);

        ControlMap {
            map: map,
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate fruently;

#[cfg(test)]
mod tests {
    use test::Bencher;
    use fruently::fluent::Fluent;
    use std::collections::HashMap;

    #[bench]
    fn benchmark_fruently(b: &mut Bencher) {
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("name".to_string(), "fruently".to_string());
        b.iter(|| {
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(&obj);
        });
    }
}
<commit_msg>benckmarks: Add missing use trait<commit_after>#![feature(test)]

extern crate test;
extern crate fruently;

#[cfg(test)]
mod tests {
    use test::Bencher;
    use fruently::fluent::Fluent;
    use std::collections::HashMap;
    use fruently::forwardable::JsonForwardable;

    #[bench]
    fn benchmark_fruently(b: &mut Bencher) {
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("name".to_string(), "fruently".to_string());
        b.iter(|| {
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(&obj);
        });
    }
}
<|endoftext|>


<commit_before>#![recursion_limit = "256"]

use crate::*;
use anyhow::{anyhow, bail};
use async_std::{net::SocketAddr, prelude::*};
use bincode::deserialize;
use futures::{
    self,
    future::FusedFuture,
    sink::SinkExt,
    stream::{self, select, FuturesUnordered, StreamExt},
};
use futures_timer::Delay;
use nhanh::*;
use serde::Serialize;
use std::{
    collections::HashMap,
    fs::File,
    time::{Duration, Instant},
};
use structopt::StructOpt;

#[derive(Serialize)]
struct TripReport {
    index: u64,
    round_trip: u128,
}

#[derive(Debug)]
struct Results {
    stream_reports: HashMap<StreamId, StreamReport>,
}

struct StreamReport {
    mean: Duration,
    deviation: Duration,
    trip_reports: Vec<TripReport>,
}

impl std::fmt::Debug for StreamReport {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("StreamReport")
            .field("Mean", &self.mean)
            .field("Deviation", &self.deviation)
            .finish()
    }
}

impl From<Vec<TripReport>> for StreamReport {
    fn from(src: Vec<TripReport>) -> Self {
        let sum: u128 = src.iter().map(|r| r.round_trip).sum();
        let n = src.len() as u128;
        let mean = sum / n;

        let square_difference = |r: &TripReport| (r.round_trip - mean).pow(2);
        let sum_of_squares: u128 = src.iter().map(square_difference).sum();
        let variance = sum_of_squares / (n - 1);
        let deviation = (variance as f64).sqrt();

        let mean = Duration::from_nanos(mean as u64);
        let deviation = Duration::from_nanos(deviation as u64);

        StreamReport {
            mean,
            deviation,
            trip_reports: src,
        }
    }
}

struct Config {
    payload_size: usize,
    streams: u8,
    payload_count: usize,
    stream_burst_width: usize,
}

async fn run(config: Config, mut client: impl Connection + Unpin) -> Results {
    let tick_ps = 60;
    let tick_rate = Duration::from_secs(1) / tick_ps;
    let mut ticker = stream::repeat(0u8).then(|_| Delay::new(tick_rate));

    let total_datagrams = config.payload_count;
    let mut remaining_to_send = total_datagrams;
    let mut live = HashMap::new();
    let mut stream_reports: HashMap<StreamId, Vec<TripReport>> = HashMap::new();

    enum Input {
        Tick,
        Wire(Result<Datagram>),
    }

    let (mut client_sink, client_stream) = client.split();
    let returned_datagrams = client_stream.map(Input::Wire);
    let ticks = ticker.map(|_| Input::Tick);
    let mut input_stream = select(returned_datagrams, ticks);
    let mut stream_alternator: usize = 0;

    loop {
        let input = input_stream.next().await.unwrap();
        match input {
            Input::Wire(returned_datagram) => {
                let returned_datagram: Datagram =
                    returned_datagram.expect("datagram");
                let stream = returned_datagram
                    .stream_position
                    .expect("stream position")
                    .stream_id;
                let benchmark_datagram =
                    bincode::deserialize::<BenchmarkDatagram>(
                        returned_datagram.data.as_slice(),
                    )
                    .expect("deserializing");

                let return_time = Instant::now();
                let send_time = live.remove(&benchmark_datagram.id).unwrap();
                let round_trip = return_time.duration_since(send_time);
                stream_reports.entry(stream).or_default().push(TripReport {
                    index: benchmark_datagram.id,
                    round_trip: round_trip.as_nanos(),
                });

                if remaining_to_send == 0 && live.is_empty() {
                    return Results {
                        stream_reports: stream_reports
                            .into_iter()
                            .map(|(stream, reports)| {
                                (stream, StreamReport::from(reports))
                            })
                            .collect(),
                    };
                }
            }
            Input::Tick => {
                let stream = {
                    let stream = (stream_alternator
                        / config.stream_burst_width)
                        % config.streams as usize;
                    stream_alternator += 1;
                    stream as u8
                };
                let delivery_mode =
                    DeliveryMode::ReliableOrdered(StreamId(stream));
                let data = vec![0; config.payload_size];
                let id = (total_datagrams - remaining_to_send) as u64;
                let benchmark_datagram = BenchmarkDatagram {
                    delivery_mode,
                    id,
                    data,
                };

                client_sink
                    .send(SendCmd {
                        data: bincode::serialize(&benchmark_datagram)
                            .expect("serializing"),
                        delivery_mode,
                        ..SendCmd::default()
                    })
                    .await;

                let old = remaining_to_send;
                remaining_to_send = remaining_to_send.saturating_sub(1);
                if old != remaining_to_send {
                    live.insert(id, Instant::now());
                }
            }
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct Options {
    /// Address of the server to run the benchmark against;
    #[structopt(short = "a", default_value = "127.0.0.1:33333")]
    pub address: SocketAddr,
    #[structopt(short = "c", default_value = "1")]
    pub streams: u8,
    #[structopt(subcommand)]
    pub protocol: Protocol,
    #[structopt(short = "d", default_value = "200")]
    pub payload_size: usize,
    #[structopt(short = "n", default_value = "600")]
    pub payload_count: usize,
    /// The number of messages to send on a single stream at once,
    /// before sending messages on another stream.
    #[structopt(short = "w", default_value = "10")]
    pub stream_burst_width: usize,
}

pub async fn client_main(options: Options) {
    let config = Config {
        payload_size: options.payload_size,
        streams: options.streams,
        payload_count: options.payload_count,
        stream_burst_width: options.stream_burst_width,
    };

    let results = match options.protocol {
        Protocol::Tcp => {
            run(
                config,
                loop {
                    let result =
                        tcp::TcpConnection::connect(options.address).await;

                    let error = match result {
                        Ok(results) => break results,
                        Err(e) => e,
                    };

                    // The server port is not yet open; give it time.
                    if error.is::<std::io::Error>()
                        && error
                            .downcast_ref::<std::io::Error>()
                            .map(std::io::Error::kind)
                            == Some(std::io::ErrorKind::ConnectionRefused)
                    {
                        continue;
                    }

                    panic!(
                        "Failed to connect to benchmark server: {:?}",
                        error
                    );
                },
            )
            .await
        }
        Protocol::Enet => {
            run(config, enet::EnetConnection::connect(options.address).await)
                .await
        }
        p => panic!("Unsupported protocol for client: {:?}", p),
    };

    println!("{:?}: {:#?}", options.protocol, results);
}
<commit_msg>Average stream results together<commit_after>#![recursion_limit = "256"]

use crate::*;
use anyhow::{anyhow, bail};
use async_std::{net::SocketAddr, prelude::*};
use bincode::deserialize;
use futures::{
    self,
    future::FusedFuture,
    sink::SinkExt,
    stream::{self, select, FuturesUnordered, StreamExt},
};
use futures_timer::Delay;
use nhanh::*;
use serde::Serialize;
use std::{
    collections::HashMap,
    fs::File,
    iter::FromIterator,
    time::{Duration, Instant},
};
use structopt::StructOpt;

#[derive(Serialize)]
struct TripReport {
    index: u64,
    round_trip: u128,
}

struct Results {
    mean: Duration,
    deviation: Duration,
}

impl FromIterator<Results> for Results {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Results>,
    {
        let (count, mean_sum, deviation_sum) = iter.into_iter().fold(
            (0, Duration::from_secs(0), Duration::from_secs(0)),
            |(mut count, mut mean_sum, mut deviation_sum), result| {
                mean_sum += result.mean;
                deviation_sum += result.deviation;
                count += 1;
                (count, mean_sum, deviation_sum)
            },
        );
        Results {
            mean: mean_sum / count,
            deviation: deviation_sum / count,
        }
    }
}

impl std::fmt::Debug for Results {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("Results")
            .field("Mean", &self.mean)
            .field("Deviation", &self.deviation)
            .finish()
    }
}

impl From<Vec<TripReport>> for Results {
    fn from(src: Vec<TripReport>) -> Self {
        let sum: u128 = src.iter().map(|r| r.round_trip).sum();
        let n = src.len() as u128;
        let mean = sum / n;

        let square_difference = |r: &TripReport| (r.round_trip - mean).pow(2);
        let sum_of_squares: u128 = src.iter().map(square_difference).sum();
        let variance = sum_of_squares / (n - 1);
        let deviation = (variance as f64).sqrt();

        let mean = Duration::from_nanos(mean as u64);
        let deviation = Duration::from_nanos(deviation as u64);

        Results { mean, deviation }
    }
}

struct Config {
    payload_size: usize,
    streams: u8,
    payload_count: usize,
    stream_burst_width: usize,
}

async fn run(config: Config, mut client: impl Connection + Unpin) -> Results {
    let tick_ps = 60;
    let tick_rate = Duration::from_secs(1) / tick_ps;
    let mut ticker = stream::repeat(0u8).then(|_| Delay::new(tick_rate));

    let total_datagrams = config.payload_count;
    let mut remaining_to_send = total_datagrams;
    let mut live = HashMap::new();
    let mut stream_results: HashMap<StreamId, Vec<TripReport>> = HashMap::new();

    enum Input {
        Tick,
        Wire(Result<Datagram>),
    }

    let (mut client_sink, client_stream) = client.split();
    let returned_datagrams = client_stream.map(Input::Wire);
    let ticks = ticker.map(|_| Input::Tick);
    let mut input_stream = select(returned_datagrams, ticks);
    let mut stream_alternator: usize = 0;

    loop {
        let input = input_stream.next().await.unwrap();
        match input {
            Input::Wire(returned_datagram) => {
                let returned_datagram: Datagram =
                    returned_datagram.expect("datagram");
                let stream = returned_datagram
                    .stream_position
                    .expect("stream position")
                    .stream_id;
                let benchmark_datagram =
                    bincode::deserialize::<BenchmarkDatagram>(
                        returned_datagram.data.as_slice(),
                    )
                    .expect("deserializing");

                let return_time = Instant::now();
                let send_time = live.remove(&benchmark_datagram.id).unwrap();
                let round_trip = return_time.duration_since(send_time);
                stream_results.entry(stream).or_default().push(TripReport {
                    index: benchmark_datagram.id,
                    round_trip: round_trip.as_nanos(),
                });

                if remaining_to_send == 0 && live.is_empty() {
                    return stream_results
                        .into_iter()
                        .map(|(_, reports)| reports)
                        .map(Results::from)
                        .collect();
                }
            }
            Input::Tick => {
                let stream = {
                    let stream = (stream_alternator
                        / config.stream_burst_width)
                        % config.streams as usize;
                    stream_alternator += 1;
                    stream as u8
                };
                let delivery_mode =
                    DeliveryMode::ReliableOrdered(StreamId(stream));
                let data = vec![0; config.payload_size];
                let id = (total_datagrams - remaining_to_send) as u64;
                let benchmark_datagram = BenchmarkDatagram {
                    delivery_mode,
                    id,
                    data,
                };

                client_sink
                    .send(SendCmd {
                        data: bincode::serialize(&benchmark_datagram)
                            .expect("serializing"),
                        delivery_mode,
                        ..SendCmd::default()
                    })
                    .await;

                let old = remaining_to_send;
                remaining_to_send = remaining_to_send.saturating_sub(1);
                if old != remaining_to_send {
                    live.insert(id, Instant::now());
                }
            }
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct Options {
    /// Address of the server to run the benchmark against;
    #[structopt(short = "a", default_value = "127.0.0.1:33333")]
    pub address: SocketAddr,
    #[structopt(short = "c", default_value = "1")]
    pub streams: u8,
    #[structopt(subcommand)]
    pub protocol: Protocol,
    #[structopt(short = "d", default_value = "200")]
    pub payload_size: usize,
    #[structopt(short = "n", default_value = "600")]
    pub payload_count: usize,
    /// The number of messages to send on a single stream at once,
    /// before sending messages on another stream.
    #[structopt(short = "w", default_value = "10")]
    pub stream_burst_width: usize,
}

pub async fn client_main(options: Options) {
    let config = Config {
        payload_size: options.payload_size,
        streams: options.streams,
        payload_count: options.payload_count,
        stream_burst_width: options.stream_burst_width,
    };

    let results = match options.protocol {
        Protocol::Tcp => {
            run(
                config,
                loop {
                    let result =
                        tcp::TcpConnection::connect(options.address).await;

                    let error = match result {
                        Ok(results) => break results,
                        Err(e) => e,
                    };

                    // The server port is not yet open; give it time.
                    if error.is::<std::io::Error>()
                        && error
                            .downcast_ref::<std::io::Error>()
                            .map(std::io::Error::kind)
                            == Some(std::io::ErrorKind::ConnectionRefused)
                    {
                        continue;
                    }

                    panic!(
                        "Failed to connect to benchmark server: {:?}",
                        error
                    );
                },
            )
            .await
        }
        Protocol::Enet => {
            run(config, enet::EnetConnection::connect(options.address).await)
                .await
        }
        p => panic!("Unsupported protocol for client: {:?}", p),
    };

    println!("{:?}: {:#?}", options.protocol, results);
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Cursor;
use std::io::prelude::*;
use std::net::TcpStream;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

const RECV_BUF_SIZE: usize = 8192;
const GQTP_HEADER_SIZE: usize = 24;

#[derive(Debug)]
pub enum GQTPError {
    InvalidProtocol,
    InvalidBodySize,
    StatusError(u16),
    IO(io::Error)
}

impl From<io::Error> for GQTPError {
    fn from(err: io::Error) -> GQTPError {
        GQTPError::IO(err)
    }
}

/// Request [GQTP protocol](http://groonga.org/docs/spec/gqtp.html) over TcpStream
pub struct GQTPRequest<'a> {
    addr: &'a str,
}

impl<'a> Default for GQTPRequest<'a> {
    fn default() -> GQTPRequest<'a> {
        GQTPRequest { addr: "127.0.0.1:10043" }
    }
}

impl<'a> GQTPRequest<'a> {
    /// Create a GQTP client.
    pub fn new() -> GQTPRequest<'a> {
        GQTPRequest::default()
    }

    /// Set host address for GQTP server.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate ruroonga_client as groonga;
    ///
    /// groonga::GQTPRequest::new().with_addr("127.0.0.1:20043");
    /// ```
    pub fn with_addr(mut self, addr: &'a str) -> GQTPRequest<'a> {
        self.addr = addr;
        self
    }

    /// Send request and Receive response.
    pub fn call<C>(&self, command: C) -> Result<String, GQTPError>
        where C: AsRef<str>
    {
        // send
        let mut stream = TcpStream::connect(self.addr).unwrap();
        let mut send_buf = vec![];
        try!(send_buf.write_u8(0xc7));
        try!(send_buf.write_u8(0));
        try!(send_buf.write_i16::<BigEndian>(0));
        try!(send_buf.write_u8(0));
        try!(send_buf.write_u8(0x02));   // flags
        try!(send_buf.write_u16::<BigEndian>(0));
        try!(send_buf.write_u32::<BigEndian>(command.as_ref().len() as u32));
        try!(send_buf.write_u32::<BigEndian>(0));
        try!(send_buf.write_u64::<BigEndian>(0));
        send_buf.extend_from_slice(command.as_ref().as_bytes());
        let _ = stream.write_all(send_buf.as_slice());

        // receive and check protocol header value
        let mut read_buf = vec![0; RECV_BUF_SIZE];
        let _ = stream.read(&mut read_buf);
        let mut buf = Cursor::new(read_buf);

        let protocol = try!(buf.read_u8());
        let query_type = try!(buf.read_u8());
        if protocol != 0xc7 || query_type > 5 {
            return Err(GQTPError::InvalidProtocol);
        }
        let _ = try!(buf.read_i16::<BigEndian>());
        let _ = try!(buf.read_u8());

        let flags = try!(buf.read_u8());
        if !((flags & 0x01) == 0x01 || (flags & 0x02) == 0x02) {
            return Err(GQTPError::InvalidProtocol);
        }

        let status = try!(buf.read_u16::<BigEndian>());
        if status != 0 && status != 1 {
            return Err(GQTPError::StatusError(status));
        }
        let size = try!(buf.read_i32::<BigEndian>());
        let _ = try!(buf.read_i32::<BigEndian>());    // opaque
        let _ = try!(buf.read_i64::<BigEndian>());    // cas

        // read body
        let mut msg_buf_len = if (size as usize + GQTP_HEADER_SIZE) > RECV_BUF_SIZE {
            RECV_BUF_SIZE - GQTP_HEADER_SIZE
        } else {
            size as usize
        };
        let mut msg = vec![0; msg_buf_len];
        let _ = try!(buf.read(&mut msg));
        if (size as usize + GQTP_HEADER_SIZE) > RECV_BUF_SIZE {
            loop {
                let mut read_buf = vec![0; RECV_BUF_SIZE];
                let rsize = try!(stream.read(&mut read_buf));
                msg.extend_from_slice(read_buf.as_ref());
                msg_buf_len += rsize;
                if msg_buf_len >= size as usize {
                    break;
                }
            }
        }

        Ok(String::from_utf8(msg).unwrap())
    }
}

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

    #[test]
    fn smoke_gqtp() {
        let req = GQTPRequest::new();
        assert_eq!("127.0.0.1:10043", req.addr)
    }

    #[test]
    fn smoke_gqtp_with_addr() {
        let req = GQTPRequest::new().with_addr("127.0.0.1:20043");
        assert_eq!("127.0.0.1:20043", req.addr)
    }
}
<commit_msg>gqtp_request: Add error handling for FromUtf8Error<commit_after>use std::io;
use std::io::Cursor;
use std::io::prelude::*;
use std::net::TcpStream;
use std::string::FromUtf8Error;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

const RECV_BUF_SIZE: usize = 8192;
const GQTP_HEADER_SIZE: usize = 24;

#[derive(Debug)]
pub enum GQTPError {
    InvalidProtocol,
    InvalidBodySize,
    StatusError(u16),
    IO(io::Error),
    EncodingError(FromUtf8Error)
}

impl From<io::Error> for GQTPError {
    fn from(err: io::Error) -> GQTPError {
        GQTPError::IO(err)
    }
}

impl From<FromUtf8Error> for GQTPError {
    fn from(err: FromUtf8Error) -> GQTPError {
        GQTPError::EncodingError(err)
    }
}

/// Request [GQTP protocol](http://groonga.org/docs/spec/gqtp.html) over TcpStream
pub struct GQTPRequest<'a> {
    addr: &'a str,
}

impl<'a> Default for GQTPRequest<'a> {
    fn default() -> GQTPRequest<'a> {
        GQTPRequest { addr: "127.0.0.1:10043" }
    }
}

impl<'a> GQTPRequest<'a> {
    /// Create a GQTP client.
    pub fn new() -> GQTPRequest<'a> {
        GQTPRequest::default()
    }

    /// Set host address for GQTP server.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate ruroonga_client as groonga;
    ///
    /// groonga::GQTPRequest::new().with_addr("127.0.0.1:20043");
    /// ```
    pub fn with_addr(mut self, addr: &'a str) -> GQTPRequest<'a> {
        self.addr = addr;
        self
    }

    /// Send request and Receive response.
    pub fn call<C>(&self, command: C) -> Result<String, GQTPError>
        where C: AsRef<str>
    {
        // send
        let mut stream = TcpStream::connect(self.addr).unwrap();
        let mut send_buf = vec![];
        try!(send_buf.write_u8(0xc7));
        try!(send_buf.write_u8(0));
        try!(send_buf.write_i16::<BigEndian>(0));
        try!(send_buf.write_u8(0));
        try!(send_buf.write_u8(0x02));   // flags
        try!(send_buf.write_u16::<BigEndian>(0));
        try!(send_buf.write_u32::<BigEndian>(command.as_ref().len() as u32));
        try!(send_buf.write_u32::<BigEndian>(0));
        try!(send_buf.write_u64::<BigEndian>(0));
        send_buf.extend_from_slice(command.as_ref().as_bytes());
        let _ = stream.write_all(send_buf.as_slice());

        // receive and check protocol header value
        let mut read_buf = vec![0; RECV_BUF_SIZE];
        let _ = stream.read(&mut read_buf);
        let mut buf = Cursor::new(read_buf);

        let protocol = try!(buf.read_u8());
        let query_type = try!(buf.read_u8());
        if protocol != 0xc7 || query_type > 5 {
            return Err(GQTPError::InvalidProtocol);
        }
        let _ = try!(buf.read_i16::<BigEndian>());
        let _ = try!(buf.read_u8());

        let flags = try!(buf.read_u8());
        if !((flags & 0x01) == 0x01 || (flags & 0x02) == 0x02) {
            return Err(GQTPError::InvalidProtocol);
        }

        let status = try!(buf.read_u16::<BigEndian>());
        if status != 0 && status != 1 {
            return Err(GQTPError::StatusError(status));
        }
        let size = try!(buf.read_i32::<BigEndian>());
        let _ = try!(buf.read_i32::<BigEndian>());    // opaque
        let _ = try!(buf.read_i64::<BigEndian>());    // cas

        // read body
        let mut msg_buf_len = if (size as usize + GQTP_HEADER_SIZE) > RECV_BUF_SIZE {
            RECV_BUF_SIZE - GQTP_HEADER_SIZE
        } else {
            size as usize
        };
        let mut msg = vec![0; msg_buf_len];
        let _ = try!(buf.read(&mut msg));
        if (size as usize + GQTP_HEADER_SIZE) > RECV_BUF_SIZE {
            loop {
                let mut read_buf = vec![0; RECV_BUF_SIZE];
                let rsize = try!(stream.read(&mut read_buf));
                msg.extend_from_slice(read_buf.as_ref());
                msg_buf_len += rsize;
                if msg_buf_len >= size as usize {
                    break;
                }
            }
        }

        Ok(try!(String::from_utf8(msg)))
    }
}

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

    #[test]
    fn smoke_gqtp() {
        let req = GQTPRequest::new();
        assert_eq!("127.0.0.1:10043", req.addr)
    }

    #[test]
    fn smoke_gqtp_with_addr() {
        let req = GQTPRequest::new().with_addr("127.0.0.1:20043");
        assert_eq!("127.0.0.1:20043", req.addr)
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient group-and-fold operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// This is the generic way to perform any operations on a `GroupingMap`.
    /// It's suggested to use this method only to implement custom operations
    /// when the already provided ones are not enough.
    ///
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let data = vec![10, 5, 7, 9, 0, 4, 2];
    /// let lookup = data.into_iter()
    ///     .map(|n| (n % 4, n))
    ///     .into_grouping_map()
    ///     .aggregate(|acc, _, val| {
    ///         match val {
    ///             0 | 2 => None,
    ///             _ => Some(acc.unwrap_or(0) + val)
    ///         }
    ///     });
    ///
    /// assert_eq!(lookup[&0], 4);
    /// assert_eq!(lookup[&1], 14);
    /// assert!(!lookup.contains_key(&2));
    /// assert_eq!(lookup[&3], 7);
    /// assert_eq!(lookup.len(), 3);
    /// ```
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let lookup = (1..=7)
    ///     .map(|n| (n % 3, n))
    ///     .into_grouping_map()
    ///     .fold(0, |acc, _, val| acc + val);
    ///
    /// assert_eq!(lookup[&0], 9);
    /// assert_eq!(lookup[&1], 12);
    /// assert_eq!(lookup[&2], 7);
    /// assert_eq!(lookup.len(), 3);
    /// ```
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// [`fold`]: #tymethod.fold
    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    /// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
    /// an instance of `C`. The iteration order is preserved when inserting elements.
    ///
    /// Return a `HashMap` associating the key of each group with the collection containing the elements of that group.
    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    /// Groups elements from the `GroupingMap` source by key and counts them.
    ///
    /// Return a `HashMap` associating the key of each group with the number of elements in that group.
    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<commit_msg>Improved doctest for GroupingMap::aggregate<commit_after>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient group-and-fold operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// This is the generic way to perform any operations on a `GroupingMap`.
    /// It's suggested to use this method only to implement custom operations
    /// when the already provided ones are not enough.
    ///
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let data = vec![2, 8, 5, 7, 9, 0, 4, 10];
    /// let lookup = data.into_iter()
    ///     .map(|n| (n % 4, n))
    ///     .into_grouping_map()
    ///     .aggregate(|acc, _, val| {
    ///         if val == 0 || val == 10 {
    ///             None
    ///         } else {
    ///             Some(acc.unwrap_or(0) + val)
    ///         }
    ///     });
    ///
    /// assert_eq!(lookup[&0], 4);        // 0 resets the accumulator so only 4 is summed
    /// assert_eq!(lookup[&1], 14);       // 5 + 9
    /// assert_eq!(lookup.get(&2), None); // 10 resets the accumulator and nothing is summed afterward
    /// assert_eq!(lookup[&3], 7);        // 7
    /// assert_eq!(lookup.len(), 3);      // The final keys are only 0, 1 and 2
    /// ```
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let lookup = (1..=7)
    ///     .map(|n| (n % 3, n))
    ///     .into_grouping_map()
    ///     .fold(0, |acc, _, val| acc + val);
    ///
    /// assert_eq!(lookup[&0], 9);
    /// assert_eq!(lookup[&1], 12);
    /// assert_eq!(lookup[&2], 7);
    /// assert_eq!(lookup.len(), 3);
    /// ```
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// [`fold`]: #tymethod.fold
    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    /// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
    /// an instance of `C`. The iteration order is preserved when inserting elements.
    ///
    /// Return a `HashMap` associating the key of each group with the collection containing the elements of that group.
    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    /// Groups elements from the `GroupingMap` source by key and counts them.
    ///
    /// Return a `HashMap` associating the key of each group with the number of elements in that group.
    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<|endoftext|>


<commit_before>//! Support library for `cargo xtask` command.
//!
//! See https://github.com/matklad/cargo-xtask/

pub mod not_bash;
pub mod install;
pub mod dist;
pub mod pre_commit;

pub mod codegen;
mod ast_src;

use anyhow::Context;
use std::{
    env,
    io::Write,
    path::{Path, PathBuf},
    process::{Command, Stdio},
};
use walkdir::{DirEntry, WalkDir};

use crate::{
    codegen::Mode,
    not_bash::{date_iso, fs2, pushd, rm_rf, run},
};

pub use anyhow::Result;

const TOOLCHAIN: &str = "stable";

pub fn project_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(1)
    .unwrap()
    .to_path_buf()
}

pub fn rust_files(path: &Path) -> impl Iterator<Item = PathBuf> {
    let iter = WalkDir::new(path);
    return iter
        .into_iter()
        .filter_entry(|e| !is_hidden(e))
        .map(|e| e.unwrap())
        .filter(|e| !e.file_type().is_dir())
        .map(|e| e.into_path())
        .filter(|path| path.extension().map(|it| it == "rs").unwrap_or(false));

    fn is_hidden(entry: &DirEntry) -> bool {
        entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
    }
}

pub fn run_rustfmt(mode: Mode) -> Result<()> {
    let _dir = pushd(project_root());
    ensure_rustfmt()?;

    let check = if mode == Mode::Verify { "--check" } else { "" };
    run!("rustup run {} -- cargo fmt -- {}", TOOLCHAIN, check)?;
    Ok(())
}

fn reformat(text: impl std::fmt::Display) -> Result<String> {
    ensure_rustfmt()?;
    let mut rustfmt = Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "rustfmt", "--config-path"])
        .arg(project_root().join("rustfmt.toml"))
        .args(&["--config", "fn_single_line=true"])
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;
    write!(rustfmt.stdin.take().unwrap(), "{}", text)?;
    let output = rustfmt.wait_with_output()?;
    let stdout = String::from_utf8(output.stdout)?;
    let preamble = "Generated file, do not edit by hand, see `xtask/src/codegen`";
    Ok(format!("//! {}\n\n{}", preamble, stdout))
}

fn ensure_rustfmt() -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "fmt", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => return Ok(()),
        _ => (),
    };
    run!("rustup toolchain install {}", TOOLCHAIN)?;
    run!("rustup component add rustfmt --toolchain {}", TOOLCHAIN)?;
    Ok(())
}

pub fn run_clippy() -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "clippy", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => install_clippy().context("install clippy")?,
    };

    let allowed_lints = [
        "clippy::collapsible_if",
        "clippy::needless_pass_by_value",
        "clippy::nonminimal_bool",
        "clippy::redundant_pattern_matching",
    ];
    run!(
        "rustup run {} -- cargo clippy --all-features --all-targets -- -A {}",
        TOOLCHAIN,
        allowed_lints.join(" -A ")
    )?;
    Ok(())
}

fn install_clippy() -> Result<()> {
    run!("rustup toolchain install {}", TOOLCHAIN)?;
    run!("rustup component add clippy --toolchain {}", TOOLCHAIN)?;
    Ok(())
}

pub fn run_fuzzer() -> Result<()> {
    let _d = pushd("./crates/ra_syntax");
    if run!("cargo fuzz --help").is_err() {
        run!("cargo install cargo-fuzz")?;
    };

    run!("rustup run nightly -- cargo fuzz run parser")?;
    Ok(())
}

/// Cleans the `./target` dir after the build such that only
/// dependencies are cached on CI.
pub fn run_pre_cache() -> Result<()> {
    let slow_tests_cookie = Path::new("./target/.slow_tests_cookie");
    if !slow_tests_cookie.exists() {
        panic!("slow tests were skipped on CI!")
    }
    rm_rf(slow_tests_cookie)?;

    for entry in Path::new("./target/debug").read_dir()? {
        let entry = entry?;
        if entry.file_type().map(|it| it.is_file()).ok() == Some(true) {
            // Can't delete yourself on windows :-(
            if !entry.path().ends_with("xtask.exe") {
                rm_rf(&entry.path())?
            }
        }
    }

    fs2::remove_file("./target/.rustc_info.json")?;
    let to_delete = ["ra_", "heavy_test", "xtask"];
    for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() {
        for entry in Path::new(dir).read_dir()? {
            let entry = entry?;
            if to_delete.iter().any(|&it| entry.path().display().to_string().contains(it)) {
                // Can't delete yourself on windows :-(
                if !entry.path().ends_with("xtask.exe") {
                    rm_rf(&entry.path())?
                }
            }
        }
    }

    Ok(())
}

pub fn run_release(dry_run: bool) -> Result<()> {
    if !dry_run {
        run!("git switch release")?;
        run!("git fetch upstream --tags --force")?;
        run!("git reset --hard tags/nightly")?;
        run!("git push")?;
    }

    let website_root = project_root().join("../rust-analyzer.github.io");
    let changelog_dir = website_root.join("./thisweek/_posts");

    let today = date_iso()?;
    let commit = run!("git rev-parse HEAD")?;
    let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count();

    let contents = format!(
        "\
= Changelog #{}
:sectanchors:
:page-layout: post

Commit: commit:{}[] +
Release: release:{}[]

== New Features

* pr:[] .

== Fixes

== Internal Improvements
",
        changelog_n, commit, today
    );

    let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
    fs2::write(&path, &contents)?;

    fs2::copy(project_root().join("./docs/user/readme.adoc"), website_root.join("manual.adoc"))?;

    let tags = run!("git tag --list"; echo = false)?;
    let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();

    println!("\n    git log {}..HEAD --merges --reverse", prev_tag);

    Ok(())
}

fn is_release_tag(tag: &str) -> bool {
    tag.len() == "2020-02-24".len() && tag.starts_with(|c: char| c.is_ascii_digit())
}
<commit_msg>Avoid `rustup` invocation for non-rustup rust installation<commit_after>//! Support library for `cargo xtask` command.
//!
//! See https://github.com/matklad/cargo-xtask/

pub mod not_bash;
pub mod install;
pub mod dist;
pub mod pre_commit;

pub mod codegen;
mod ast_src;

use std::{
    env,
    io::Write,
    path::{Path, PathBuf},
    process::{Command, Stdio},
};
use walkdir::{DirEntry, WalkDir};

use crate::{
    codegen::Mode,
    not_bash::{date_iso, fs2, pushd, rm_rf, run},
};

pub use anyhow::{bail, Context as _, Result};

const RUSTFMT_TOOLCHAIN: &str = "stable";

pub fn project_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(1)
    .unwrap()
    .to_path_buf()
}

pub fn rust_files(path: &Path) -> impl Iterator<Item = PathBuf> {
    let iter = WalkDir::new(path);
    return iter
        .into_iter()
        .filter_entry(|e| !is_hidden(e))
        .map(|e| e.unwrap())
        .filter(|e| !e.file_type().is_dir())
        .map(|e| e.into_path())
        .filter(|path| path.extension().map(|it| it == "rs").unwrap_or(false));

    fn is_hidden(entry: &DirEntry) -> bool {
        entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
    }
}

pub fn run_rustfmt(mode: Mode) -> Result<()> {
    let _dir = pushd(project_root());
    ensure_rustfmt()?;

    if Command::new("cargo")
        .env("RUSTUP_TOOLCHAIN", RUSTFMT_TOOLCHAIN)
        .args(&["fmt", "--"])
        .args(if mode == Mode::Verify { &["--check"][..] } else { &[] })
        .stderr(Stdio::inherit())
        .status()?
        .success()
    {
        Ok(())
    } else {
        bail!("Rustfmt failed");
    }
}

fn reformat(text: impl std::fmt::Display) -> Result<String> {
    ensure_rustfmt()?;
    let mut rustfmt = Command::new("rustfmt")
        .env("RUSTUP_TOOLCHAIN", RUSTFMT_TOOLCHAIN)
        .args(&["--config-path"])
        .arg(project_root().join("rustfmt.toml"))
        .args(&["--config", "fn_single_line=true"])
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;
    write!(rustfmt.stdin.take().unwrap(), "{}", text)?;
    let output = rustfmt.wait_with_output()?;
    let stdout = String::from_utf8(output.stdout)?;
    let preamble = "Generated file, do not edit by hand, see `xtask/src/codegen`";
    Ok(format!("//! {}\n\n{}", preamble, stdout))
}

fn ensure_rustfmt() -> Result<()> {
    match Command::new("rustfmt")
        .args(&["--version"])
        .env("RUSTUP_TOOLCHAIN", RUSTFMT_TOOLCHAIN)
        .stdout(Stdio::piped())
        .stderr(Stdio::null())
        .spawn()
        .and_then(|child| child.wait_with_output())
    {
        Ok(output)
            if output.status.success()
                && std::str::from_utf8(&output.stdout)?.contains(RUSTFMT_TOOLCHAIN) =>
        {
            Ok(())
        }
        _ => {
            bail!(
                "Failed to run rustfmt from toolchain '{0}'. \
                Please run `rustup component add rustfmt --toolchain {0}` to install it.",
                RUSTFMT_TOOLCHAIN,
            );
        }
    }
}

pub fn run_clippy() -> Result<()> {
    match Command::new("cargo")
        .args(&["clippy", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => bail!(
            "Failed run cargo clippy. \
            Please run `rustup component add clippy` to install it.",
        ),
    };

    let allowed_lints = [
        "clippy::collapsible_if",
        "clippy::needless_pass_by_value",
        "clippy::nonminimal_bool",
        "clippy::redundant_pattern_matching",
    ];
    run!("cargo clippy --all-features --all-targets -- -A {}", allowed_lints.join(" -A "))?;
    Ok(())
}

pub fn run_fuzzer() -> Result<()> {
    let _d = pushd("./crates/ra_syntax");
    if run!("cargo fuzz --help").is_err() {
        run!("cargo install cargo-fuzz")?;
    };

    // Expecting nightly rustc
    match Command::new("rustc")
        .args(&["--version"])
        .env("RUSTUP_TOOLCHAIN", "nightly")
        .stdout(Stdio::piped())
        .stderr(Stdio::null())
        .spawn()
        .and_then(|child| child.wait_with_output())
    {
        Ok(output)
            if output.status.success()
                && std::str::from_utf8(&output.stdout)?.contains("nightly") => {}
        _ => bail!("fuzz tests require nightly rustc"),
    }

    let status = Command::new("cargo")
        .env("RUSTUP_TOOLCHAIN", "nightly")
        .args(&["fuzz", "run", "parser"])
        .stderr(Stdio::inherit())
        .status()?;
    if !status.success() {
        bail!("{}", status);
    }
    Ok(())
}

/// Cleans the `./target` dir after the build such that only
/// dependencies are cached on CI.
pub fn run_pre_cache() -> Result<()> {
    let slow_tests_cookie = Path::new("./target/.slow_tests_cookie");
    if !slow_tests_cookie.exists() {
        panic!("slow tests were skipped on CI!")
    }
    rm_rf(slow_tests_cookie)?;

    for entry in Path::new("./target/debug").read_dir()? {
        let entry = entry?;
        if entry.file_type().map(|it| it.is_file()).ok() == Some(true) {
            // Can't delete yourself on windows :-(
            if !entry.path().ends_with("xtask.exe") {
                rm_rf(&entry.path())?
            }
        }
    }

    fs2::remove_file("./target/.rustc_info.json")?;
    let to_delete = ["ra_", "heavy_test", "xtask"];
    for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() {
        for entry in Path::new(dir).read_dir()? {
            let entry = entry?;
            if to_delete.iter().any(|&it| entry.path().display().to_string().contains(it)) {
                // Can't delete yourself on windows :-(
                if !entry.path().ends_with("xtask.exe") {
                    rm_rf(&entry.path())?
                }
            }
        }
    }

    Ok(())
}

pub fn run_release(dry_run: bool) -> Result<()> {
    if !dry_run {
        run!("git switch release")?;
        run!("git fetch upstream --tags --force")?;
        run!("git reset --hard tags/nightly")?;
        run!("git push")?;
    }

    let website_root = project_root().join("../rust-analyzer.github.io");
    let changelog_dir = website_root.join("./thisweek/_posts");

    let today = date_iso()?;
    let commit = run!("git rev-parse HEAD")?;
    let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count();

    let contents = format!(
        "\
= Changelog #{}
:sectanchors:
:page-layout: post

Commit: commit:{}[] +
Release: release:{}[]

== New Features

* pr:[] .

== Fixes

== Internal Improvements
",
        changelog_n, commit, today
    );

    let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
    fs2::write(&path, &contents)?;

    fs2::copy(project_root().join("./docs/user/readme.adoc"), website_root.join("manual.adoc"))?;

    let tags = run!("git tag --list"; echo = false)?;
    let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();

    println!("\n    git log {}..HEAD --merges --reverse", prev_tag);

    Ok(())
}

fn is_release_tag(tag: &str) -> bool {
    tag.len() == "2020-02-24".len() && tag.starts_with(|c: char| c.is_ascii_digit())
}
<|endoftext|>