<commit_before>use std::io::Read;
use std::path;

use ::image;
use gfx;

use crate::context::{Context, DebugId};
use crate::error::GameError;
use crate::error::GameResult;
use crate::filesystem;
use crate::graphics;
use crate::graphics::shader::*;
use crate::graphics::*;

/// Generic in-GPU-memory image data available to be drawn on the screen.
/// You probably just want to look at the `Image` type.
#[derive(Clone, PartialEq)]
pub struct ImageGeneric<B>
where
    B: BackendSpec,
{
    pub(crate) texture: gfx::handle::RawShaderResourceView<B::Resources>,
    pub(crate) texture_handle: gfx::handle::RawTexture<B::Resources>,
    pub(crate) sampler_info: gfx::texture::SamplerInfo,
    pub(crate) blend_mode: Option<BlendMode>,
    pub(crate) width: u16,
    pub(crate) height: u16,

    pub(crate) debug_id: DebugId,
}

impl<B> ImageGeneric<B>
where
    B: BackendSpec,
{
    /// A helper function that just takes a factory directly so we can make an image
    /// without needing the full context object, so we can create an Image while still
    /// creating the GraphicsContext.
    pub(crate) fn make_raw(
        factory: &mut <B as BackendSpec>::Factory,
        sampler_info: &texture::SamplerInfo,
        width: u16,
        height: u16,
        rgba: &[u8],
        color_format: gfx::format::Format,
        debug_id: DebugId,
    ) -> GameResult<Self> {
        if width == 0 || height == 0 {
            let msg = format!(
                "Tried to create a texture of size {}x{}, each dimension must
                be >0",
                width, height
            );
            return Err(GameError::ResourceLoadError(msg));
        }
        // Check for overflow, which might happen on 32-bit systems.
        // Textures can be max u16*u16, pixels, but then have 4 bytes per pixel.
        let uwidth = width as usize;
        let uheight = height as usize;
        let expected_bytes = uwidth
            .checked_mul(uheight)
            .and_then(|size| size.checked_mul(4))
            .ok_or_else(|| {
                let msg = format!(
                    "Integer overflow in Image::make_raw, image size: {} {}",
                    uwidth, uheight
                );
                GameError::ResourceLoadError(msg)
            })?;
        if expected_bytes != rgba.len() {
            let msg = format!(
                "Tried to create a texture of size {}x{}, but gave {} bytes of data (expected {})",
                width,
                height,
                rgba.len(),
                expected_bytes
            );
            return Err(GameError::ResourceLoadError(msg));
        }
        let kind = gfx::texture::Kind::D2(width, height, gfx::texture::AaMode::Single);
        use gfx::memory::Bind;
        let gfx::format::Format(surface_format, channel_type) = color_format;
        let texinfo = gfx::texture::Info {
            kind,
            levels: 1,
            format: surface_format,
            bind: Bind::SHADER_RESOURCE
                | Bind::RENDER_TARGET
                | Bind::TRANSFER_SRC
                | Bind::TRANSFER_DST,
            usage: gfx::memory::Usage::Dynamic,
        };
        let raw_tex = factory.create_texture_raw(
            texinfo,
            Some(channel_type),
            Some((&[rgba], gfx::texture::Mipmap::Provided)),
        )?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: channel_type,
            layer: None,
            min: 0,
            max: raw_tex.get_info().levels - 1,
            swizzle: gfx::format::Swizzle::new(),
        };
        let raw_view = factory.view_texture_as_shader_resource_raw(&raw_tex, resource_desc)?;
        Ok(Self {
            texture: raw_view,
            texture_handle: raw_tex,
            sampler_info: *sampler_info,
            blend_mode: None,
            width,
            height,
            debug_id,
        })
    }
}

/// In-GPU-memory image data available to be drawn on the screen,
/// using the OpenGL backend.
///
/// Under the hood this is just an `Arc`'ed texture handle and
/// some metadata, so cloning it is fairly cheap; it doesn't
/// make another copy of the underlying image data.
pub type Image = ImageGeneric<GlBackendSpec>;

/// The supported formats for saving an image.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ImageFormat {
    /// .png image format (defaults to RGBA with 8-bit channels.)
    Png,
}

impl Image {
    /// Load a new image from the file at the given path. The documentation for the
    /// [`filesystem`](../filesystem/index.html) module explains how the path must be specified.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let img = {
            let mut buf = Vec::new();
            let mut reader = context.filesystem.open(path)?;
            let _ = reader.read_to_end(&mut buf)?;
            image::load_from_memory(&buf)?.to_rgba()
        };
        let (width, height) = img.dimensions();
        Self::from_rgba8(context, width as u16, height as u16, &img)
    }

    /// Creates a new `Image` from the given buffer of `u8` RGBA values.
    ///
    /// The pixel layout is row-major.  That is,
    /// the first 4 `u8` values make the top-left pixel in the `Image`, the
    /// next 4 make the next pixel in the same row, and so on to the end of
    /// the row.  The next `width * 4` values make up the second row, and so
    /// on.
    pub fn from_rgba8(
        context: &mut Context,
        width: u16,
        height: u16,
        rgba: &[u8],
    ) -> GameResult<Self> {
        let debug_id = DebugId::get(context);
        let color_format = context.gfx_context.color_format();
        Self::make_raw(
            &mut *context.gfx_context.factory,
            &context.gfx_context.default_sampler_info,
            width,
            height,
            rgba,
            color_format,
            debug_id,
        )
    }

    /// Dumps the `Image`'s data to a `Vec` of `u8` RGBA values.
    pub fn to_rgba8(&self, ctx: &mut Context) -> GameResult<Vec<u8>> {
        use gfx::memory::Typed;
        use gfx::traits::FactoryExt;

        let gfx = &mut ctx.gfx_context;
        let w = self.width;
        let h = self.height;

        // Note: In the GFX example, the download buffer is created ahead of time
        // and updated on screen resize events. This may be preferable, but then
        // the buffer also needs to be updated when we switch to/from a canvas.
        // Unsure of the performance impact of creating this as it is needed.
        // Probably okay for now though, since this probably won't be a super
        // common operation.
        let dl_buffer = gfx
            .factory
            .create_download_buffer::<[u8; 4]>(w as usize * h as usize)?;

        let factory = &mut *gfx.factory;
        let mut local_encoder = GlBackendSpec::encoder(factory);

        local_encoder.copy_texture_to_buffer_raw(
            &self.texture_handle,
            None,
            gfx::texture::RawImageInfo {
                xoffset: 0,
                yoffset: 0,
                zoffset: 0,
                width: w as u16,
                height: h as u16,
                depth: 0,
                format: gfx.color_format(),
                mipmap: 0,
            },
            dl_buffer.raw(),
            0,
        )?;
        local_encoder.flush(&mut *gfx.device);

        let reader = gfx.factory.read_mapping(&dl_buffer)?;

        // intermediary buffer to avoid casting.
        let mut data = Vec::with_capacity(self.width as usize * self.height as usize * 4);
        // Assuming OpenGL backend whose typical readback option (glReadPixels) has origin at bottom left.
        // Image formats on the other hand usually deal with top right.
        for y in (0..self.height as usize).rev() {
            data.extend(
                reader
                    .iter()
                    .skip(y * self.width as usize)
                    .take(self.width as usize)
                    .flatten(),
            );
        }
        Ok(data)
    }

    /// Encode the `Image` to the given file format and
    /// write it out to the given path.
    ///
    /// See the [`filesystem`](../filesystem/index.html) module docs for where exactly
    /// the file will end up.
    pub fn encode<P: AsRef<path::Path>>(
        &self,
        ctx: &mut Context,
        format: ImageFormat,
        path: P,
    ) -> GameResult {
        use std::io;
        let data = self.to_rgba8(ctx)?;
        let f = filesystem::create(ctx, path)?;
        let writer = &mut io::BufWriter::new(f);
        let color_format = image::ColorType::RGBA(8);
        match format {
            ImageFormat::Png => image::png::PNGEncoder::new(writer)
                .encode(
                    &data,
                    u32::from(self.width),
                    u32::from(self.height),
                    color_format,
                )
                .map_err(Into::into),
        }
    }

    /// A little helper function that creates a new `Image` that is just
    /// a solid square of the given size and color.  Mainly useful for
    /// debugging.
    pub fn solid(context: &mut Context, size: u16, color: Color) -> GameResult<Self> {
        let (r, g, b, a) = color.into();
        let pixel_array: [u8; 4] = [r, g, b, a];
        let size_squared = size as usize * size as usize;
        let mut buffer = Vec::with_capacity(size_squared);
        for _i in 0..size_squared {
            buffer.extend(&pixel_array[..]);
        }
        Image::from_rgba8(context, size, size, &buffer)
    }

    /// Return the width of the image.
    pub fn width(&self) -> u16 {
        self.width
    }

    /// Return the height of the image.
    pub fn height(&self) -> u16 {
        self.height
    }

    /// Get the filter mode for the image.
    pub fn filter(&self) -> FilterMode {
        self.sampler_info.filter.into()
    }

    /// Set the filter mode for the image.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.sampler_info.filter = mode.into();
    }

    /// Returns the dimensions of the image.
    pub fn dimensions(&self) -> Rect {
        Rect::new(0.0, 0.0, f32::from(self.width()), f32::from(self.height()))
    }

    /// Gets the `Image`'s `WrapMode` along the X and Y axes.
    pub fn wrap(&self) -> (WrapMode, WrapMode) {
        (self.sampler_info.wrap_mode.0, self.sampler_info.wrap_mode.1)
    }

    /// Sets the `Image`'s `WrapMode` along the X and Y axes.
    pub fn set_wrap(&mut self, wrap_x: WrapMode, wrap_y: WrapMode) {
        self.sampler_info.wrap_mode.0 = wrap_x;
        self.sampler_info.wrap_mode.1 = wrap_y;
    }
}

impl fmt::Debug for Image {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "<Image: {}x{}, {:p}, texture address {:p}, sampler: {:?}>",
            self.width(),
            self.height(),
            self,
            &self.texture,
            &self.sampler_info
        )
    }
}

impl Drawable for Image {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        self.debug_id.assert(ctx);

        let gfx = &mut ctx.gfx_context;
        let src_width = param.src.w;
        let src_height = param.src.h;
        // We have to mess with the scale to make everything
        // be its-unit-size-in-pixels.
        let real_scale = nalgebra::Vector2::new(
            param.scale.x * src_width * f32::from(self.width),
            param.scale.y * src_height * f32::from(self.height),
        );

        let mut new_param = param;
        new_param.scale = real_scale.into();

        gfx.update_instance_properties(new_param.into())?;
        let sampler = gfx
            .samplers
            .get_or_insert(self.sampler_info, gfx.factory.as_mut());
        gfx.data.vbuf = gfx.quad_vertex_buffer.clone();
        let typed_thingy = gfx
            .backend_spec
            .raw_to_typed_shader_resource(self.texture.clone());
        gfx.data.tex = (typed_thingy, sampler);
        let previous_mode: Option<BlendMode> = if let Some(mode) = self.blend_mode {
            let current_mode = gfx.blend_mode();
            if current_mode != mode {
                gfx.set_blend_mode(mode)?;
                Some(current_mode)
            } else {
                None
            }
        } else {
            None
        };

        gfx.draw(None)?;
        if let Some(mode) = previous_mode {
            gfx.set_blend_mode(mode)?;
        }
        Ok(())
    }

    fn dimensions(&self, _: &mut Context) -> Option<graphics::Rect> {
        Some(self.dimensions())
    }

    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.blend_mode = mode;
    }

    fn blend_mode(&self) -> Option<BlendMode> {
        self.blend_mode
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::ContextBuilder;
    #[test]
    fn test_invalid_image_size() {
        let (ctx, _) = &mut ContextBuilder::new("unittest", "unittest").build().unwrap();
        let _i = assert!(Image::from_rgba8(ctx, 0, 0, &vec![]).is_err());
        let _i = assert!(Image::from_rgba8(ctx, 3432, 432, &vec![]).is_err());
        let _i = Image::from_rgba8(ctx, 2, 2, &vec![99; 16]).unwrap();
    }
}
<commit_msg>Replaces vec! with slices on image.rs<commit_after>use std::io::Read;
use std::path;

use ::image;
use gfx;

use crate::context::{Context, DebugId};
use crate::error::GameError;
use crate::error::GameResult;
use crate::filesystem;
use crate::graphics;
use crate::graphics::shader::*;
use crate::graphics::*;

/// Generic in-GPU-memory image data available to be drawn on the screen.
/// You probably just want to look at the `Image` type.
#[derive(Clone, PartialEq)]
pub struct ImageGeneric<B>
where
    B: BackendSpec,
{
    pub(crate) texture: gfx::handle::RawShaderResourceView<B::Resources>,
    pub(crate) texture_handle: gfx::handle::RawTexture<B::Resources>,
    pub(crate) sampler_info: gfx::texture::SamplerInfo,
    pub(crate) blend_mode: Option<BlendMode>,
    pub(crate) width: u16,
    pub(crate) height: u16,

    pub(crate) debug_id: DebugId,
}

impl<B> ImageGeneric<B>
where
    B: BackendSpec,
{
    /// A helper function that just takes a factory directly so we can make an image
    /// without needing the full context object, so we can create an Image while still
    /// creating the GraphicsContext.
    pub(crate) fn make_raw(
        factory: &mut <B as BackendSpec>::Factory,
        sampler_info: &texture::SamplerInfo,
        width: u16,
        height: u16,
        rgba: &[u8],
        color_format: gfx::format::Format,
        debug_id: DebugId,
    ) -> GameResult<Self> {
        if width == 0 || height == 0 {
            let msg = format!(
                "Tried to create a texture of size {}x{}, each dimension must
                be >0",
                width, height
            );
            return Err(GameError::ResourceLoadError(msg));
        }
        // Check for overflow, which might happen on 32-bit systems.
        // Textures can be max u16*u16, pixels, but then have 4 bytes per pixel.
        let uwidth = width as usize;
        let uheight = height as usize;
        let expected_bytes = uwidth
            .checked_mul(uheight)
            .and_then(|size| size.checked_mul(4))
            .ok_or_else(|| {
                let msg = format!(
                    "Integer overflow in Image::make_raw, image size: {} {}",
                    uwidth, uheight
                );
                GameError::ResourceLoadError(msg)
            })?;
        if expected_bytes != rgba.len() {
            let msg = format!(
                "Tried to create a texture of size {}x{}, but gave {} bytes of data (expected {})",
                width,
                height,
                rgba.len(),
                expected_bytes
            );
            return Err(GameError::ResourceLoadError(msg));
        }
        let kind = gfx::texture::Kind::D2(width, height, gfx::texture::AaMode::Single);
        use gfx::memory::Bind;
        let gfx::format::Format(surface_format, channel_type) = color_format;
        let texinfo = gfx::texture::Info {
            kind,
            levels: 1,
            format: surface_format,
            bind: Bind::SHADER_RESOURCE
                | Bind::RENDER_TARGET
                | Bind::TRANSFER_SRC
                | Bind::TRANSFER_DST,
            usage: gfx::memory::Usage::Dynamic,
        };
        let raw_tex = factory.create_texture_raw(
            texinfo,
            Some(channel_type),
            Some((&[rgba], gfx::texture::Mipmap::Provided)),
        )?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: channel_type,
            layer: None,
            min: 0,
            max: raw_tex.get_info().levels - 1,
            swizzle: gfx::format::Swizzle::new(),
        };
        let raw_view = factory.view_texture_as_shader_resource_raw(&raw_tex, resource_desc)?;
        Ok(Self {
            texture: raw_view,
            texture_handle: raw_tex,
            sampler_info: *sampler_info,
            blend_mode: None,
            width,
            height,
            debug_id,
        })
    }
}

/// In-GPU-memory image data available to be drawn on the screen,
/// using the OpenGL backend.
///
/// Under the hood this is just an `Arc`'ed texture handle and
/// some metadata, so cloning it is fairly cheap; it doesn't
/// make another copy of the underlying image data.
pub type Image = ImageGeneric<GlBackendSpec>;

/// The supported formats for saving an image.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ImageFormat {
    /// .png image format (defaults to RGBA with 8-bit channels.)
    Png,
}

impl Image {
    /// Load a new image from the file at the given path. The documentation for the
    /// [`filesystem`](../filesystem/index.html) module explains how the path must be specified.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let img = {
            let mut buf = Vec::new();
            let mut reader = context.filesystem.open(path)?;
            let _ = reader.read_to_end(&mut buf)?;
            image::load_from_memory(&buf)?.to_rgba()
        };
        let (width, height) = img.dimensions();
        Self::from_rgba8(context, width as u16, height as u16, &img)
    }

    /// Creates a new `Image` from the given buffer of `u8` RGBA values.
    ///
    /// The pixel layout is row-major.  That is,
    /// the first 4 `u8` values make the top-left pixel in the `Image`, the
    /// next 4 make the next pixel in the same row, and so on to the end of
    /// the row.  The next `width * 4` values make up the second row, and so
    /// on.
    pub fn from_rgba8(
        context: &mut Context,
        width: u16,
        height: u16,
        rgba: &[u8],
    ) -> GameResult<Self> {
        let debug_id = DebugId::get(context);
        let color_format = context.gfx_context.color_format();
        Self::make_raw(
            &mut *context.gfx_context.factory,
            &context.gfx_context.default_sampler_info,
            width,
            height,
            rgba,
            color_format,
            debug_id,
        )
    }

    /// Dumps the `Image`'s data to a `Vec` of `u8` RGBA values.
    pub fn to_rgba8(&self, ctx: &mut Context) -> GameResult<Vec<u8>> {
        use gfx::memory::Typed;
        use gfx::traits::FactoryExt;

        let gfx = &mut ctx.gfx_context;
        let w = self.width;
        let h = self.height;

        // Note: In the GFX example, the download buffer is created ahead of time
        // and updated on screen resize events. This may be preferable, but then
        // the buffer also needs to be updated when we switch to/from a canvas.
        // Unsure of the performance impact of creating this as it is needed.
        // Probably okay for now though, since this probably won't be a super
        // common operation.
        let dl_buffer = gfx
            .factory
            .create_download_buffer::<[u8; 4]>(w as usize * h as usize)?;

        let factory = &mut *gfx.factory;
        let mut local_encoder = GlBackendSpec::encoder(factory);

        local_encoder.copy_texture_to_buffer_raw(
            &self.texture_handle,
            None,
            gfx::texture::RawImageInfo {
                xoffset: 0,
                yoffset: 0,
                zoffset: 0,
                width: w as u16,
                height: h as u16,
                depth: 0,
                format: gfx.color_format(),
                mipmap: 0,
            },
            dl_buffer.raw(),
            0,
        )?;
        local_encoder.flush(&mut *gfx.device);

        let reader = gfx.factory.read_mapping(&dl_buffer)?;

        // intermediary buffer to avoid casting.
        let mut data = Vec::with_capacity(self.width as usize * self.height as usize * 4);
        // Assuming OpenGL backend whose typical readback option (glReadPixels) has origin at bottom left.
        // Image formats on the other hand usually deal with top right.
        for y in (0..self.height as usize).rev() {
            data.extend(
                reader
                    .iter()
                    .skip(y * self.width as usize)
                    .take(self.width as usize)
                    .flatten(),
            );
        }
        Ok(data)
    }

    /// Encode the `Image` to the given file format and
    /// write it out to the given path.
    ///
    /// See the [`filesystem`](../filesystem/index.html) module docs for where exactly
    /// the file will end up.
    pub fn encode<P: AsRef<path::Path>>(
        &self,
        ctx: &mut Context,
        format: ImageFormat,
        path: P,
    ) -> GameResult {
        use std::io;
        let data = self.to_rgba8(ctx)?;
        let f = filesystem::create(ctx, path)?;
        let writer = &mut io::BufWriter::new(f);
        let color_format = image::ColorType::RGBA(8);
        match format {
            ImageFormat::Png => image::png::PNGEncoder::new(writer)
                .encode(
                    &data,
                    u32::from(self.width),
                    u32::from(self.height),
                    color_format,
                )
                .map_err(Into::into),
        }
    }

    /// A little helper function that creates a new `Image` that is just
    /// a solid square of the given size and color.  Mainly useful for
    /// debugging.
    pub fn solid(context: &mut Context, size: u16, color: Color) -> GameResult<Self> {
        let (r, g, b, a) = color.into();
        let pixel_array: [u8; 4] = [r, g, b, a];
        let size_squared = size as usize * size as usize;
        let mut buffer = Vec::with_capacity(size_squared);
        for _i in 0..size_squared {
            buffer.extend(&pixel_array[..]);
        }
        Image::from_rgba8(context, size, size, &buffer)
    }

    /// Return the width of the image.
    pub fn width(&self) -> u16 {
        self.width
    }

    /// Return the height of the image.
    pub fn height(&self) -> u16 {
        self.height
    }

    /// Get the filter mode for the image.
    pub fn filter(&self) -> FilterMode {
        self.sampler_info.filter.into()
    }

    /// Set the filter mode for the image.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.sampler_info.filter = mode.into();
    }

    /// Returns the dimensions of the image.
    pub fn dimensions(&self) -> Rect {
        Rect::new(0.0, 0.0, f32::from(self.width()), f32::from(self.height()))
    }

    /// Gets the `Image`'s `WrapMode` along the X and Y axes.
    pub fn wrap(&self) -> (WrapMode, WrapMode) {
        (self.sampler_info.wrap_mode.0, self.sampler_info.wrap_mode.1)
    }

    /// Sets the `Image`'s `WrapMode` along the X and Y axes.
    pub fn set_wrap(&mut self, wrap_x: WrapMode, wrap_y: WrapMode) {
        self.sampler_info.wrap_mode.0 = wrap_x;
        self.sampler_info.wrap_mode.1 = wrap_y;
    }
}

impl fmt::Debug for Image {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "<Image: {}x{}, {:p}, texture address {:p}, sampler: {:?}>",
            self.width(),
            self.height(),
            self,
            &self.texture,
            &self.sampler_info
        )
    }
}

impl Drawable for Image {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        self.debug_id.assert(ctx);

        let gfx = &mut ctx.gfx_context;
        let src_width = param.src.w;
        let src_height = param.src.h;
        // We have to mess with the scale to make everything
        // be its-unit-size-in-pixels.
        let real_scale = nalgebra::Vector2::new(
            param.scale.x * src_width * f32::from(self.width),
            param.scale.y * src_height * f32::from(self.height),
        );

        let mut new_param = param;
        new_param.scale = real_scale.into();

        gfx.update_instance_properties(new_param.into())?;
        let sampler = gfx
            .samplers
            .get_or_insert(self.sampler_info, gfx.factory.as_mut());
        gfx.data.vbuf = gfx.quad_vertex_buffer.clone();
        let typed_thingy = gfx
            .backend_spec
            .raw_to_typed_shader_resource(self.texture.clone());
        gfx.data.tex = (typed_thingy, sampler);
        let previous_mode: Option<BlendMode> = if let Some(mode) = self.blend_mode {
            let current_mode = gfx.blend_mode();
            if current_mode != mode {
                gfx.set_blend_mode(mode)?;
                Some(current_mode)
            } else {
                None
            }
        } else {
            None
        };

        gfx.draw(None)?;
        if let Some(mode) = previous_mode {
            gfx.set_blend_mode(mode)?;
        }
        Ok(())
    }

    fn dimensions(&self, _: &mut Context) -> Option<graphics::Rect> {
        Some(self.dimensions())
    }

    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.blend_mode = mode;
    }

    fn blend_mode(&self) -> Option<BlendMode> {
        self.blend_mode
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::ContextBuilder;
    #[test]
    fn test_invalid_image_size() {
        let (ctx, _) = &mut ContextBuilder::new("unittest", "unittest").build().unwrap();
        let _i = assert!(Image::from_rgba8(ctx, 0, 0, &[]).is_err());
        let _i = assert!(Image::from_rgba8(ctx, 3432, 432, &[]).is_err());
        let _i = Image::from_rgba8(ctx, 2, 2, &[99; 16]).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::fmt;

/// How the [`Context`](../block/struct.Context.html) will be printed by the [`Logger`](../logger/index.html).
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ContextLabel {
    Describe,
    Context,
    Specify,
    Given,
    When,
}

impl fmt::Display for ContextLabel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ContextLabel::Describe => write!(f, "Describe"),
            &ContextLabel::Context => write!(f, "Context"),
            &ContextLabel::Specify => write!(f, "Specify"),
            &ContextLabel::Given => write!(f, "Given"),
            &ContextLabel::When => write!(f, "When"),
        }
    }
}

/// A [`Header`](trait.Header.html) with label and name of a [`Context`](../block/struct.Context.html).
#[derive(Clone, PartialEq, Eq, Debug, new)]
pub struct ContextHeader {
    pub label: ContextLabel,
    pub name: &'static str,
}

impl fmt::Display for ContextHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {:?}", self.label, self.name)
    }
}

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

    #[test]
    fn label_fmt() {
        fn subject(label: ContextLabel) -> String {
            format!("{}", label)
        };
        assert_eq!(subject(ContextLabel::Context), "Context".to_owned());
        assert_eq!(subject(ContextLabel::Specify), "Specify".to_owned());
        assert_eq!(subject(ContextLabel::When), "When".to_owned());
    }

    #[test]
    fn header_fmt() {
        fn subject(label: ContextLabel) -> String {
            format!("{}", ContextHeader::new(label, "Test"))
        };
        assert_eq!(
            subject(ContextLabel::Context),
            "Context \"Test\"".to_owned()
        );
        assert_eq!(
            subject(ContextLabel::Specify),
            "Specify \"Test\"".to_owned()
        );
        assert_eq!(subject(ContextLabel::When), "When \"Test\"".to_owned());
    }
}
<commit_msg>Remove unused enum cases (they were extracted to `SuiteLabel`)<commit_after>use std::fmt;

/// How the [`Context`](../block/struct.Context.html) will be printed by the [`Logger`](../logger/index.html).
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ContextLabel {
    Context,
    Specify,
    When,
}

impl fmt::Display for ContextLabel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ContextLabel::Context => write!(f, "Context"),
            &ContextLabel::Specify => write!(f, "Specify"),
            &ContextLabel::When => write!(f, "When"),
        }
    }
}

/// A [`Header`](trait.Header.html) with label and name of a [`Context`](../block/struct.Context.html).
#[derive(Clone, PartialEq, Eq, Debug, new)]
pub struct ContextHeader {
    pub label: ContextLabel,
    pub name: &'static str,
}

impl fmt::Display for ContextHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {:?}", self.label, self.name)
    }
}

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

    #[test]
    fn label_fmt() {
        fn subject(label: ContextLabel) -> String {
            format!("{}", label)
        };
        assert_eq!(subject(ContextLabel::Context), "Context".to_owned());
        assert_eq!(subject(ContextLabel::Specify), "Specify".to_owned());
        assert_eq!(subject(ContextLabel::When), "When".to_owned());
    }

    #[test]
    fn header_fmt() {
        fn subject(label: ContextLabel) -> String {
            format!("{}", ContextHeader::new(label, "Test"))
        };
        assert_eq!(
            subject(ContextLabel::Context),
            "Context \"Test\"".to_owned()
        );
        assert_eq!(
            subject(ContextLabel::Specify),
            "Specify \"Test\"".to_owned()
        );
        assert_eq!(subject(ContextLabel::When), "When \"Test\"".to_owned());
    }
}
<|endoftext|>


<commit_before>use proc_macro2::{Ident, Span};
use std::fmt;

/// Specialized formatting trait used by `format_ident!`.
///
/// [`Ident`] arguments formatted using this trait will have their `r#` prefix
/// stripped, if present.
///
/// See [`format_ident!`] for more information.
pub trait IdentFragment {
    /// Format this value as an identifier fragment.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;

    /// Span associated with this `IdentFragment`.
    ///
    /// If non-`None`, may be inherited by formatted identifiers.
    fn span(&self) -> Option<Span> {
        None
    }
}

impl<T: IdentFragment + ?Sized> IdentFragment for &T {
    fn span(&self) -> Option<Span> {
        <T as IdentFragment>::span(*self)
    }

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        IdentFragment::fmt(*self, f)
    }
}

impl<T: IdentFragment + ?Sized> IdentFragment for &mut T {
    fn span(&self) -> Option<Span> {
        <T as IdentFragment>::span(*self)
    }

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        IdentFragment::fmt(*self, f)
    }
}

impl IdentFragment for Ident {
    fn span(&self) -> Option<Span> {
        Some(self.span())
    }

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let id = self.to_string();
        if id.starts_with("r#") {
            fmt::Display::fmt(&id[2..], f)
        } else {
            fmt::Display::fmt(&id[..], f)
        }
    }
}

// Limited set of types which this is implemented for, as we want to avoid types
// which will often include non-identifier characters in their `Display` impl.
macro_rules! ident_fragment_display {
    ($($T:ty),*) => {
        $(
            impl IdentFragment for $T {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                    fmt::Display::fmt(self, f)
                }
            }
        )*
    }
}

ident_fragment_display!(bool, str, String);
ident_fragment_display!(u8, u16, u32, u64, u128, usize);
<commit_msg>Allow char as a fragment in format_ident<commit_after>use proc_macro2::{Ident, Span};
use std::fmt;

/// Specialized formatting trait used by `format_ident!`.
///
/// [`Ident`] arguments formatted using this trait will have their `r#` prefix
/// stripped, if present.
///
/// See [`format_ident!`] for more information.
pub trait IdentFragment {
    /// Format this value as an identifier fragment.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;

    /// Span associated with this `IdentFragment`.
    ///
    /// If non-`None`, may be inherited by formatted identifiers.
    fn span(&self) -> Option<Span> {
        None
    }
}

impl<T: IdentFragment + ?Sized> IdentFragment for &T {
    fn span(&self) -> Option<Span> {
        <T as IdentFragment>::span(*self)
    }

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        IdentFragment::fmt(*self, f)
    }
}

impl<T: IdentFragment + ?Sized> IdentFragment for &mut T {
    fn span(&self) -> Option<Span> {
        <T as IdentFragment>::span(*self)
    }

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        IdentFragment::fmt(*self, f)
    }
}

impl IdentFragment for Ident {
    fn span(&self) -> Option<Span> {
        Some(self.span())
    }

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let id = self.to_string();
        if id.starts_with("r#") {
            fmt::Display::fmt(&id[2..], f)
        } else {
            fmt::Display::fmt(&id[..], f)
        }
    }
}

// Limited set of types which this is implemented for, as we want to avoid types
// which will often include non-identifier characters in their `Display` impl.
macro_rules! ident_fragment_display {
    ($($T:ty),*) => {
        $(
            impl IdentFragment for $T {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                    fmt::Display::fmt(self, f)
                }
            }
        )*
    }
}

ident_fragment_display!(bool, str, String, char);
ident_fragment_display!(u8, u16, u32, u64, u128, usize);
<|endoftext|>


<commit_before>use crate::codecs::DataFormat;
use crate::codecs::Encodable;
use std::io::Result;
use std::io::Write;

const ID: u64 = 2;
const MEDIA_TYPE: &str = "application/octet-stream";

/// The most basic data format. It just simply writes raw bytes into the channel, without
/// any regard of the underlying data's structure
pub struct RawBinDataFormat;
impl DataFormat for RawBinDataFormat {
    ///Returns 2, the id of the most basic encoder.
    #[inline]
    fn id() -> u64 {
        ID
    }
    ///Returns "application/octet-stream"
    #[inline]
    fn media_type() -> &'static str {
        MEDIA_TYPE
    }
}

impl<T: AsRef<[u8]>> Encodable<RawBinDataFormat> for T {
    #[inline]
    fn encode_to(&self, _format: &RawBinDataFormat, w: &mut impl Write) -> Result<usize> {
        w.write(self.as_ref())
    }
}

// impl<'a> Encodable<RawBinDataFormat> for &'a [u8] {
//     #[inline]
//     fn encode_to(&self, _format: &RawBinDataFormat, w: &mut impl Write) -> Result<usize> {
//         w.write(self)
//     }
// }

//Will see if this is need it or just a basic nice to have
//use std::io::Read;
// impl<'a> Encodable<RawBinDataFormat> for &'a Read {
//     fn encode_to(&mut self, _format: &RawBinDataFormat, w: &mut impl Write) {
//         std::io::copy(&mut self, w).unwrap();
//     }
// }

#[cfg(test)]
mod test {
    use super::*;
    use std::io::Cursor;
    use std::io::Read;

    #[test]
    fn check_raw_binary_encoder_slice() {
        let mut vec = Vec::<u8>::new();
        let mut cursor = Cursor::new(&mut vec);
        let msg = &[1u8; 10][..];
        let df = RawBinDataFormat;
        msg.encode_to(&df, &mut cursor).unwrap();
        assert_eq!(cursor.position() as usize, msg.len());
        cursor.set_position(0);
        let expected = &mut [11u8; 10][..];
        cursor.read_exact(expected).unwrap();
        assert_eq!(expected, msg);
    }
    #[test]
    fn check_data_format() {
        assert_eq!(RawBinDataFormat::id(), ID);
        assert_eq!(RawBinDataFormat::media_type(), MEDIA_TYPE);
    }
}
<commit_msg>Source code cleanup.<commit_after>use crate::codecs::DataFormat;
use crate::codecs::Encodable;
use std::io::Result;
use std::io::Write;

const ID: u64 = 2;
const MEDIA_TYPE: &str = "application/octet-stream";

/// The most basic data format. It just simply writes raw bytes into the channel, without
/// any regard of the underlying data's structure
pub struct RawBinDataFormat;
impl DataFormat for RawBinDataFormat {
    ///Returns 2, the id of the most basic encoder.
    #[inline]
    fn id() -> u64 {
        ID
    }
    ///Returns "application/octet-stream"
    #[inline]
    fn media_type() -> &'static str {
        MEDIA_TYPE
    }
}

impl<T: AsRef<[u8]>> Encodable<RawBinDataFormat> for T {
    #[inline]
    fn encode_to(&self, _format: &RawBinDataFormat, w: &mut impl Write) -> Result<usize> {
        w.write(self.as_ref())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::Cursor;
    use std::io::Read;

    #[test]
    fn check_raw_binary_encoder_slice() {
        let mut vec = Vec::<u8>::new();
        let mut cursor = Cursor::new(&mut vec);
        let msg = &[1u8; 10][..];
        let df = RawBinDataFormat;
        msg.encode_to(&df, &mut cursor).unwrap();
        assert_eq!(cursor.position() as usize, msg.len());
        cursor.set_position(0);
        let expected = &mut [11u8; 10][..];
        cursor.read_exact(expected).unwrap();
        assert_eq!(expected, msg);
    }
    #[test]
    fn check_data_format() {
        assert_eq!(RawBinDataFormat::id(), ID);
        assert_eq!(RawBinDataFormat::media_type(), MEDIA_TYPE);
    }
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]

use formatter::RdbParseFormatter;
use std::io;
use std::str;
use serialize::json;

pub struct JSONFormatter {
    out: Box<Writer+'static>,
    is_first_db: bool,
    has_databases: bool,
    is_first_key_in_db: bool,
    elements_in_key: u32,
    element_index: u32
}

impl JSONFormatter {
    pub fn new() -> JSONFormatter {
        let out = Box::new(io::stdout());
        JSONFormatter {
            out: out,
            is_first_db: true,
            has_databases: false,
            is_first_key_in_db: true,
            elements_in_key: 0,
            element_index: 0
        }
    }
}

fn encode_to_ascii(value: &[u8]) -> String {
    let s = unsafe{str::from_utf8_unchecked(value)};
    json::encode(&s)
}

impl JSONFormatter {
    fn start_key(&mut self, length: u32) {
        if !self.is_first_key_in_db {
            self.out.write_str(",");
        }

        self.is_first_key_in_db = false;
        self.elements_in_key = length;
        self.element_index = 0;
    }

    fn end_key(&mut self) { }

    fn write_comma(&mut self) {
        if self.element_index > 0 {
            self.out.write_str(",");
        }
        self.element_index += 1;
    }

    fn write_key(&mut self, key: &[u8]) {
        self.out.write(encode_to_ascii(key).as_bytes());
    }
    fn write_value(&mut self, value: &[u8]) {
        self.out.write(encode_to_ascii(value).as_bytes());
    }
}

impl RdbParseFormatter for JSONFormatter {
    fn start_rdb(&mut self) {
        self.out.write_str("[");
    }

    fn end_rdb(&mut self) {
        if self.has_databases {
            self.out.write_str("}");
        }
        self.out.write_str("]\n");
    }

    fn start_database(&mut self, _db_number: u32) {
        if !self.is_first_db {
            self.out.write_str("},");
        }

        self.out.write_str("{");
        self.is_first_db = false;
        self.has_databases = true;
        self.is_first_key_in_db = true;
    }

    fn set(&mut self, key: &[u8], value: &[u8], _expiry: Option<u64>) {
        self.start_key(0);
        self.write_key(key);
        self.out.write_str(":");
        self.write_value(value);
    }

    fn start_hash(&mut self, key: &[u8], length: u32,
                  _expiry: Option<u64>, _info: Option<()>) {
        self.start_key(length);
        self.write_key(key);
        self.out.write_str(":{");
        self.out.flush();
    }
    fn end_hash(&mut self, _key: &[u8]) {
        self.end_key();
        self.out.write_str("}");
        self.out.flush();
    }
    fn hash_element(&mut self, _key: &[u8], field: &[u8], value: &[u8]) {
        self.write_comma();
        self.write_key(field);
        self.out.write_str(":");
        self.write_value(value);
        self.out.flush();
    }

    fn start_set(&mut self, key: &[u8], cardinality: u32,
                 _expiry: Option<u64>, _info: Option<()>) {
        self.start_key(cardinality);
        self.write_key(key);
        self.out.write_str(":[");
        self.out.flush();
    }
    fn end_set(&mut self, _key: &[u8]) {
        self.end_key();
        self.out.write_str("]");
    }
    fn set_element(&mut self, _key: &[u8], member: &[u8]) {
        self.write_comma();
        self.write_value(member);
    }

    fn start_list(&mut self, key: &[u8], length: u32,
                  _expiry: Option<u64>, _info: Option<()>) {
        self.start_key(length);
        self.write_key(key);
        self.out.write_str(":[");
    }
    fn end_list(&mut self, _key: &[u8]) {
        self.end_key();
        self.out.write_str("]");
    }
    fn list_element(&mut self, _key: &[u8], value: &[u8]) {
        self.write_comma();
        self.write_value(value);
    }

    fn start_sorted_set(&mut self, key: &[u8], length: u32,
                        _expiry: Option<u64>, _info: Option<()>) {
        self.start_key(length);
        self.write_key(key);
        self.out.write_str(":{");
    }
    fn end_sorted_set(&mut self, _key: &[u8]) {
        self.end_key();
        self.out.write_str("}");
    }
    fn sorted_set_element(&mut self, _key: &[u8],
                          score: f64, member: &[u8]) {
        self.write_comma();
        self.write_key(member);
        self.out.write_str(":");
        self.write_value(score.to_string().as_bytes());
    }

}
<commit_msg>Add some whitespace<commit_after>#![allow(unused_must_use)]

use formatter::RdbParseFormatter;
use std::io;
use std::str;
use serialize::json;

pub struct JSONFormatter {
    out: Box<Writer+'static>,
    is_first_db: bool,
    has_databases: bool,
    is_first_key_in_db: bool,
    elements_in_key: u32,
    element_index: u32
}

impl JSONFormatter {
    pub fn new() -> JSONFormatter {
        let out = Box::new(io::stdout());
        JSONFormatter {
            out: out,
            is_first_db: true,
            has_databases: false,
            is_first_key_in_db: true,
            elements_in_key: 0,
            element_index: 0
        }
    }
}

fn encode_to_ascii(value: &[u8]) -> String {
    let s = unsafe{str::from_utf8_unchecked(value)};
    json::encode(&s)
}

impl JSONFormatter {
    fn start_key(&mut self, length: u32) {
        if !self.is_first_key_in_db {
            self.out.write_str(",");
        }

        self.is_first_key_in_db = false;
        self.elements_in_key = length;
        self.element_index = 0;
    }

    fn end_key(&mut self) { }

    fn write_comma(&mut self) {
        if self.element_index > 0 {
            self.out.write_str(",");
        }
        self.element_index += 1;
    }

    fn write_key(&mut self, key: &[u8]) {
        self.out.write(encode_to_ascii(key).as_bytes());
    }
    fn write_value(&mut self, value: &[u8]) {
        self.out.write(encode_to_ascii(value).as_bytes());
    }
}

impl RdbParseFormatter for JSONFormatter {
    fn start_rdb(&mut self) {
        self.out.write_str("[");
    }

    fn end_rdb(&mut self) {
        if self.has_databases {
            self.out.write_str("}");
        }
        self.out.write_str("]\n");
    }

    fn start_database(&mut self, _db_number: u32) {
        if !self.is_first_db {
            self.out.write_str("},");
        }

        self.out.write_str("{");
        self.is_first_db = false;
        self.has_databases = true;
        self.is_first_key_in_db = true;
    }

    fn set(&mut self, key: &[u8], value: &[u8], _expiry: Option<u64>) {
        self.start_key(0);
        self.write_key(key);
        self.out.write_str(":");
        self.write_value(value);
    }

    fn start_hash(&mut self, key: &[u8], length: u32,
                  _expiry: Option<u64>, _info: Option<()>) {
        self.start_key(length);
        self.write_key(key);
        self.out.write_str(":{");
        self.out.flush();
    }

    fn end_hash(&mut self, _key: &[u8]) {
        self.end_key();
        self.out.write_str("}");
        self.out.flush();
    }

    fn hash_element(&mut self, _key: &[u8], field: &[u8], value: &[u8]) {
        self.write_comma();
        self.write_key(field);
        self.out.write_str(":");
        self.write_value(value);
        self.out.flush();
    }

    fn start_set(&mut self, key: &[u8], cardinality: u32,
                 _expiry: Option<u64>, _info: Option<()>) {
        self.start_key(cardinality);
        self.write_key(key);
        self.out.write_str(":[");
        self.out.flush();
    }

    fn end_set(&mut self, _key: &[u8]) {
        self.end_key();
        self.out.write_str("]");
    }

    fn set_element(&mut self, _key: &[u8], member: &[u8]) {
        self.write_comma();
        self.write_value(member);
    }

    fn start_list(&mut self, key: &[u8], length: u32,
                  _expiry: Option<u64>, _info: Option<()>) {
        self.start_key(length);
        self.write_key(key);
        self.out.write_str(":[");
    }

    fn end_list(&mut self, _key: &[u8]) {
        self.end_key();
        self.out.write_str("]");
    }

    fn list_element(&mut self, _key: &[u8], value: &[u8]) {
        self.write_comma();
        self.write_value(value);
    }

    fn start_sorted_set(&mut self, key: &[u8], length: u32,
                        _expiry: Option<u64>, _info: Option<()>) {
        self.start_key(length);
        self.write_key(key);
        self.out.write_str(":{");
    }

    fn end_sorted_set(&mut self, _key: &[u8]) {
        self.end_key();
        self.out.write_str("}");
    }

    fn sorted_set_element(&mut self, _key: &[u8],
                          score: f64, member: &[u8]) {
        self.write_comma();
        self.write_key(member);
        self.out.write_str(":");
        self.write_value(score.to_string().as_bytes());
    }

}
<|endoftext|>


<commit_before>
use chrono;

use lib::hasher::*;
use lib::transaction::Transaction;
use std::collections::BTreeSet;
use std::collections::HashSet;
use self::chrono::offset::Utc;
use url::{Url};

pub type Chain = BTreeSet<Block>;

///
/// The representation of a block chain.
///
/// chain: An ordered set of `Block`s
/// nodes: Other nodes in the network
/// current_transactions: Transactions that will be added to the next block
/// difficulty: Mining difficulty 3=hashes that start with '000'
///
#[derive(Debug)]
pub struct Blockchain {
    chain: Chain,
    //not a lot of sorted options in stdlib...
    current_transactions: BTreeSet<Transaction>,
    nodes: HashSet<Url>,
    difficulty: u64
}

#[derive(Debug)]
#[derive(Serialize, Deserialize)]
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct Block {
    pub index: usize,
    pub timestamp: i64,
    pub proof: u64,
    pub previous_hash: String,
    pub transactions: BTreeSet<Transaction>
}

impl Blockchain {

    #[cfg(test)]
    pub fn new() -> Blockchain {
        Self::new_with(3)
    }
    pub fn new_with(difficulty: u64) -> Blockchain {
        let mut blockchain = Blockchain {
            chain: BTreeSet::new(),
            current_transactions: BTreeSet::new(),
            nodes: HashSet::new(),
            difficulty: difficulty
        };
        blockchain.new_block(100, String::from("Genesis block."));
        blockchain
    }

    ///
    /// Add a new transaction
    ///
    /// returns: the index of the block it will be added to
    pub fn new_transaction(&mut self, transaction: Transaction) -> usize {
        self.current_transactions.insert(transaction);
        //It will be added to the index of the next block
        self.last_block().index + 1
    }

    ///
    /// Mine a new block
    ///
   pub fn mine(&mut self) -> Result<&Block, String> {
        // We run the proof of work algorithm to get the next proof...
        let new_block_proof = self.proof_of_work()?;
        //Got it. Give ourselves the new coin (block?)
        //The sender is "0" to signify that this node has mined a new coin.
        self.new_transaction(Transaction::new("0".into(), "my node address".into(), 1));
        let previous_hash = self.hash_last_block()?;
        //Forge the new Block by adding it to the chain
        let mined_block = self.new_block(new_block_proof, previous_hash);
        Ok(&mined_block)
    }

    pub fn chain(&self) -> &Chain {
        &self.chain
    }

    #[cfg(test)]
    pub fn into_chain(self) -> Chain {
        self.chain
    }

    ///
    /// Add a new node
    ///
    pub fn register_node(&mut self, address: Url) -> bool {
        self.nodes.insert(address)
    }

    pub fn nodes(&self) -> &HashSet<Url> {
        &self.nodes
    }

    pub fn replace(&mut self, new_chain: Chain) {
        self.chain = new_chain;
    }

    pub fn len(&self) -> usize {
        self.chain.len()
    }

    fn create_block(&mut self, proof: u64, previous_hash: String) -> Block {
        //Current transactions get moved to this block and are cleared to start
        //collecting the next block's transactions
        let mut txns = BTreeSet::new();
        txns.append(&mut self.current_transactions);
        Block {
            index: self.chain.len() + 1,
            timestamp: Utc::now().timestamp(),
            proof: proof,
            previous_hash: previous_hash,
            transactions: txns
        }
    }

    ///
    ///Create a new Block
    ///
    fn new_block(&mut self, proof: u64, previous_hash: String) -> &Block {
        let block = self.create_block(proof, previous_hash);
        self.chain.insert(block);
        &self.chain.iter().next_back().expect("invariant: just added element")
    }

    fn last_block(&self) -> &Block {
        //it's a double-ended iterator, and it's sorted, so it should be fast
        self.chain.iter().next_back().expect("invariant: Chain empty. Expected genesis block")
    }

    //todo: get away from string errors
    fn hash(block: &Block) -> Result<String, String> {
       self::hash(block)
    }

    ///
    ///Simple Proof of Work Algorithm:
    /// Simple PoW algo:
    /// Find a number p' (new proof) s. t. hash(pp'h) contains 4 leading zeroes, where p is the
    /// previous proof and h is the hash of the previous block.
    ///
    fn proof_of_work(&self) -> Result<u64, String> {

        let last_block = self.last_block();
        let last_proof = last_block.proof;

        info!("Mining from last_proof {}...", last_proof);
        let mut proof = 0;
        let previous_hash = self.hash_last_block()?;
        while !Self::valid_proof(last_proof, proof, self.difficulty, &previous_hash) {
             proof += 1;
        }
        debug!("Took {} iterations", proof);
        Ok(proof)
    }

    /// Validates the Proof
    /// i.e. does the hash of last_proof and this proof start with 000?
    fn valid_proof(last_proof: u64, proof: u64, difficulty: u64, previous_hash: &String) -> bool {

        //todo: don't recalculate every time
        let hash_prefix = "0".repeat(difficulty as usize); //"000"

        let guess = format!("{}{}{}", last_proof, proof, previous_hash);
        let guess_hash =  self::hash_string(guess);
        let is_valid = guess_hash.starts_with(hash_prefix.as_str());
        if is_valid {
            info!("proof {} -> guess_hash: {}", proof, guess_hash);
        } else {
            debug!("proof {} -> guess_hash: {}", proof, guess_hash);
        }
        is_valid
    }

    fn hash_last_block(&self) -> Result<String, String> {
        let last_block = self.last_block();
        Self::hash(last_block)
    }

    ///
    /// Determine if a given blockchain is valid
    ///
    pub fn valid_chain(&self, chain: &Chain) -> bool {
        debug!("{} blocks in chain.", chain.len());
        let mut previous_block_opt: Option<&Block> = None;
        for block in chain {
            if let Some(previous_block) = previous_block_opt {
                //Check the hash and proof
                if !Self::check_hash(previous_block, block) ||
                   !Self::check_proof(previous_block, block, self.difficulty) {
                    return false;
                }
            }
            previous_block_opt = Some(&block);
        }
        true
    }

    fn check_hash(previous_block: &Block, current_block: &Block) -> bool {
        let previous_block_hash = Self::hash(previous_block).unwrap_or_else(|e| format!("hash failure: {}", e));
        if current_block.previous_hash != previous_block_hash {
            warn!("HASH MISMATCH {} <> {}", current_block.previous_hash, previous_block_hash);
            return false
        }
        true
    }

    fn check_proof(previous_block: &Block, current_block: &Block, difficulty: u64) -> bool {
        let previous_hash = Self::hash(previous_block).unwrap_or_else(|e| format!("hash failure: {}", e));
        if !Self::valid_proof(previous_block.proof, current_block.proof, difficulty, &previous_hash) {
            warn!("PROOF MISMATCH {} <> {}", previous_block.proof, current_block.proof);
            return false
        }
        true
    }
}

#[cfg(test)]
mod tests {
    //use env_logger;
    use lib::blockchain::Blockchain;
    use lib::transaction::Transaction;
    use url::Url;

    #[test]
    fn new_transaction() {
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        let _idx = blockchain.new_transaction(txn);
        let last_txn = blockchain.current_transactions.iter().next_back().expect("expected a txn");
        assert_eq!(last_txn.sender, String::from("a"));
        assert_eq!(last_txn.recipient, String::from("b"));
        assert_eq!(last_txn.amount, 100);
    }

     #[test]
    fn new_block() {
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        blockchain.new_transaction(txn);

        let a = blockchain.current_transactions.len();
        assert_eq!(1, a , "1 transaction");

        blockchain.new_block(2, String::from("abc"));

        let b = blockchain.current_transactions.len();
        assert_eq!(0, b, "New block should clear transactions (which were on the previous block");
    }

    #[test]
    fn hash() {
        let mut blockchain = Blockchain::new();
        blockchain.new_block(2, String::from("abc"));
        let block = blockchain.last_block();
        let hash = Blockchain::hash(block);
        let hash2 = Blockchain::hash(block);
        println!("{:?}", hash);
        assert!(hash.is_ok());
        assert_eq!(hash.unwrap(), hash2.unwrap(), "Expected same block to hash to the same value");
        //assert!(hash.unwrap().len() > 10, "expected a longer hash");
    }

    #[test]
    fn valid_proof_false() {
        assert_eq!(Blockchain::valid_proof(100,1, 3, &String::from("some hash")), false);
    }

    #[cfg(feature = "mining-tests")]
    #[test]
    fn proof_of_work() {
        let difficulty = 2;
        let blockchain = Blockchain::new_with(difficulty);
        println!("Starting proof of work... (long running)");
        let proof = blockchain.proof_of_work().unwrap();
        println!("Finished proof of work: {}", proof);
        assert!(proof > 1, "expected a higher proof");
        let previous_hash = blockchain.hash_last_block().unwrap();
        assert!(Blockchain::valid_proof(100, proof, difficulty, &previous_hash));
        assert!(!Blockchain::valid_proof(100, proof, difficulty, &String::from("invalid hash")));
    }

    #[test]
    fn chain() {
        let mut blockchain = Blockchain::new();

        assert_eq!(blockchain.chain().len(),  1, "Expected 1 block (genesis)");
        blockchain.new_block(100, "abc".into());
        assert_eq!(blockchain.chain().len(),  2, "Expected 2 blocks");
    }

    #[test]
    fn register_node() {
        let mut blockchain = Blockchain::new();
        let test_local_url = Url::parse("http://localhost:9000").expect("valid url");
        blockchain.register_node(test_local_url.clone());
        assert_eq!(blockchain.nodes().len(),  1, "Expected 1 node");
        blockchain.register_node(test_local_url);
        assert_eq!(blockchain.nodes().len(),  1, "Expected 1 node after dupe add (idempotent)");
    }

    #[test]
    fn valid_chain_invalid_hash() {
        //env_logger::init().unwrap();
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        blockchain.new_transaction(txn);
        //invalid hash
        blockchain.new_block(2, String::from("abc"));
        assert!(!blockchain.valid_chain(&blockchain.chain), "blockchain not valid (hash mismatch)");
    }

    #[test]
    fn valid_chain_invalid_proof() {
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        blockchain.new_transaction(txn);
        //valid hash, invalid proof
        let hash = blockchain.hash_last_block().unwrap();
        blockchain.new_block(2, hash);

        assert!(!blockchain.valid_chain(&blockchain.chain), "blockchain not valid (proof mismatch)");
    }

    #[test]
    #[cfg(feature = "mining-tests")]
    fn valid_chain_ok() {
        //env_logger::init().unwrap();
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        blockchain.new_transaction(txn);
        //valid hash, invalid proof
        blockchain.mine();
        assert!(blockchain.valid_chain(&blockchain.chain), "blockchain should be valid with a mined block");
    }
}<commit_msg>more comments<commit_after>
use chrono;

use lib::hasher::*;
use lib::transaction::Transaction;
use std::collections::BTreeSet;
use std::collections::HashSet;
use self::chrono::offset::Utc;
use url::{Url};

pub type Chain = BTreeSet<Block>;

///
/// The representation of a block chain.
///
/// chain: An ordered set of `Block`s
/// nodes: Other nodes in the network
/// current_transactions: Transactions that will be added to the next block
/// difficulty: Mining difficulty 3=hashes that start with '000'
///
#[derive(Debug)]
pub struct Blockchain {
    chain: Chain,
    //not a lot of sorted options in stdlib...
    current_transactions: BTreeSet<Transaction>,
    nodes: HashSet<Url>,
    difficulty: u64
}

///
/// Represents a `Block` on the chain.
///
#[derive(Debug)]
#[derive(Serialize, Deserialize)]
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct Block {
    pub index: usize,
    pub timestamp: i64,
    pub proof: u64,
    pub previous_hash: String,
    pub transactions: BTreeSet<Transaction>
}

impl Blockchain {

    #[cfg(test)]
    pub fn new() -> Blockchain {
        Self::new_with(3)
    }
    pub fn new_with(difficulty: u64) -> Blockchain {
        let mut blockchain = Blockchain {
            chain: BTreeSet::new(),
            current_transactions: BTreeSet::new(),
            nodes: HashSet::new(),
            difficulty: difficulty
        };
        blockchain.new_block(100, String::from("Genesis block."));
        blockchain
    }

    ///
    /// Add a new transaction
    ///
    /// returns: the index of the block it will be added to
    pub fn new_transaction(&mut self, transaction: Transaction) -> usize {
        self.current_transactions.insert(transaction);
        //It will be added to the index of the next block
        self.last_block().index + 1
    }

    ///
    /// Mine a new block
    ///
   pub fn mine(&mut self) -> Result<&Block, String> {
        // We run the proof of work algorithm to get the next proof...
        let new_block_proof = self.proof_of_work()?;
        //Got it. Give ourselves the new coin (block?)
        //The sender is "0" to signify that this node has mined a new coin.
        self.new_transaction(Transaction::new("0".into(), "my node address".into(), 1));
        let previous_hash = self.hash_last_block()?;
        //Forge the new Block by adding it to the chain
        let mined_block = self.new_block(new_block_proof, previous_hash);
        Ok(&mined_block)
    }

    ///
    /// Returns the `Chain`
    ///
    pub fn chain(&self) -> &Chain {
        &self.chain
    }

    #[cfg(test)]
    pub fn into_chain(self) -> Chain {
        self.chain
    }

    ///
    /// Add a new node
    ///
    pub fn register_node(&mut self, address: Url) -> bool {
        self.nodes.insert(address)
    }

    ///
    /// Returns the other nodes in the network
    ///
    pub fn nodes(&self) -> &HashSet<Url> {
        &self.nodes
    }

    ///
    /// Replace our chain with a new one (such as during consensus)
    ///
    pub fn replace(&mut self, new_chain: Chain) {
        self.chain = new_chain;
    }

    ///
    /// Number of blocks in the chain
    ///
    pub fn len(&self) -> usize {
        self.chain.len()
    }

    fn create_block(&mut self, proof: u64, previous_hash: String) -> Block {
        //Current transactions get moved to this block and are cleared to start
        //collecting the next block's transactions
        let mut txns = BTreeSet::new();
        txns.append(&mut self.current_transactions);
        Block {
            index: self.chain.len() + 1,
            timestamp: Utc::now().timestamp(),
            proof: proof,
            previous_hash: previous_hash,
            transactions: txns
        }
    }

    ///
    ///Create a new Block
    ///
    fn new_block(&mut self, proof: u64, previous_hash: String) -> &Block {
        let block = self.create_block(proof, previous_hash);
        self.chain.insert(block);
        &self.chain.iter().next_back().expect("invariant: just added element")
    }

    ///
    /// The last mined block
    ///
    fn last_block(&self) -> &Block {
        //it's a double-ended iterator, and it's sorted, so it should be fast
        self.chain.iter().next_back().expect("invariant: Chain empty. Expected genesis block")
    }

    //todo: get away from string errors
    fn hash(block: &Block) -> Result<String, String> {
       self::hash(block)
    }

    ///
    ///Simple Proof of Work Algorithm:
    /// Simple PoW algo:
    /// Find a number p' (new proof) s. t. hash(pp'h) contains 4 leading zeroes, where p is the
    /// previous proof and h is the hash of the previous block.
    ///
    fn proof_of_work(&self) -> Result<u64, String> {

        let last_block = self.last_block();
        let last_proof = last_block.proof;

        info!("Mining from last_proof {}...", last_proof);
        let mut proof = 0;
        let previous_hash = self.hash_last_block()?;
        while !Self::valid_proof(last_proof, proof, self.difficulty, &previous_hash) {
             proof += 1;
        }
        debug!("Took {} iterations", proof);
        Ok(proof)
    }

    /// Validates the Proof
    /// i.e. does the hash of last_proof and this proof start with 000?
    fn valid_proof(last_proof: u64, proof: u64, difficulty: u64, previous_hash: &String) -> bool {

        //todo: don't recalculate every time
        let hash_prefix = "0".repeat(difficulty as usize); //"000"

        let guess = format!("{}{}{}", last_proof, proof, previous_hash);
        let guess_hash =  self::hash_string(guess);
        let is_valid = guess_hash.starts_with(hash_prefix.as_str());
        if is_valid {
            info!("proof {} -> guess_hash: {}", proof, guess_hash);
        } else {
            debug!("proof {} -> guess_hash: {}", proof, guess_hash);
        }
        is_valid
    }

    fn hash_last_block(&self) -> Result<String, String> {
        let last_block = self.last_block();
        Self::hash(last_block)
    }

    ///
    /// Determine if a given blockchain is valid
    ///
    pub fn valid_chain(&self, chain: &Chain) -> bool {
        debug!("{} blocks in chain.", chain.len());
        let mut previous_block_opt: Option<&Block> = None;
        for block in chain {
            if let Some(previous_block) = previous_block_opt {
                //Check the hash and proof
                if !Self::check_hash(previous_block, block) ||
                   !Self::check_proof(previous_block, block, self.difficulty) {
                    return false;
                }
            }
            previous_block_opt = Some(&block);
        }
        true
    }

    fn check_hash(previous_block: &Block, current_block: &Block) -> bool {
        let previous_block_hash = Self::hash(previous_block).unwrap_or_else(|e| format!("hash failure: {}", e));
        if current_block.previous_hash != previous_block_hash {
            warn!("HASH MISMATCH {} <> {}", current_block.previous_hash, previous_block_hash);
            return false
        }
        true
    }

    fn check_proof(previous_block: &Block, current_block: &Block, difficulty: u64) -> bool {
        let previous_hash = Self::hash(previous_block).unwrap_or_else(|e| format!("hash failure: {}", e));
        if !Self::valid_proof(previous_block.proof, current_block.proof, difficulty, &previous_hash) {
            warn!("PROOF MISMATCH {} <> {}", previous_block.proof, current_block.proof);
            return false
        }
        true
    }
}

#[cfg(test)]
mod tests {
    //use env_logger;
    use lib::blockchain::Blockchain;
    use lib::transaction::Transaction;
    use url::Url;

    #[test]
    fn new_transaction() {
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        let _idx = blockchain.new_transaction(txn);
        let last_txn = blockchain.current_transactions.iter().next_back().expect("expected a txn");
        assert_eq!(last_txn.sender, String::from("a"));
        assert_eq!(last_txn.recipient, String::from("b"));
        assert_eq!(last_txn.amount, 100);
    }

     #[test]
    fn new_block() {
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        blockchain.new_transaction(txn);

        let a = blockchain.current_transactions.len();
        assert_eq!(1, a , "1 transaction");

        blockchain.new_block(2, String::from("abc"));

        let b = blockchain.current_transactions.len();
        assert_eq!(0, b, "New block should clear transactions (which were on the previous block");
    }

    #[test]
    fn hash() {
        let mut blockchain = Blockchain::new();
        blockchain.new_block(2, String::from("abc"));
        let block = blockchain.last_block();
        let hash = Blockchain::hash(block);
        let hash2 = Blockchain::hash(block);
        println!("{:?}", hash);
        assert!(hash.is_ok());
        assert_eq!(hash.unwrap(), hash2.unwrap(), "Expected same block to hash to the same value");
        //assert!(hash.unwrap().len() > 10, "expected a longer hash");
    }

    #[test]
    fn valid_proof_false() {
        assert_eq!(Blockchain::valid_proof(100,1, 3, &String::from("some hash")), false);
    }

    #[cfg(feature = "mining-tests")]
    #[test]
    fn proof_of_work() {
        let difficulty = 2;
        let blockchain = Blockchain::new_with(difficulty);
        println!("Starting proof of work... (long running)");
        let proof = blockchain.proof_of_work().unwrap();
        println!("Finished proof of work: {}", proof);
        assert!(proof > 1, "expected a higher proof");
        let previous_hash = blockchain.hash_last_block().unwrap();
        assert!(Blockchain::valid_proof(100, proof, difficulty, &previous_hash));
        assert!(!Blockchain::valid_proof(100, proof, difficulty, &String::from("invalid hash")));
    }

    #[test]
    fn chain() {
        let mut blockchain = Blockchain::new();

        assert_eq!(blockchain.chain().len(),  1, "Expected 1 block (genesis)");
        blockchain.new_block(100, "abc".into());
        assert_eq!(blockchain.chain().len(),  2, "Expected 2 blocks");
    }

    #[test]
    fn register_node() {
        let mut blockchain = Blockchain::new();
        let test_local_url = Url::parse("http://localhost:9000").expect("valid url");
        blockchain.register_node(test_local_url.clone());
        assert_eq!(blockchain.nodes().len(),  1, "Expected 1 node");
        blockchain.register_node(test_local_url);
        assert_eq!(blockchain.nodes().len(),  1, "Expected 1 node after dupe add (idempotent)");
    }

    #[test]
    fn valid_chain_invalid_hash() {
        //env_logger::init().unwrap();
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        blockchain.new_transaction(txn);
        //invalid hash
        blockchain.new_block(2, String::from("abc"));
        assert!(!blockchain.valid_chain(&blockchain.chain), "blockchain not valid (hash mismatch)");
    }

    #[test]
    fn valid_chain_invalid_proof() {
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        blockchain.new_transaction(txn);
        //valid hash, invalid proof
        let hash = blockchain.hash_last_block().unwrap();
        blockchain.new_block(2, hash);

        assert!(!blockchain.valid_chain(&blockchain.chain), "blockchain not valid (proof mismatch)");
    }

    #[test]
    #[cfg(feature = "mining-tests")]
    fn valid_chain_ok() {
        //env_logger::init().unwrap();
        let mut blockchain = Blockchain::new();
        let txn = Transaction::new(String::from("a"), String::from("b"), 100);
        blockchain.new_transaction(txn);
        //valid hash, invalid proof
        blockchain.mine();
        assert!(blockchain.valid_chain(&blockchain.chain), "blockchain should be valid with a mined block");
    }
}<|endoftext|>


<commit_before>// https://stackoverflow.
// com/questions/3202629/where-can-i-find-a-list-of-mac-virtual-key-codes

/* keycodes for keys that are independent of keyboard layout */

#![allow(non_upper_case_globals)]
#![allow(dead_code)]

pub const kVK_Return: u16 = 0x24;
pub const kVK_Tab: u16 = 0x30;
pub const kVK_Space: u16 = 0x31;
pub const kVK_Delete: u16 = 0x33;
pub const kVK_Escape: u16 = 0x35;
pub const kVK_Command: u16 = 0x37;
pub const kVK_Shift: u16 = 0x38;
pub const kVK_CapsLock: u16 = 0x39;
pub const kVK_Option: u16 = 0x3A;
pub const kVK_Control: u16 = 0x3B;
pub const kVK_RightShift: u16 = 0x3C;
pub const kVK_RightOption: u16 = 0x3D;
pub const kVK_RightControl: u16 = 0x3E;
pub const kVK_Function: u16 = 0x3F;
pub const kVK_F17: u16 = 0x40;
pub const kVK_VolumeUp: u16 = 0x48;
pub const kVK_VolumeDown: u16 = 0x49;
pub const kVK_Mute: u16 = 0x4A;
pub const kVK_F18: u16 = 0x4F;
pub const kVK_F19: u16 = 0x50;
pub const kVK_F20: u16 = 0x5A;
pub const kVK_F5: u16 = 0x60;
pub const kVK_F6: u16 = 0x61;
pub const kVK_F7: u16 = 0x62;
pub const kVK_F3: u16 = 0x63;
pub const kVK_F8: u16 = 0x64;
pub const kVK_F9: u16 = 0x65;
pub const kVK_F11: u16 = 0x67;
pub const kVK_F13: u16 = 0x69;
pub const kVK_F16: u16 = 0x6A;
pub const kVK_F14: u16 = 0x6B;
pub const kVK_F10: u16 = 0x6D;
pub const kVK_F12: u16 = 0x6F;
pub const kVK_F15: u16 = 0x71;
pub const kVK_Help: u16 = 0x72;
pub const kVK_Home: u16 = 0x73;
pub const kVK_PageUp: u16 = 0x74;
pub const kVK_ForwardDelete: u16 = 0x75;
pub const kVK_F4: u16 = 0x76;
pub const kVK_End: u16 = 0x77;
pub const kVK_F2: u16 = 0x78;
pub const kVK_PageDown: u16 = 0x79;
pub const kVK_F1: u16 = 0x7A;
pub const kVK_LeftArrow: u16 = 0x7B;
pub const kVK_RightArrow: u16 = 0x7C;
pub const kVK_DownArrow: u16 = 0x7D;
pub const kVK_UpArrow: u16 = 0x7;
<commit_msg>Fix macOS up arrow virtual key<commit_after>// https://stackoverflow.
// com/questions/3202629/where-can-i-find-a-list-of-mac-virtual-key-codes

/* keycodes for keys that are independent of keyboard layout */

#![allow(non_upper_case_globals)]
#![allow(dead_code)]

pub const kVK_Return: u16 = 0x24;
pub const kVK_Tab: u16 = 0x30;
pub const kVK_Space: u16 = 0x31;
pub const kVK_Delete: u16 = 0x33;
pub const kVK_Escape: u16 = 0x35;
pub const kVK_Command: u16 = 0x37;
pub const kVK_Shift: u16 = 0x38;
pub const kVK_CapsLock: u16 = 0x39;
pub const kVK_Option: u16 = 0x3A;
pub const kVK_Control: u16 = 0x3B;
pub const kVK_RightShift: u16 = 0x3C;
pub const kVK_RightOption: u16 = 0x3D;
pub const kVK_RightControl: u16 = 0x3E;
pub const kVK_Function: u16 = 0x3F;
pub const kVK_F17: u16 = 0x40;
pub const kVK_VolumeUp: u16 = 0x48;
pub const kVK_VolumeDown: u16 = 0x49;
pub const kVK_Mute: u16 = 0x4A;
pub const kVK_F18: u16 = 0x4F;
pub const kVK_F19: u16 = 0x50;
pub const kVK_F20: u16 = 0x5A;
pub const kVK_F5: u16 = 0x60;
pub const kVK_F6: u16 = 0x61;
pub const kVK_F7: u16 = 0x62;
pub const kVK_F3: u16 = 0x63;
pub const kVK_F8: u16 = 0x64;
pub const kVK_F9: u16 = 0x65;
pub const kVK_F11: u16 = 0x67;
pub const kVK_F13: u16 = 0x69;
pub const kVK_F16: u16 = 0x6A;
pub const kVK_F14: u16 = 0x6B;
pub const kVK_F10: u16 = 0x6D;
pub const kVK_F12: u16 = 0x6F;
pub const kVK_F15: u16 = 0x71;
pub const kVK_Help: u16 = 0x72;
pub const kVK_Home: u16 = 0x73;
pub const kVK_PageUp: u16 = 0x74;
pub const kVK_ForwardDelete: u16 = 0x75;
pub const kVK_F4: u16 = 0x76;
pub const kVK_End: u16 = 0x77;
pub const kVK_F2: u16 = 0x78;
pub const kVK_PageDown: u16 = 0x79;
pub const kVK_F1: u16 = 0x7A;
pub const kVK_LeftArrow: u16 = 0x7B;
pub const kVK_RightArrow: u16 = 0x7C;
pub const kVK_DownArrow: u16 = 0x7D;
pub const kVK_UpArrow: u16 = 0x7E;
<|endoftext|>


<commit_before>use crate::syntax::namespace::Namespace;
use quote::quote;
use syn::parse::{Error, Parse, ParseStream, Result};
use syn::{
    braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemStruct,
    ItemUse, LitStr, Token, Visibility,
};

pub struct Module {
    pub namespace: Namespace,
    pub attrs: Vec<Attribute>,
    pub vis: Visibility,
    pub unsafety: Option<Token![unsafe]>,
    pub mod_token: Token![mod],
    pub ident: Ident,
    pub brace_token: token::Brace,
    pub content: Vec<Item>,
}

pub enum Item {
    Struct(ItemStruct),
    Enum(ItemEnum),
    ForeignMod(ItemForeignMod),
    Use(ItemUse),
    Other(RustItem),
}

pub struct ItemForeignMod {
    pub attrs: Vec<Attribute>,
    pub unsafety: Option<Token![unsafe]>,
    pub abi: Abi,
    pub brace_token: token::Brace,
    pub items: Vec<ForeignItem>,
}

impl Parse for Module {
    fn parse(input: ParseStream) -> Result<Self> {
        let namespace = Namespace::none();
        let mut attrs = input.call(Attribute::parse_outer)?;
        let vis: Visibility = input.parse()?;
        let unsafety: Option<Token![unsafe]> = input.parse()?;
        let mod_token: Token![mod] = input.parse()?;
        let ident: Ident = input.parse()?;

        let semi: Option<Token![;]> = input.parse()?;
        if let Some(semi) = semi {
            let span = quote!(#vis #mod_token #semi);
            return Err(Error::new_spanned(
                span,
                "#[cxx::bridge] module must have inline contents",
            ))?;
        }

        let content;
        let brace_token = braced!(content in input);
        attrs.extend(content.call(Attribute::parse_inner)?);

        let mut items = Vec::new();
        while !content.is_empty() {
            items.push(content.parse()?);
        }

        Ok(Module {
            namespace,
            attrs,
            vis,
            unsafety,
            mod_token,
            ident,
            brace_token,
            content: items,
        })
    }
}

impl Parse for Item {
    fn parse(input: ParseStream) -> Result<Self> {
        let attrs = input.call(Attribute::parse_outer)?;

        let ahead = input.fork();
        let unsafety = if ahead.parse::<Option<Token![unsafe]>>()?.is_some()
            && ahead.parse::<Option<Token![extern]>>()?.is_some()
            && ahead.parse::<Option<LitStr>>().is_ok()
            && ahead.peek(token::Brace)
        {
            Some(input.parse()?)
        } else {
            None
        };

        let item = input.parse()?;
        match item {
            RustItem::Struct(item) => Ok(Item::Struct(ItemStruct { attrs, ..item })),
            RustItem::Enum(item) => Ok(Item::Enum(ItemEnum { attrs, ..item })),
            RustItem::ForeignMod(item) => Ok(Item::ForeignMod(ItemForeignMod {
                attrs: item.attrs,
                unsafety,
                abi: item.abi,
                brace_token: item.brace_token,
                items: item.items,
            })),
            RustItem::Use(item) => Ok(Item::Use(ItemUse { attrs, ..item })),
            other => Ok(Item::Other(other)),
        }
    }
}
<commit_msg>Fix stray question operator<commit_after>use crate::syntax::namespace::Namespace;
use quote::quote;
use syn::parse::{Error, Parse, ParseStream, Result};
use syn::{
    braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemStruct,
    ItemUse, LitStr, Token, Visibility,
};

pub struct Module {
    pub namespace: Namespace,
    pub attrs: Vec<Attribute>,
    pub vis: Visibility,
    pub unsafety: Option<Token![unsafe]>,
    pub mod_token: Token![mod],
    pub ident: Ident,
    pub brace_token: token::Brace,
    pub content: Vec<Item>,
}

pub enum Item {
    Struct(ItemStruct),
    Enum(ItemEnum),
    ForeignMod(ItemForeignMod),
    Use(ItemUse),
    Other(RustItem),
}

pub struct ItemForeignMod {
    pub attrs: Vec<Attribute>,
    pub unsafety: Option<Token![unsafe]>,
    pub abi: Abi,
    pub brace_token: token::Brace,
    pub items: Vec<ForeignItem>,
}

impl Parse for Module {
    fn parse(input: ParseStream) -> Result<Self> {
        let namespace = Namespace::none();
        let mut attrs = input.call(Attribute::parse_outer)?;
        let vis: Visibility = input.parse()?;
        let unsafety: Option<Token![unsafe]> = input.parse()?;
        let mod_token: Token![mod] = input.parse()?;
        let ident: Ident = input.parse()?;

        let semi: Option<Token![;]> = input.parse()?;
        if let Some(semi) = semi {
            let span = quote!(#vis #mod_token #semi);
            return Err(Error::new_spanned(
                span,
                "#[cxx::bridge] module must have inline contents",
            ));
        }

        let content;
        let brace_token = braced!(content in input);
        attrs.extend(content.call(Attribute::parse_inner)?);

        let mut items = Vec::new();
        while !content.is_empty() {
            items.push(content.parse()?);
        }

        Ok(Module {
            namespace,
            attrs,
            vis,
            unsafety,
            mod_token,
            ident,
            brace_token,
            content: items,
        })
    }
}

impl Parse for Item {
    fn parse(input: ParseStream) -> Result<Self> {
        let attrs = input.call(Attribute::parse_outer)?;

        let ahead = input.fork();
        let unsafety = if ahead.parse::<Option<Token![unsafe]>>()?.is_some()
            && ahead.parse::<Option<Token![extern]>>()?.is_some()
            && ahead.parse::<Option<LitStr>>().is_ok()
            && ahead.peek(token::Brace)
        {
            Some(input.parse()?)
        } else {
            None
        };

        let item = input.parse()?;
        match item {
            RustItem::Struct(item) => Ok(Item::Struct(ItemStruct { attrs, ..item })),
            RustItem::Enum(item) => Ok(Item::Enum(ItemEnum { attrs, ..item })),
            RustItem::ForeignMod(item) => Ok(Item::ForeignMod(ItemForeignMod {
                attrs: item.attrs,
                unsafety,
                abi: item.abi,
                brace_token: item.brace_token,
                items: item.items,
            })),
            RustItem::Use(item) => Ok(Item::Use(ItemUse { attrs, ..item })),
            other => Ok(Item::Other(other)),
        }
    }
}
<|endoftext|>


<commit_before>use chrono::NaiveDateTime;
use diesel::prelude::*;

use crate::models::Crate;
use crate::schema::*;
use crate::sql::lower;

#[derive(Clone, Identifiable, Queryable, Debug)]
pub struct Keyword {
    pub id: i32,
    pub keyword: String,
    pub crates_cnt: i32,
    pub created_at: NaiveDateTime,
}

#[derive(Associations, Insertable, Identifiable, Debug, Clone, Copy)]
#[belongs_to(Keyword)]
#[belongs_to(Crate)]
#[table_name = "crates_keywords"]
#[primary_key(crate_id, keyword_id)]
pub struct CrateKeyword {
    crate_id: i32,
    keyword_id: i32,
}

impl Keyword {
    pub fn find_by_keyword(conn: &PgConnection, name: &str) -> QueryResult<Keyword> {
        keywords::table
            .filter(keywords::keyword.eq(lower(name)))
            .first(&*conn)
    }

    pub fn find_or_create_all(conn: &PgConnection, names: &[&str]) -> QueryResult<Vec<Keyword>> {
        use diesel::dsl::any;

        let lowercase_names: Vec<_> = names.iter().map(|s| s.to_lowercase()).collect();

        let new_keywords: Vec<_> = lowercase_names
            .iter()
            .map(|s| keywords::keyword.eq(s))
            .collect();

        diesel::insert_into(keywords::table)
            .values(&new_keywords)
            .on_conflict_do_nothing()
            .execute(conn)?;
        keywords::table
            .filter(keywords::keyword.eq(any(&lowercase_names)))
            .load(conn)
    }

    pub fn valid_name(name: &str) -> bool {
        if name.is_empty() {
            return false;
        }
        // unwrap is okay because name is non-empty
        name.chars().next().unwrap().is_ascii_alphanumeric()
            && name
                .chars()
                .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
    }

    pub fn update_crate(conn: &PgConnection, krate: &Crate, keywords: &[&str]) -> QueryResult<()> {
        conn.transaction(|| {
            let keywords = Keyword::find_or_create_all(conn, keywords)?;
            diesel::delete(CrateKeyword::belonging_to(krate)).execute(conn)?;
            let crate_keywords = keywords
                .into_iter()
                .map(|kw| CrateKeyword {
                    crate_id: krate.id,
                    keyword_id: kw.id,
                })
                .collect::<Vec<_>>();
            diesel::insert_into(crates_keywords::table)
                .values(&crate_keywords)
                .execute(conn)?;
            Ok(())
        })
    }
}

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

    fn pg_connection() -> PgConnection {
        let database_url =
            dotenv::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
        let conn = PgConnection::establish(&database_url).unwrap();
        // These tests deadlock if run concurrently
        conn.batch_execute("BEGIN;").unwrap();
        conn
    }

    #[test]
    fn dont_associate_with_non_lowercased_keywords() {
        let conn = pg_connection();
        // The code should be preventing lowercased keywords from existing,
        // but if one happens to sneak in there, don't associate crates with it.

        diesel::insert_into(keywords::table)
            .values(keywords::keyword.eq("NO"))
            .execute(&conn)
            .unwrap();

        let associated = Keyword::find_or_create_all(&conn, &["no"]).unwrap();
        assert_eq!(associated.len(), 1);
        assert_eq!(associated.first().unwrap().keyword, "no");
    }
}
<commit_msg>Eliminate unwrap from Keyword::valid_name (#5043)<commit_after>use chrono::NaiveDateTime;
use diesel::prelude::*;

use crate::models::Crate;
use crate::schema::*;
use crate::sql::lower;

#[derive(Clone, Identifiable, Queryable, Debug)]
pub struct Keyword {
    pub id: i32,
    pub keyword: String,
    pub crates_cnt: i32,
    pub created_at: NaiveDateTime,
}

#[derive(Associations, Insertable, Identifiable, Debug, Clone, Copy)]
#[belongs_to(Keyword)]
#[belongs_to(Crate)]
#[table_name = "crates_keywords"]
#[primary_key(crate_id, keyword_id)]
pub struct CrateKeyword {
    crate_id: i32,
    keyword_id: i32,
}

impl Keyword {
    pub fn find_by_keyword(conn: &PgConnection, name: &str) -> QueryResult<Keyword> {
        keywords::table
            .filter(keywords::keyword.eq(lower(name)))
            .first(&*conn)
    }

    pub fn find_or_create_all(conn: &PgConnection, names: &[&str]) -> QueryResult<Vec<Keyword>> {
        use diesel::dsl::any;

        let lowercase_names: Vec<_> = names.iter().map(|s| s.to_lowercase()).collect();

        let new_keywords: Vec<_> = lowercase_names
            .iter()
            .map(|s| keywords::keyword.eq(s))
            .collect();

        diesel::insert_into(keywords::table)
            .values(&new_keywords)
            .on_conflict_do_nothing()
            .execute(conn)?;
        keywords::table
            .filter(keywords::keyword.eq(any(&lowercase_names)))
            .load(conn)
    }

    pub fn valid_name(name: &str) -> bool {
        let mut chars = name.chars();
        let first = match chars.next() {
            None => return false,
            Some(c) => c,
        };
        first.is_ascii_alphanumeric()
            && chars.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
    }

    pub fn update_crate(conn: &PgConnection, krate: &Crate, keywords: &[&str]) -> QueryResult<()> {
        conn.transaction(|| {
            let keywords = Keyword::find_or_create_all(conn, keywords)?;
            diesel::delete(CrateKeyword::belonging_to(krate)).execute(conn)?;
            let crate_keywords = keywords
                .into_iter()
                .map(|kw| CrateKeyword {
                    crate_id: krate.id,
                    keyword_id: kw.id,
                })
                .collect::<Vec<_>>();
            diesel::insert_into(crates_keywords::table)
                .values(&crate_keywords)
                .execute(conn)?;
            Ok(())
        })
    }
}

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

    fn pg_connection() -> PgConnection {
        let database_url =
            dotenv::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
        let conn = PgConnection::establish(&database_url).unwrap();
        // These tests deadlock if run concurrently
        conn.batch_execute("BEGIN;").unwrap();
        conn
    }

    #[test]
    fn dont_associate_with_non_lowercased_keywords() {
        let conn = pg_connection();
        // The code should be preventing lowercased keywords from existing,
        // but if one happens to sneak in there, don't associate crates with it.

        diesel::insert_into(keywords::table)
            .values(keywords::keyword.eq("NO"))
            .execute(&conn)
            .unwrap();

        let associated = Keyword::find_or_create_all(&conn, &["no"]).unwrap();
        assert_eq!(associated.len(), 1);
        assert_eq!(associated.first().unwrap().keyword, "no");
    }
}
<|endoftext|>