<commit_before>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use byteorder::{LE, ReadBytesExt};

use std::{fmt, io};

/// Represents a Glb loader error.
#[derive(Debug)]
pub enum Error {
    /// Io error occured.
    Io(::std::io::Error),
    /// Unsupported version.
    Version(u32),
    /// Magic says that file is not glTF.
    Magic([u8; 4]),
    /// Length specified in GLB header exceeeds that of slice.
    Length {
        /// length specified in GLB header.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Stream ended before we could read the chunk.
    ChunkLength {
        /// chunkType error happened at.
        ty: ChunkType,
        /// chunkLength.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Chunk of this chunkType was not expected.
    ChunkType(ChunkType),
    /// Unknown chunk type.
    UnknownChunkType([u8; 4]),
}

/// The contents of a .glb file.
#[derive(Clone, Debug)]
pub struct Glb<'a> {
    /// The header section of the `.glb` file.
    pub header: Header,
    /// The JSON section of the `.glb` file.
    pub json: &'a [u8],
    /// The optional BIN section of the `.glb` file.
    pub bin: Option<&'a [u8]>,
}

/// The header section of a .glb file.
#[derive(Copy, Clone, Debug)]
pub struct Header {
    /// Must be `b"glTF"`.
    pub magic: [u8; 4],
    /// Must be `2`.
    pub version: u32,
    /// Must match the length of the parent .glb file.
    pub length: u32,
}

/// GLB chunk type.
#[derive(Copy, Clone, Debug)]
pub enum ChunkType {
    /// JSON chunk.
    Json,
    /// BIN\0 chunk.
    Bin,
}

/// Chunk header with no data read yet.
#[derive(Copy, Clone, Debug)]
struct ChunkHeader {
    /// The length of the chunk data in byte excluding the header.
    length: u32,
    /// Chunk type.
    ty: ChunkType,
}

impl Header {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, Error> {
        use self::Error::Io;
        let mut magic = [0; 4];
        reader.read_exact(&mut magic).map_err(Io)?;
        // We only validate magic as we don't care for version and length of
        // contents, the caller does.  Let them decide what to do next with
        // regard to version and length.
        if &magic == b"glTF" {
            Ok(Self {
                magic,
                version: reader.read_u32::<LE>().map_err(Io)?,
                length: reader.read_u32::<LE>().map_err(Io)?,
            })
        } else {
            Err(Error::Magic(magic))
        }
    }

    fn size_of() -> usize { 12 }
}

impl ChunkHeader {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, Error> {
        use self::Error::Io;
        let length = reader.read_u32::<LE>().map_err(Io)?;
        let mut ty = [0; 4];
        reader.read_exact(&mut ty).map_err(Io)?;
        let ty = match &ty {
            b"JSON" => Ok(ChunkType::Json),
            b"BIN\0" => Ok(ChunkType::Bin),
            _ => Err(Error::UnknownChunkType(ty)),
        }?;
        Ok(Self { length, ty })
    }
}

impl<'a> Glb<'a> {
    /// Splits loaded GLB into its three chunks.
    ///
    /// * Mandatory GLB header.
    /// * Mandatory JSON chunk.
    /// * Optional BIN chunk.
    pub fn from_slice(mut data: &'a [u8]) -> Result<Self, ::Error> {
        let header = Header::from_reader(&mut data)
            .and_then(|header| {
                let contents_length = header.length as usize - Header::size_of();
                if contents_length <= data.len() {
                    Ok(header)
                } else {
                    Err(Error::Length {
                        length: contents_length as u32,
                        length_read: data.len(),
                    })
                }
            })
            .map_err(::Error::Glb)?;
        match header.version {
            2 => Self::from_v2(data)
                .map(|(json, bin)| Glb { header, json, bin })
                .map_err(::Error::Glb),
            x => Err(::Error::Glb(Error::Version(x)))
        }
    }

    /// Does the loading job for you.  Provided buf will be cleared before new
    /// data will be written.  When error happens, if only header was read, buf
    /// will not be mutated, otherwise, buf will be empty.
    pub fn from_reader<R: io::Read>(mut reader: R, buf: &'a mut Vec<u8>)
                                    -> Result<Self, ::Error> {
        let header = Header::from_reader(&mut reader).map_err(::Error::Glb)?;
        match header.version {
            2 => {
                let glb_len = header.length - Header::size_of() as u32;
                buf.clear();
                buf.reserve(glb_len as usize);
                // SAFETY: We are doing unsafe operation on a user-supplied
                // container!  Make sure not to expose user to uninitialized
                // data if an error happens during reading.
                //
                // It is guaranteed by reserve's implementation that the reserve
                // call will make buf's capacity _at least_ buf_len.
                //
                // We do not read contents of the Vec unless it is fully
                // initialized.
                unsafe { buf.set_len(glb_len as usize) };
                if let Err(e) = reader.read_exact(buf).map_err(Error::Io) {
                    // SAFETY: It is safe to not run destructors because u8 has
                    // none.
                    unsafe { buf.set_len(0) };
                    Err(::Error::Glb(e))
                } else {
                    Self::from_v2(buf)
                       .map(|(json, bin)| Glb { header, json, bin })
                       .map_err(::Error::Glb)
                }
            }
            x => Err(::Error::Glb(Error::Version(x)))
        }
    }

    fn from_v2(mut data: &'a [u8]) -> Result<(&'a [u8], Option<&'a [u8]>), Error> {
        let (json, mut data) = ChunkHeader::from_reader(&mut data)
            .and_then(|json_h| if let ChunkType::Json = json_h.ty {
                Ok(json_h)
            } else {
                Err(Error::ChunkType(json_h.ty))
            })
            .and_then(|json_h| if json_h.length as usize <= data.len() {
                Ok(json_h)
            } else {
                Err(Error::ChunkLength {
                    ty: json_h.ty,
                    length: json_h.length,
                    length_read: data.len(),
                })
            })
            // PANIC: We have verified that json_h.length is no greater than
            // that of data.len().
            .map(|json_h| data.split_at(json_h.length as usize))?;

        let bin = if data.len() > 0 {
            ChunkHeader::from_reader(&mut data)
                .and_then(|bin_h| if let ChunkType::Bin = bin_h.ty {
                    Ok(bin_h)
                } else {
                    Err(Error::ChunkType(bin_h.ty))
                })
                .and_then(|bin_h| if bin_h.length as usize <= data.len() {
                    Ok(bin_h)
                } else {
                    Err(Error::ChunkLength {
                        ty: bin_h.ty,
                        length: bin_h.length,
                        length_read: data.len(),
                    })
                })
                // PANIC: we have verified that bin_h.length is no greater than
                // that of data.len().
                .map(|bin_h| data.split_at(bin_h.length as usize))
                .map(|(x, _)| Some(x))?
        } else {
            None
        };
        Ok((json, bin))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
         match *self {
             Error::Io(ref e) => e.description(),
             Error::Version(_) => "unsupported version",
             Error::Magic(_) => "not glTF magic",
             Error::Length { .. } => "could not completely read the object",
             Error::ChunkLength { ty, .. } => match ty {
                 ChunkType::Json => "JSON chunk length exceeds that of slice",
                 ChunkType::Bin => "BIN\\0 chunk length exceeds that of slice",
             },
             Error::ChunkType(ty) => match ty {
                 ChunkType::Json => "was not expecting JSON chunk",
                 ChunkType::Bin => "was not expecting BIN\\0 chunk",
             },
             Error::UnknownChunkType(_) => "unknown chunk type",
        }
    }
}
<commit_msg>Remove redundant and confusing `PANIC's in panic-safety explanation comments<commit_after>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use byteorder::{LE, ReadBytesExt};

use std::{fmt, io};

/// Represents a Glb loader error.
#[derive(Debug)]
pub enum Error {
    /// Io error occured.
    Io(::std::io::Error),
    /// Unsupported version.
    Version(u32),
    /// Magic says that file is not glTF.
    Magic([u8; 4]),
    /// Length specified in GLB header exceeeds that of slice.
    Length {
        /// length specified in GLB header.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Stream ended before we could read the chunk.
    ChunkLength {
        /// chunkType error happened at.
        ty: ChunkType,
        /// chunkLength.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Chunk of this chunkType was not expected.
    ChunkType(ChunkType),
    /// Unknown chunk type.
    UnknownChunkType([u8; 4]),
}

/// The contents of a .glb file.
#[derive(Clone, Debug)]
pub struct Glb<'a> {
    /// The header section of the `.glb` file.
    pub header: Header,
    /// The JSON section of the `.glb` file.
    pub json: &'a [u8],
    /// The optional BIN section of the `.glb` file.
    pub bin: Option<&'a [u8]>,
}

/// The header section of a .glb file.
#[derive(Copy, Clone, Debug)]
pub struct Header {
    /// Must be `b"glTF"`.
    pub magic: [u8; 4],
    /// Must be `2`.
    pub version: u32,
    /// Must match the length of the parent .glb file.
    pub length: u32,
}

/// GLB chunk type.
#[derive(Copy, Clone, Debug)]
pub enum ChunkType {
    /// JSON chunk.
    Json,
    /// BIN\0 chunk.
    Bin,
}

/// Chunk header with no data read yet.
#[derive(Copy, Clone, Debug)]
struct ChunkHeader {
    /// The length of the chunk data in byte excluding the header.
    length: u32,
    /// Chunk type.
    ty: ChunkType,
}

impl Header {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, Error> {
        use self::Error::Io;
        let mut magic = [0; 4];
        reader.read_exact(&mut magic).map_err(Io)?;
        // We only validate magic as we don't care for version and length of
        // contents, the caller does.  Let them decide what to do next with
        // regard to version and length.
        if &magic == b"glTF" {
            Ok(Self {
                magic,
                version: reader.read_u32::<LE>().map_err(Io)?,
                length: reader.read_u32::<LE>().map_err(Io)?,
            })
        } else {
            Err(Error::Magic(magic))
        }
    }

    fn size_of() -> usize { 12 }
}

impl ChunkHeader {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, Error> {
        use self::Error::Io;
        let length = reader.read_u32::<LE>().map_err(Io)?;
        let mut ty = [0; 4];
        reader.read_exact(&mut ty).map_err(Io)?;
        let ty = match &ty {
            b"JSON" => Ok(ChunkType::Json),
            b"BIN\0" => Ok(ChunkType::Bin),
            _ => Err(Error::UnknownChunkType(ty)),
        }?;
        Ok(Self { length, ty })
    }
}

impl<'a> Glb<'a> {
    /// Splits loaded GLB into its three chunks.
    ///
    /// * Mandatory GLB header.
    /// * Mandatory JSON chunk.
    /// * Optional BIN chunk.
    pub fn from_slice(mut data: &'a [u8]) -> Result<Self, ::Error> {
        let header = Header::from_reader(&mut data)
            .and_then(|header| {
                let contents_length = header.length as usize - Header::size_of();
                if contents_length <= data.len() {
                    Ok(header)
                } else {
                    Err(Error::Length {
                        length: contents_length as u32,
                        length_read: data.len(),
                    })
                }
            })
            .map_err(::Error::Glb)?;
        match header.version {
            2 => Self::from_v2(data)
                .map(|(json, bin)| Glb { header, json, bin })
                .map_err(::Error::Glb),
            x => Err(::Error::Glb(Error::Version(x)))
        }
    }

    /// Does the loading job for you.  Provided buf will be cleared before new
    /// data will be written.  When error happens, if only header was read, buf
    /// will not be mutated, otherwise, buf will be empty.
    pub fn from_reader<R: io::Read>(mut reader: R, buf: &'a mut Vec<u8>)
                                    -> Result<Self, ::Error> {
        let header = Header::from_reader(&mut reader).map_err(::Error::Glb)?;
        match header.version {
            2 => {
                let glb_len = header.length - Header::size_of() as u32;
                buf.clear();
                buf.reserve(glb_len as usize);
                // SAFETY: We are doing unsafe operation on a user-supplied
                // container!  Make sure not to expose user to uninitialized
                // data if an error happens during reading.
                //
                // It is guaranteed by reserve's implementation that the reserve
                // call will make buf's capacity _at least_ buf_len.
                //
                // We do not read contents of the Vec unless it is fully
                // initialized.
                unsafe { buf.set_len(glb_len as usize) };
                if let Err(e) = reader.read_exact(buf).map_err(Error::Io) {
                    // SAFETY: It is safe to not run destructors because u8 has
                    // none.
                    unsafe { buf.set_len(0) };
                    Err(::Error::Glb(e))
                } else {
                    Self::from_v2(buf)
                       .map(|(json, bin)| Glb { header, json, bin })
                       .map_err(::Error::Glb)
                }
            }
            x => Err(::Error::Glb(Error::Version(x)))
        }
    }

    fn from_v2(mut data: &'a [u8]) -> Result<(&'a [u8], Option<&'a [u8]>), Error> {
        let (json, mut data) = ChunkHeader::from_reader(&mut data)
            .and_then(|json_h| if let ChunkType::Json = json_h.ty {
                Ok(json_h)
            } else {
                Err(Error::ChunkType(json_h.ty))
            })
            .and_then(|json_h| if json_h.length as usize <= data.len() {
                Ok(json_h)
            } else {
                Err(Error::ChunkLength {
                    ty: json_h.ty,
                    length: json_h.length,
                    length_read: data.len(),
                })
            })
            // We have verified that json_h.length is no greater than that of
            // data.len().
            .map(|json_h| data.split_at(json_h.length as usize))?;

        let bin = if data.len() > 0 {
            ChunkHeader::from_reader(&mut data)
                .and_then(|bin_h| if let ChunkType::Bin = bin_h.ty {
                    Ok(bin_h)
                } else {
                    Err(Error::ChunkType(bin_h.ty))
                })
                .and_then(|bin_h| if bin_h.length as usize <= data.len() {
                    Ok(bin_h)
                } else {
                    Err(Error::ChunkLength {
                        ty: bin_h.ty,
                        length: bin_h.length,
                        length_read: data.len(),
                    })
                })
                // We have verified that bin_h.length is no greater than that
                // of data.len().
                .map(|bin_h| data.split_at(bin_h.length as usize))
                .map(|(x, _)| Some(x))?
        } else {
            None
        };
        Ok((json, bin))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
         match *self {
             Error::Io(ref e) => e.description(),
             Error::Version(_) => "unsupported version",
             Error::Magic(_) => "not glTF magic",
             Error::Length { .. } => "could not completely read the object",
             Error::ChunkLength { ty, .. } => match ty {
                 ChunkType::Json => "JSON chunk length exceeds that of slice",
                 ChunkType::Bin => "BIN\\0 chunk length exceeds that of slice",
             },
             Error::ChunkType(ty) => match ty {
                 ChunkType::Json => "was not expecting JSON chunk",
                 ChunkType::Bin => "was not expecting BIN\\0 chunk",
             },
             Error::UnknownChunkType(_) => "unknown chunk type",
        }
    }
}
<|endoftext|>


<commit_before>use {Color, Rgb, Luma, Xyz, Lab, Lch, Hsl, ColorSpace, Mix, Shade, GetHue, Hue, Saturate, RgbHue, clamp};

///Linear HSV color space with an alpha component.
///
///HSV is a cylindrical version of [RGB](struct.Rgb.html) and it's very
///similar to [HSL](struct.Hsl.html). The difference is that the `value`
///component in HSV determines the _brightness_ of the color, and not the
///_lightness_. The difference is that, for example, red (100% R, 0% G, 0% B)
///and white (100% R, 100% G, 100% B) has the same brightness (or value), but
///not the same lightness.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Hsv {
    ///The hue of the color, in degrees. Decides if it's red, blue, purple,
    ///etc.
    pub hue: RgbHue,

    ///The colorfulness of the color. 0.0 gives gray scale colors and 1.0 will
    ///give absolutely clear colors.
    pub saturation: f32,

    ///Decides how bright the color will look. 0.0 will be black, and 1.0 will
    ///give a bright an clear color that goes towards white when `saturation`
    ///goes towards 0.0.
    pub value: f32,

    ///The transparency of the color. 0.0 is completely transparent and 1.0 is
    ///completely opaque.
    pub alpha: f32,
}

impl Hsv {
    ///Linear HSV.
    pub fn hsv(hue: RgbHue, saturation: f32, value: f32) -> Hsv {
        Hsv {
            hue: hue,
            saturation: saturation,
            value: value,
            alpha: 1.0,
        }
    }

    ///Linear HSV and transparency.
    pub fn hsva(hue: RgbHue, saturation: f32, value: f32, alpha: f32) -> Hsv {
        Hsv {
            hue: hue,
            saturation: saturation,
            value: value,
            alpha: alpha,
        }
    }
}

impl ColorSpace for Hsv {
    fn is_valid(&self) -> bool {
        self.saturation >= 0.0 && self.saturation <= 1.0 &&
        self.value >= 0.0 && self.value <= 1.0 &&
        self.alpha >= 0.0 && self.alpha <= 1.0
    }

    fn clamp(&self) -> Hsv {
        let mut c = *self;
        c.clamp_self();
        c
    }

    fn clamp_self(&mut self) {
        self.saturation = clamp(self.saturation, 0.0, 1.0);
        self.value = clamp(self.value, 0.0, 1.0);
        self.alpha = clamp(self.alpha, 0.0, 1.0);
    }
}

impl Mix for Hsv {
    fn mix(&self, other: &Hsv, factor: f32) -> Hsv {
        let factor = clamp(factor, 0.0, 1.0);
        let hue_diff: f32 = (other.hue - self.hue).into();

        Hsv {
            hue: self.hue + factor * hue_diff,
            saturation: self.saturation + factor * (other.saturation - self.saturation),
            value: self.value + factor * (other.value - self.value),
            alpha: self.alpha + factor * (other.alpha - self.alpha),
        }
    }
}

impl Shade for Hsv {
    fn lighten(&self, amount: f32) -> Hsv {
        Hsv {
            hue: self.hue,
            saturation: self.saturation,
            value: self.value + amount,
            alpha: self.alpha,
        }
    }
}

impl GetHue for Hsv {
    type Hue = RgbHue;

    fn get_hue(&self) -> Option<RgbHue> {
        if self.saturation <= 0.0 || self.value <= 0.0 {
            None
        } else {
            Some(self.hue)
        }
    }
}

impl Hue for Hsv {
    fn with_hue(&self, hue: RgbHue) -> Hsv {
        Hsv {
            hue: hue,
            saturation: self.saturation,
            value: self.value,
            alpha: self.alpha,
        }
    }

    fn shift_hue(&self, amount: RgbHue) -> Hsv {
        Hsv {
            hue: self.hue + amount,
            saturation: self.saturation,
            value: self.value,
            alpha: self.alpha,
        }
    }
}

impl Saturate for Hsv {
    fn saturate(&self, factor: f32) -> Hsv {
        Hsv {
            hue: self.hue,
            saturation: self.saturation * (1.0 + factor),
            value: self.value,
            alpha: self.alpha,
        }
    }
}

impl Default for Hsv {
    fn default() -> Hsv {
        Hsv::hsv(0.0.into(), 0.0, 0.0)
    }
}

from_color!(to Hsv from Rgb, Luma, Xyz, Lab, Lch, Hsl);

impl From<Rgb> for Hsv {
    fn from(rgb: Rgb) -> Hsv {
        enum Channel { Red, Green, Blue };

        let val_min = rgb.red.min(rgb.green).min(rgb.blue);
        let mut val_max = rgb.red;
        let mut chan_max = Channel::Red;

        if rgb.green > val_max {
            chan_max = Channel::Green;
            val_max = rgb.green;
        }

        if rgb.blue > val_max {
            chan_max = Channel::Blue;
            val_max = rgb.blue;
        }

        let diff = val_max - val_min;

        let hue = if diff == 0.0 {
            0.0
        } else {
            60.0 * match chan_max {
                Channel::Red => ((rgb.green - rgb.blue) / diff) % 6.0,
                Channel::Green => ((rgb.blue - rgb.red) / diff + 2.0),
                Channel::Blue => ((rgb.red - rgb.green) / diff + 4.0),
            }
        };

        let saturation = if val_max == 0.0 {
            0.0
        } else {
            diff / val_max
        };

        Hsv {
            hue: hue.into(),
            saturation: saturation,
            value: val_max,
            alpha: rgb.alpha,
        }
    }
}

impl From<Luma> for Hsv {
    fn from(luma: Luma) -> Hsv {
        Rgb::from(luma).into()
    }
}

impl From<Xyz> for Hsv {
    fn from(xyz: Xyz) -> Hsv {
        Rgb::from(xyz).into()
    }
}

impl From<Lab> for Hsv {
    fn from(lab: Lab) -> Hsv {
        Rgb::from(lab).into()
    }
}

impl From<Lch> for Hsv {
    fn from(lch: Lch) -> Hsv {
        Rgb::from(lch).into()
    }
}

impl From<Hsl> for Hsv {
    fn from(hsl: Hsl) -> Hsv {
        let x = hsl.saturation * if hsl.lightness < 0.5 {
            hsl.lightness
        } else {
            1.0 - hsl.lightness
        };

        Hsv {
            hue: hsl.hue,
            saturation: 2.0 * x / (hsl.lightness + x),
            value: hsl.lightness + x,
            alpha: hsl.alpha,
        }
    }
}

#[cfg(test)]
mod test {
    use super::Hsv;
    use ::{Rgb, Hsl};

    #[test]
    fn red() {
        let a = Hsv::from(Rgb::linear_rgb(1.0, 0.0, 0.0));
        let b = Hsv::hsv(0.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(0.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }

    #[test]
    fn orange() {
        let a = Hsv::from(Rgb::linear_rgb(1.0, 0.5, 0.0));
        let b = Hsv::hsv(30.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(30.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }

    #[test]
    fn green() {
        let a = Hsv::from(Rgb::linear_rgb(0.0, 1.0, 0.0));
        let b = Hsv::hsv(120.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(120.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }

    #[test]
    fn blue() {
        let a = Hsv::from(Rgb::linear_rgb(0.0, 0.0, 1.0));
        let b = Hsv::hsv(240.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(240.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }

    #[test]
    fn purple() {
        let a = Hsv::from(Rgb::linear_rgb(0.5, 0.0, 1.0));
        let b = Hsv::hsv(270.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(270.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }
}
<commit_msg>Implement Add and Sub for Hsv<commit_after>use std::ops::{Add, Sub};

use {Color, Rgb, Luma, Xyz, Lab, Lch, Hsl, ColorSpace, Mix, Shade, GetHue, Hue, Saturate, RgbHue, clamp};

///Linear HSV color space with an alpha component.
///
///HSV is a cylindrical version of [RGB](struct.Rgb.html) and it's very
///similar to [HSL](struct.Hsl.html). The difference is that the `value`
///component in HSV determines the _brightness_ of the color, and not the
///_lightness_. The difference is that, for example, red (100% R, 0% G, 0% B)
///and white (100% R, 100% G, 100% B) has the same brightness (or value), but
///not the same lightness.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Hsv {
    ///The hue of the color, in degrees. Decides if it's red, blue, purple,
    ///etc.
    pub hue: RgbHue,

    ///The colorfulness of the color. 0.0 gives gray scale colors and 1.0 will
    ///give absolutely clear colors.
    pub saturation: f32,

    ///Decides how bright the color will look. 0.0 will be black, and 1.0 will
    ///give a bright an clear color that goes towards white when `saturation`
    ///goes towards 0.0.
    pub value: f32,

    ///The transparency of the color. 0.0 is completely transparent and 1.0 is
    ///completely opaque.
    pub alpha: f32,
}

impl Hsv {
    ///Linear HSV.
    pub fn hsv(hue: RgbHue, saturation: f32, value: f32) -> Hsv {
        Hsv {
            hue: hue,
            saturation: saturation,
            value: value,
            alpha: 1.0,
        }
    }

    ///Linear HSV and transparency.
    pub fn hsva(hue: RgbHue, saturation: f32, value: f32, alpha: f32) -> Hsv {
        Hsv {
            hue: hue,
            saturation: saturation,
            value: value,
            alpha: alpha,
        }
    }
}

impl ColorSpace for Hsv {
    fn is_valid(&self) -> bool {
        self.saturation >= 0.0 && self.saturation <= 1.0 &&
        self.value >= 0.0 && self.value <= 1.0 &&
        self.alpha >= 0.0 && self.alpha <= 1.0
    }

    fn clamp(&self) -> Hsv {
        let mut c = *self;
        c.clamp_self();
        c
    }

    fn clamp_self(&mut self) {
        self.saturation = clamp(self.saturation, 0.0, 1.0);
        self.value = clamp(self.value, 0.0, 1.0);
        self.alpha = clamp(self.alpha, 0.0, 1.0);
    }
}

impl Mix for Hsv {
    fn mix(&self, other: &Hsv, factor: f32) -> Hsv {
        let factor = clamp(factor, 0.0, 1.0);
        let hue_diff: f32 = (other.hue - self.hue).into();

        Hsv {
            hue: self.hue + factor * hue_diff,
            saturation: self.saturation + factor * (other.saturation - self.saturation),
            value: self.value + factor * (other.value - self.value),
            alpha: self.alpha + factor * (other.alpha - self.alpha),
        }
    }
}

impl Shade for Hsv {
    fn lighten(&self, amount: f32) -> Hsv {
        Hsv {
            hue: self.hue,
            saturation: self.saturation,
            value: self.value + amount,
            alpha: self.alpha,
        }
    }
}

impl GetHue for Hsv {
    type Hue = RgbHue;

    fn get_hue(&self) -> Option<RgbHue> {
        if self.saturation <= 0.0 || self.value <= 0.0 {
            None
        } else {
            Some(self.hue)
        }
    }
}

impl Hue for Hsv {
    fn with_hue(&self, hue: RgbHue) -> Hsv {
        Hsv {
            hue: hue,
            saturation: self.saturation,
            value: self.value,
            alpha: self.alpha,
        }
    }

    fn shift_hue(&self, amount: RgbHue) -> Hsv {
        Hsv {
            hue: self.hue + amount,
            saturation: self.saturation,
            value: self.value,
            alpha: self.alpha,
        }
    }
}

impl Saturate for Hsv {
    fn saturate(&self, factor: f32) -> Hsv {
        Hsv {
            hue: self.hue,
            saturation: self.saturation * (1.0 + factor),
            value: self.value,
            alpha: self.alpha,
        }
    }
}

impl Default for Hsv {
    fn default() -> Hsv {
        Hsv::hsv(0.0.into(), 0.0, 0.0)
    }
}

impl Add<Hsv> for Hsv {
    type Output = Hsv;

    fn add(self, other: Hsv) -> Hsv {
        Hsv {
            hue: self.hue + other.hue,
            saturation: self.saturation + other.saturation,
            value: self.value + other.value,
            alpha: self.alpha + other.alpha,
        }
    }
}

impl Add<f32> for Hsv {
    type Output = Hsv;

    fn add(self, c: f32) -> Hsv {
        Hsv {
            hue: self.hue + c,
            saturation: self.saturation + c,
            value: self.value + c,
            alpha: self.alpha + c,
        }
    }
}

impl Sub<Hsv> for Hsv {
    type Output = Hsv;

    fn sub(self, other: Hsv) -> Hsv {
        Hsv {
            hue: self.hue - other.hue,
            saturation: self.saturation - other.saturation,
            value: self.value - other.value,
            alpha: self.alpha - other.alpha,
        }
    }
}

impl Sub<f32> for Hsv {
    type Output = Hsv;

    fn sub(self, c: f32) -> Hsv {
        Hsv {
            hue: self.hue - c,
            saturation: self.saturation - c,
            value: self.value - c,
            alpha: self.alpha - c,
        }
    }
}

from_color!(to Hsv from Rgb, Luma, Xyz, Lab, Lch, Hsl);

impl From<Rgb> for Hsv {
    fn from(rgb: Rgb) -> Hsv {
        enum Channel { Red, Green, Blue };

        let val_min = rgb.red.min(rgb.green).min(rgb.blue);
        let mut val_max = rgb.red;
        let mut chan_max = Channel::Red;

        if rgb.green > val_max {
            chan_max = Channel::Green;
            val_max = rgb.green;
        }

        if rgb.blue > val_max {
            chan_max = Channel::Blue;
            val_max = rgb.blue;
        }

        let diff = val_max - val_min;

        let hue = if diff == 0.0 {
            0.0
        } else {
            60.0 * match chan_max {
                Channel::Red => ((rgb.green - rgb.blue) / diff) % 6.0,
                Channel::Green => ((rgb.blue - rgb.red) / diff + 2.0),
                Channel::Blue => ((rgb.red - rgb.green) / diff + 4.0),
            }
        };

        let saturation = if val_max == 0.0 {
            0.0
        } else {
            diff / val_max
        };

        Hsv {
            hue: hue.into(),
            saturation: saturation,
            value: val_max,
            alpha: rgb.alpha,
        }
    }
}

impl From<Luma> for Hsv {
    fn from(luma: Luma) -> Hsv {
        Rgb::from(luma).into()
    }
}

impl From<Xyz> for Hsv {
    fn from(xyz: Xyz) -> Hsv {
        Rgb::from(xyz).into()
    }
}

impl From<Lab> for Hsv {
    fn from(lab: Lab) -> Hsv {
        Rgb::from(lab).into()
    }
}

impl From<Lch> for Hsv {
    fn from(lch: Lch) -> Hsv {
        Rgb::from(lch).into()
    }
}

impl From<Hsl> for Hsv {
    fn from(hsl: Hsl) -> Hsv {
        let x = hsl.saturation * if hsl.lightness < 0.5 {
            hsl.lightness
        } else {
            1.0 - hsl.lightness
        };

        Hsv {
            hue: hsl.hue,
            saturation: 2.0 * x / (hsl.lightness + x),
            value: hsl.lightness + x,
            alpha: hsl.alpha,
        }
    }
}

#[cfg(test)]
mod test {
    use super::Hsv;
    use ::{Rgb, Hsl};

    #[test]
    fn red() {
        let a = Hsv::from(Rgb::linear_rgb(1.0, 0.0, 0.0));
        let b = Hsv::hsv(0.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(0.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }

    #[test]
    fn orange() {
        let a = Hsv::from(Rgb::linear_rgb(1.0, 0.5, 0.0));
        let b = Hsv::hsv(30.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(30.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }

    #[test]
    fn green() {
        let a = Hsv::from(Rgb::linear_rgb(0.0, 1.0, 0.0));
        let b = Hsv::hsv(120.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(120.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }

    #[test]
    fn blue() {
        let a = Hsv::from(Rgb::linear_rgb(0.0, 0.0, 1.0));
        let b = Hsv::hsv(240.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(240.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }

    #[test]
    fn purple() {
        let a = Hsv::from(Rgb::linear_rgb(0.5, 0.0, 1.0));
        let b = Hsv::hsv(270.0.into(), 1.0, 1.0);
        let c = Hsv::from(Hsl::hsl(270.0.into(), 1.0, 0.5));

        assert_approx_eq!(a, b, [hue, saturation, value]);
        assert_approx_eq!(a, c, [hue, saturation, value]);
    }
}
<|endoftext|>


<commit_before>// finds the longest common subsequences
// outputs the edit distance and a string containing
// all chars both inputs have in common
pub fn lcs(orig: &str, edit: &str, split: &str) -> (i32, String) {

    let a : Vec<&str> = orig.split(split).collect();
    let b : Vec<&str> = edit.split(split).collect();

    let N = a.len() as i32;
    let M = b.len() as i32;

    let MAX = N + M;

    let mut v : Vec<i32> = (-MAX..MAX).collect();

    let mut common = String::new();

    v[1] = 0;

    for D in 0..MAX {
        let mut max = 0;
        let mut max_snake : Box<String> = Box::new("".to_string());

        for k in (-D..D+1).step_by(2) {
            let mut snake = String::new();

            let mut x;

            let index = (MAX + k - 1) as usize;
            if k == -D || k != D && v[index - 1] < v[index + 1]{
                x = v[index + 1];
            }else{
                x = v[index - 1] + 1;
            }

            let mut y = x - k;

            while x < N && y < M && a[x as usize] == b[y as usize] {
                snake.push_str(a[x as usize]);
                snake.push_str(split);
                x += 1;
                y += 1;
            }

            v[index] = x;

            if x > max {
                max = x;
                max_snake = Box::new(snake);
            }

            if x >= N && y >= M {
                if max_snake.len() > 0 {
                    common.push_str(&max_snake);
                }
                return (D, common);
            }
        }

        if max_snake.len() > 0 {
            common.push_str(&max_snake);
        }

    }

    unreachable!()
}

#[test]
fn test_lcs() {
    assert_eq!(lcs("test", "tost", ""), (2, "tst".to_string()));
    assert_eq!(lcs("The quick brown fox jumps over the lazy dog", "The quick brown dog leaps over the lazy cat", ""), (16, "The quick brown o ps over the lazy ".to_string()));
    assert_eq!(lcs("The quick brown fox jumps over the lazy dog", "The quick brown dog leaps over the lazy cat", " "), (6, "The quick brown over the lazy ".to_string()));
}
<commit_msg>Remove unreachable at the end of lcs<commit_after>// finds the longest common subsequences
// outputs the edit distance and a string containing
// all chars both inputs have in common
#[allow(non_snake_case)]
pub fn lcs(orig: &str, edit: &str, split: &str) -> (i32, String) {

    // make list by custom splits
    let a : Vec<&str> = orig.split(split).collect();
    let b : Vec<&str> = edit.split(split).collect();

    let N = a.len() as i32;
    let M = b.len() as i32;

    let MAX = N + M;

    let mut v : Vec<i32> = (-MAX..MAX).collect();

    let mut common = String::new();

    v[1] = 0;

    for D in 0..MAX {
        let mut max = 0;
        let mut max_snake : Box<String> = Box::new("".to_string());

        for k in (-D..D+1).step_by(2) {
            let mut snake = String::new();

            let mut x;

            let index = (MAX + k - 1) as usize;
            if k == -D || k != D && v[index - 1] < v[index + 1]{
                x = v[index + 1];
            }else{
                x = v[index - 1] + 1;
            }

            let mut y = x - k;

            while x < N && y < M && a[x as usize] == b[y as usize] {
                if snake.len() > 0 {
                    // add back the splits that were taken away
                    snake.push_str(split);
                }
                snake.push_str(a[x as usize]);
                x += 1;
                y += 1;
            }

            v[index] = x;

            if x > max {
                max = x;
                max_snake = Box::new(snake);
            }

            if x >= N && y >= M {
                // add last max_snake
                if max_snake.len() > 0 {
                    if common.len() > 0 {
                        // add back the splits that were taken away
                        common.push_str(split);
                    }
                    common.push_str(&max_snake);
                }
                return (D, common);
            }
        }

        if max_snake.len() > 0 {
            if common.len() > 0 {
                // add back the splits that were taken away
                common.push_str(split);
            }
            common.push_str(&max_snake);
        }

    }

    // both strings don't match at all
    (MAX, "".to_string())
}

#[test]
fn test_lcs() {
    assert_eq!(lcs("test", "tost", ""), (2, "tst".to_string()));
    assert_eq!(lcs("test", "test", ""), (0, "test".to_string()));

    assert_eq!(lcs("test", "test", " "), (0, "test".to_string()));

    assert_eq!(lcs("The quick brown fox jumps over the lazy dog", "The quick brown dog leaps over the lazy cat", ""), (16, "The quick brown o ps over the lazy ".to_string()));
    assert_eq!(lcs("The quick brown fox jumps over the lazy dog", "The quick brown dog leaps over the lazy cat", " "), (6, "The quick brown over the lazy".to_string()));

    assert_eq!(lcs("The quick brown fox jumps over the lazy dog", "The quick brown dog leaps over the lazy cat", "\n"), (2, "".to_string()));
    assert_eq!(lcs("The quick brown fox jumps over the lazy dog", "The quick brown fox jumps over the lazy dog", "\n"), (0, "The quick brown fox jumps over the lazy dog".to_string()));
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate route_recognizer;

use hyper::header::Headers;
use hyper::method::Method;
use hyper::server::Handler as HyperHandler;
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

use route_recognizer::Router;

pub use route_recognizer::{Match, Params};

#[macro_export]
macro_rules! create_router {
    ( $( $path:expr => $( $method:ident ),+ => $handler:expr ),+, ) => {{
        let mut router = $crate::HyperRouter::new();

        $(
            let mut entry = $crate::RouteEntry::with_handler($handler);
            $(
                entry.add_method($crate::MethodRoutes::$method);
            )+

            router.add_path_entry($path, entry);
        )+

        router
    }};
}

fn method_to_bit(method: &Method) -> u8 {
    use hyper::method::Method::*;
    let exp = match *method {
        Options => 0,
        Get | Head => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Trace | Extension(_) => 7,
    };

    1u8 << exp
}

fn method_route_to_bit(method: MethodRoutes) -> u8 {
    use MethodRoutes::*;
    let exp = match method {
        Options => 0,
        Get => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Other => 7,
    };

    1u8 << exp
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MethodRoutes {
    Options,
    Get,
    Post,
    Put,
    Delete,
    Connect,
    Patch,
    Other,
}

#[derive(Debug)]
pub struct RouteEntry<H> {
    accepted_methods: u8,
    handler: H,
}

impl<H> RouteEntry<H> {
    pub fn with_handler(handler: H) -> RouteEntry<H> {
        RouteEntry {
            accepted_methods: 0,
            handler: handler,
        }
    }

    pub fn add_method(&mut self, method: MethodRoutes) {
        self.accepted_methods |= method_route_to_bit(method);
    }

    pub fn add_methods(&mut self, methods: &[MethodRoutes]) {
        for method in methods {
            self.accepted_methods |= method_route_to_bit(*method);
        }
    }

    pub fn add_all_methods(&mut self) {
        self.accepted_methods = !0u8;
    }

    pub fn accepts_method(&self, method: &Method) -> bool {
        (self.accepted_methods & method_to_bit(method)) > 0
    }

    pub fn handler(&self) -> &H {
        &self.handler
    }
}

pub trait RouteHandler: Sync + Send {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>);

    fn check_continue(&self, _: Params, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
        StatusCode::Continue
    }
}

impl RouteHandler for Box<RouteHandler> {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.as_ref().handle(params, req, res)
    }

    fn check_continue(&self, params: Params, t: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.as_ref().check_continue(params, t)
    }
}

impl RouteHandler for HyperHandler {
    fn handle<'a, 'k>(&'a self, _: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.handle(req, res)
    }

    fn check_continue(&self, _: Params, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.check_continue(tuple)
    }
}

impl<F> RouteHandler for F
    where F: Fn(Params, Request, Response),
          F: Sync + Send
{
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self(params, req, res)
    }
}

pub struct HyperRouter<H> {
    path_router: Router<RouteEntry<H>>,
    url_router: Router<RouteEntry<H>>,
    authority_router: Router<RouteEntry<H>>,
    server_wide: Option<RouteEntry<H>>,
}

impl<H> HyperRouter<H> {
    pub fn new() -> HyperRouter<H> {
        HyperRouter {
            path_router: Router::new(),
            url_router: Router::new(),
            authority_router: Router::new(),
            server_wide: None,
        }
    }

    pub fn add_path_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_url_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_authority_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_server_wide_entry(&mut self, entry: RouteEntry<H>) {
        self.server_wide = Some(entry);
    }

    pub fn get_match(&self, method: &Method, uri: &RequestUri) -> Option<Match<&RouteEntry<H>>> {
        use hyper::uri::RequestUri::*;

        let m = match *uri {
            AbsolutePath(ref path) => self.path_router.recognize(&path).ok(),
            AbsoluteUri(ref url) => self.url_router.recognize(url.as_str()).ok(),
            Authority(ref authority) => self.authority_router.recognize(&authority).ok(),
            Star => {
                self.server_wide.as_ref().map(|handler| {
                    Match {
                        handler: handler,
                        params: Params::new(),
                    }
                })
            }
        };

        if let Some(mat) = m {
            if mat.handler.accepts_method(method) {
                Some(mat)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl<H> HyperHandler for HyperRouter<H>
    where H: AsRef<RouteHandler> + Send + Sync
{
    fn handle<'a, 'k>(&'a self, req: Request<'a, 'k>, mut res: Response<'a>) {
        if let Some(matches) = self.get_match(&req.method, &req.uri) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().handle(params, req, res);
        } else {
            *res.status_mut() = StatusCode::NotFound;
        }
    }

    fn check_continue(&self, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        if let Some(matches) = self.get_match(tuple.0, tuple.1) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().check_continue(params, tuple)
        } else {
            StatusCode::Continue
        }
    }
}

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

    use hyper::method::Method;
    use hyper::uri::RequestUri;

    #[test]
    fn simple_test() {
        let mut entry = RouteEntry::with_handler(0u8);
        entry.add_method(MethodRoutes::Get);
        let mut router = HyperRouter::new();
        router.add_path_entry("/test/", entry);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test2/")));
        assert!(res.is_none());

        let res = router.get_match(&Method::Post,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());
    }

    #[test]
    fn multi_method_test() {
        let mut entry = RouteEntry::with_handler(0u8);
        entry.add_method(MethodRoutes::Get);
        entry.add_method(MethodRoutes::Put);
        let mut router = HyperRouter::new();
        router.add_path_entry("/test/", entry);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Put,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Post,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());
    }

    #[test]
    fn create_router_test() {
        let router = create_router! {
            "/test/" => Get, Put => 0u8,
            "/test2/:id" => Delete => 1u8,
        };

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Put,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Delete,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());

        let res = router.get_match(&Method::Delete,
                                   &RequestUri::AbsolutePath(String::from("/test2/test")));
        assert_eq!(res.as_ref().unwrap().handler.handler, 1u8);
        assert_eq!(res.unwrap().params["id"], "test");
    }
}
<commit_msg>Remove AsRef bound<commit_after>extern crate hyper;
extern crate route_recognizer;

use hyper::header::Headers;
use hyper::method::Method;
use hyper::server::Handler as HyperHandler;
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

use route_recognizer::Router;

pub use route_recognizer::{Match, Params};

#[macro_export]
macro_rules! create_router {
    ( $( $path:expr => $( $method:ident ),+ => $handler:expr ),+, ) => {{
        let mut router = $crate::HyperRouter::new();

        $(
            let mut entry = $crate::RouteEntry::with_handler($handler);
            $(
                entry.add_method($crate::MethodRoutes::$method);
            )+

            router.add_path_entry($path, entry);
        )+

        router
    }};
}

fn method_to_bit(method: &Method) -> u8 {
    use hyper::method::Method::*;
    let exp = match *method {
        Options => 0,
        Get | Head => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Trace | Extension(_) => 7,
    };

    1u8 << exp
}

fn method_route_to_bit(method: MethodRoutes) -> u8 {
    use MethodRoutes::*;
    let exp = match method {
        Options => 0,
        Get => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Other => 7,
    };

    1u8 << exp
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MethodRoutes {
    Options,
    Get,
    Post,
    Put,
    Delete,
    Connect,
    Patch,
    Other,
}

#[derive(Debug)]
pub struct RouteEntry<H> {
    accepted_methods: u8,
    handler: H,
}

impl<H> RouteEntry<H> {
    pub fn with_handler(handler: H) -> RouteEntry<H> {
        RouteEntry {
            accepted_methods: 0,
            handler: handler,
        }
    }

    pub fn add_method(&mut self, method: MethodRoutes) {
        self.accepted_methods |= method_route_to_bit(method);
    }

    pub fn add_methods(&mut self, methods: &[MethodRoutes]) {
        for method in methods {
            self.accepted_methods |= method_route_to_bit(*method);
        }
    }

    pub fn add_all_methods(&mut self) {
        self.accepted_methods = !0u8;
    }

    pub fn accepts_method(&self, method: &Method) -> bool {
        (self.accepted_methods & method_to_bit(method)) > 0
    }

    pub fn handler(&self) -> &H {
        &self.handler
    }
}

pub trait RouteHandler: Sync + Send {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>);

    fn check_continue(&self, _: Params, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
        StatusCode::Continue
    }
}

impl RouteHandler for Box<RouteHandler> {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.as_ref().handle(params, req, res)
    }

    fn check_continue(&self, params: Params, t: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.as_ref().check_continue(params, t)
    }
}

impl RouteHandler for HyperHandler {
    fn handle<'a, 'k>(&'a self, _: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.handle(req, res)
    }

    fn check_continue(&self, _: Params, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.check_continue(tuple)
    }
}

impl<F> RouteHandler for F
    where F: Fn(Params, Request, Response),
          F: Sync + Send
{
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self(params, req, res)
    }
}

pub struct HyperRouter<H> {
    path_router: Router<RouteEntry<H>>,
    url_router: Router<RouteEntry<H>>,
    authority_router: Router<RouteEntry<H>>,
    server_wide: Option<RouteEntry<H>>,
}

impl<H> HyperRouter<H> {
    pub fn new() -> HyperRouter<H> {
        HyperRouter {
            path_router: Router::new(),
            url_router: Router::new(),
            authority_router: Router::new(),
            server_wide: None,
        }
    }

    pub fn add_path_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_url_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_authority_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_server_wide_entry(&mut self, entry: RouteEntry<H>) {
        self.server_wide = Some(entry);
    }

    pub fn get_match(&self, method: &Method, uri: &RequestUri) -> Option<Match<&RouteEntry<H>>> {
        use hyper::uri::RequestUri::*;

        let m = match *uri {
            AbsolutePath(ref path) => self.path_router.recognize(&path).ok(),
            AbsoluteUri(ref url) => self.url_router.recognize(url.as_str()).ok(),
            Authority(ref authority) => self.authority_router.recognize(&authority).ok(),
            Star => {
                self.server_wide.as_ref().map(|handler| {
                    Match {
                        handler: handler,
                        params: Params::new(),
                    }
                })
            }
        };

        if let Some(mat) = m {
            if mat.handler.accepts_method(method) {
                Some(mat)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl<H> HyperHandler for HyperRouter<H>
    where H: RouteHandler
{
    fn handle<'a, 'k>(&'a self, req: Request<'a, 'k>, mut res: Response<'a>) {
        if let Some(matches) = self.get_match(&req.method, &req.uri) {
            let Match { handler, params } = matches;
            handler.handler.handle(params, req, res);
        } else {
            *res.status_mut() = StatusCode::NotFound;
        }
    }

    fn check_continue(&self, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        if let Some(matches) = self.get_match(tuple.0, tuple.1) {
            let Match { handler, params } = matches;
            handler.handler.check_continue(params, tuple)
        } else {
            StatusCode::Continue
        }
    }
}

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

    use hyper::method::Method;
    use hyper::uri::RequestUri;

    #[test]
    fn simple_test() {
        let mut entry = RouteEntry::with_handler(0u8);
        entry.add_method(MethodRoutes::Get);
        let mut router = HyperRouter::new();
        router.add_path_entry("/test/", entry);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test2/")));
        assert!(res.is_none());

        let res = router.get_match(&Method::Post,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());
    }

    #[test]
    fn multi_method_test() {
        let mut entry = RouteEntry::with_handler(0u8);
        entry.add_method(MethodRoutes::Get);
        entry.add_method(MethodRoutes::Put);
        let mut router = HyperRouter::new();
        router.add_path_entry("/test/", entry);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Put,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Post,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());
    }

    #[test]
    fn create_router_test() {
        let router = create_router! {
            "/test/" => Get, Put => 0u8,
            "/test2/:id" => Delete => 1u8,
        };

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Put,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Delete,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());

        let res = router.get_match(&Method::Delete,
                                   &RequestUri::AbsolutePath(String::from("/test2/test")));
        assert_eq!(res.as_ref().unwrap().handler.handler, 1u8);
        assert_eq!(res.unwrap().params["id"], "test");
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]

use std::io::*;
use std::io::net::ip::SocketAddr;
use std::str::FromStr;
use std::error::*;
use std::time::Duration;
use std::default::Default;
use std::cell::RefCell;

pub struct Client {
    addr : SocketAddr,
    conn : RefCell<Option<TcpStream>>
}

#[deriving(Show,Clone)]
pub enum Failure {
    Io(IoError),
    Client(ClientError)
}

impl FromError<IoError> for Failure {
    fn from_error(err:IoError) -> Failure {
        Failure::Io(err)
    }
}

#[deriving(Show,Clone)]
pub struct ClientError {
    desc : String
}

impl Error for ClientError {
    fn description(&self) -> &str {
        self.desc.as_slice()
    }
}

impl FromError<ClientError> for Failure {
    fn from_error(err:ClientError) -> Failure {
        Failure::Client(err)
    }
}

pub type McResult<T> = Result<T,Failure>;

impl Client {

    pub fn new(addr:&str) -> McResult<Client> {
        let addr : Option<SocketAddr> = FromStr::from_str(addr);
        match addr {
            Some(ad) => {
                Ok(Client{addr:ad,conn:RefCell::new(None)})
            },
            None => {
                Err(Failure::Client(ClientError{desc:"invalid addr".into_string()}))
            }
        }
    }
/*
    fn get_conn(&self) -> McResult<Client> {
        let mut tc = self.conn.borrow_mut();
        if tc.is_none() {
            let t = try!(TcpStream::connect_timeout(self.addr,Duration::seconds(1)));
            *tc = Some(t);
        }
        Ok(*self)
    }
*/
}

#[test]
fn test_new_mc() {
    let mut c = Client::new("127.0.0.1:11211");
    assert!(c.is_ok());
}

<commit_msg>remove get_conn<commit_after>#![feature(globs)]

use std::io::*;
use std::io::net::ip::SocketAddr;
use std::str::FromStr;
use std::error::*;
use std::time::Duration;
use std::default::Default;
use std::cell::RefCell;

pub struct Client {
    addr : SocketAddr,
    conn : RefCell<TcpStream>
}

#[deriving(Show,Clone)]
pub enum Failure {
    Io(IoError),
    Client(ClientError)
}

impl FromError<IoError> for Failure {
    fn from_error(err:IoError) -> Failure {
        Failure::Io(err)
    }
}

#[deriving(Show,Clone)]
pub struct ClientError {
    desc : String
}

impl Error for ClientError {
    fn description(&self) -> &str {
        self.desc.as_slice()
    }
}

impl FromError<ClientError> for Failure {
    fn from_error(err:ClientError) -> Failure {
        Failure::Client(err)
    }
}

pub type McResult<T> = Result<T,Failure>;

impl Client {

    pub fn new(addr:&str) -> McResult<Client> {
        let ad : Option<SocketAddr> = FromStr::from_str(addr);
        match ad {
            Some(addr) => {
                let conn = try!(TcpStream::connect_timeout(addr,Duration::seconds(1)));
                Ok(Client{addr:addr,conn:RefCell::new(conn)})
            },
            None => {
                Err(Failure::Client(ClientError{desc:"invalid addr".into_string()}))
            }
        }
    }

}

#[test]
fn test_new_mc() {
    let c = Client::new("127.0.0.1:11211");
    assert!(c.is_ok());
}

<|endoftext|>


<commit_before>//! A minimal implementation of SHA1 for rust.
//!
//! Example:
//!
//! ```rust
//! extern crate sha1;
//! # fn main() {
//!
//! let mut m = sha1::Sha1::new();
//! m.update("Hello World!".as_bytes());
//! assert_eq!(m.hexdigest().as_slice(),
//!            "2ef7bde608ce5404e97d5f042f95f89f1c232871");
//! # }
//! ```

#![feature(slicing_syntax)]

#![experimental]

#[cfg(test)] extern crate test;

use std::io::BufWriter;

/// Represents a Sha1 hash object in memory.
#[derive(Clone)]
pub struct Sha1 {
    state: [u32; 5],
    data: Vec<u8>,
    len: u64,
}

const DEFAULT_STATE : [u32; 5] =
    [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];

fn to_hex(input: &[u8]) -> String {
    let mut s = String::new();
    for b in input.iter() {
        s.push_str(format!("{:02x}", *b)[]);
    }
    return s;
}

impl Sha1 {

    /// Creates an fresh sha1 hash object.
    pub fn new() -> Sha1 {
        Sha1 {
            state: DEFAULT_STATE,
            data: Vec::new(),
            len: 0,
        }
    }

    fn process_block(&mut self, block: &[u8]) {
        assert_eq!(block.len(), 64);

        let mut words = [0u32; 80];
        for (i, chunk) in block.chunks(4).enumerate() {
            words[i] = (chunk[3] as u32) |
                       ((chunk[2] as u32) << 8) |
                       ((chunk[1] as u32) << 16) |
                       ((chunk[0] as u32) << 24);
        }

        fn ff(b: u32, c: u32, d: u32) -> u32 { d ^ (b & (c ^ d)) }
        fn gg(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }
        fn hh(b: u32, c: u32, d: u32) -> u32 { (b & c) | (d & (b | c)) }
        fn ii(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }

        fn left_rotate(x: u32, n: u32) -> u32 { (x << n as uint) | (x >> (32 - n) as uint) }

        for i in range(16u, 80u) {
            let n = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16];
            words[i] = left_rotate(n, 1);
        }

        let mut a = self.state[0];
        let mut b = self.state[1];
        let mut c = self.state[2];
        let mut d = self.state[3];
        let mut e = self.state[4];

        for i in range(0u, 80u) {
            let (f, k) = match i {
                0 ... 19 => (ff(b, c, d), 0x5a827999),
                20 ... 39 => (gg(b, c, d), 0x6ed9eba1),
                40 ... 59 => (hh(b, c, d), 0x8f1bbcdc),
                60 ... 79 => (ii(b, c, d), 0xca62c1d6),
                _ => (0, 0),
            };

            let tmp = left_rotate(a, 5) + f + e + k + words[i];
            e = d;
            d = c;
            c = left_rotate(b, 30);
            b = a;
            a = tmp;
        }

        self.state[0] += a;
        self.state[1] += b;
        self.state[2] += c;
        self.state[3] += d;
        self.state[4] += e;
    }

    /// Resets the hash object to it's initial state.
    pub fn reset(&mut self) {
        self.state = DEFAULT_STATE;
        self.data.clear();
        self.len = 0;
    }

    /// Update hash with input data.
    pub fn update(&mut self, data: &[u8]) {
        let mut d = self.data.clone();
        self.data.clear();

        d.push_all(data);

        for chunk in d[].chunks(64) {
            if chunk.len() == 64 {
                self.len += 64;
                self.process_block(chunk);
            } else {
                self.data.push_all(chunk);
            }
        }
    }

    /// Retrieve digest result.  The output must be large enough to
    /// contain result (20 bytes).
    pub fn output(&self, out: &mut [u8]) {
        // these are unlikely to fail, since we're writing to memory
        #![allow(unused_must_use)]

        let mut m = Sha1 {
            state: self.state.clone(),
            data: Vec::new(),
            len: 0,
        };

        let mut w = Vec::<u8>::new();
        w.write(self.data[]);
        w.write_u8(0x80u8);
        let padding = 64 - ((self.data.len() + 9) % 64);
        for _ in range(0, padding) {
            w.write_u8(0u8);
        }
        w.write_be_u64((self.data.len() as u64 + self.len) * 8);
        for chunk in w[].chunks(64) {
            m.process_block(chunk);
        }

        let mut w = BufWriter::new(out);
        for &n in m.state.iter() {
            w.write_be_u32(n);
        }
    }

    /// Shortcut for getting `output` into a new vector.
    pub fn digest(&self) -> Vec<u8> {
        let mut buf = [0u8; 20].to_vec();
        self.output(&mut *buf[]);
        buf
    }

    /// Shortcut for getting a hex output of the vector.
    pub fn hexdigest(&self) -> String {
        to_hex(self.digest()[])
    }
}

#[cfg(test)]
mod tests {
    use test::Bencher;
    use super::{Sha1, to_hex};

    #[test]
    fn test_simple() {
        let mut m = Sha1::new();

        let tests = [
            ("The quick brown fox jumps over the lazy dog",
            "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"),
            ("The quick brown fox jumps over the lazy cog",
            "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"),
            ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"),
            ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"),
            ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"),
        ];

        for &(s, ref h) in tests.iter() {
            let data = s.as_bytes();

            m.reset();
            m.update(data);
            let hh = m.hexdigest();

            assert_eq!(hh.len(), h.len());
            assert_eq!(hh[], *h);
        }
    }

    #[test]
    fn test_dirty_run() {
        let mut m = Sha1::new();

        m.update(b"123");
        let out1 = m.digest();

        m.update(b"123");
        let out2 = m.digest();

        assert!(out1[] != out2[]);
        assert_eq!(to_hex(out1[])[], "40bd001563085fc35165329ea1ff5c5ecbdbbeef");
        assert_eq!(to_hex(out2[])[], "601f1889667efaebb33b8c12572835da3f027f78");
    }

    #[bench]
    fn test_sha1_speed(b: &mut Bencher) {
        let mut m = Sha1::new();
        let s = "The quick brown fox jumps over the lazy dog.";
        let n = 1000u64;

        b.bytes = n * s.len() as u64;
        b.iter(|| {
            m.reset();
            for _ in range(0, n) {
                m.update(s.as_bytes());
            }
            assert_eq!(m.hexdigest()[], "7ca27655f67fceaa78ed2e645a81c7f1d6e249d2");
        });
    }
}
<commit_msg>update to latest rust, implement hasher<commit_after>//! A minimal implementation of SHA1 for rust.
//!
//! Example:
//!
//! ```rust
//! extern crate sha1;
//! use std::hash::Writer;
//!
//! # fn main() {
//!
//! let mut m = sha1::Sha1::new();
//! m.write("Hello World!".as_bytes());
//! assert_eq!(&*m.hexdigest(), "2ef7bde608ce5404e97d5f042f95f89f1c232871");
//! # }
//! ```

#![feature(slicing_syntax)]
#![allow(unstable)]

#![experimental]

#[cfg(test)] extern crate test;
extern crate serialize;

use std::io::{Writer, BufWriter};
use std::default::Default;
use std::hash::{self, Hasher};

/// Represents a Sha1 hash object in memory.
#[derive(Clone)]
pub struct Sha1 {
    state: [u32; 5],
    data: Vec<u8>,
    len: u64,
}

const DEFAULT_STATE : [u32; 5] =
    [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];

fn to_hex(input: &[u8]) -> String {
    let mut s = String::new();
    for b in input.iter() {
        s.push_str(&*format!("{:02x}", *b));
    }
    return s;
}

impl hash::Hasher for Sha1 {
    type Output = Vec<u8>;
    fn reset(&mut self) {
        self.state = DEFAULT_STATE;
        self.data.clear();
        self.len = 0;
    }
    fn finish(&self) -> Vec<u8> {
        let mut buf = [0u8; 20].to_vec();
        self.output(&mut *buf);
        buf
    }
}

impl Default for Sha1 {
    #[inline]
    fn default() -> Sha1 {
        Sha1::new()
    }
}

impl hash::Writer for Sha1 {
    fn write(&mut self, bytes: &[u8]) {
        let mut d = self.data.clone();
        self.data.clear();

        d.push_all(bytes);

        for chunk in d[].chunks(64) {
            if chunk.len() == 64 {
                self.len += 64;
                self.process_block(chunk);
            } else {
                self.data.push_all(chunk);
            }
        }
    }
}

impl Sha1 {

    /// Creates an fresh sha1 hash object.
    pub fn new() -> Sha1 {
        Sha1 {
            state: DEFAULT_STATE,
            data: Vec::new(),
            len: 0,
        }
    }

    fn process_block(&mut self, block: &[u8]) {
        assert_eq!(block.len(), 64);

        let mut words = [0u32; 80];
        for (i, chunk) in block.chunks(4).enumerate() {
            words[i] = (chunk[3] as u32) |
                       ((chunk[2] as u32) << 8) |
                       ((chunk[1] as u32) << 16) |
                       ((chunk[0] as u32) << 24);
        }

        fn ff(b: u32, c: u32, d: u32) -> u32 { d ^ (b & (c ^ d)) }
        fn gg(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }
        fn hh(b: u32, c: u32, d: u32) -> u32 { (b & c) | (d & (b | c)) }
        fn ii(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }

        fn left_rotate(x: u32, n: u32) -> u32 { (x << n) | (x >> (32 - n)) }

        for i in range(16, 80) {
            let n = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16];
            words[i] = left_rotate(n, 1);
        }

        let mut a = self.state[0];
        let mut b = self.state[1];
        let mut c = self.state[2];
        let mut d = self.state[3];
        let mut e = self.state[4];

        for i in range(0, 80) {
            let (f, k) = match i {
                0 ... 19 => (ff(b, c, d), 0x5a827999),
                20 ... 39 => (gg(b, c, d), 0x6ed9eba1),
                40 ... 59 => (hh(b, c, d), 0x8f1bbcdc),
                60 ... 79 => (ii(b, c, d), 0xca62c1d6),
                _ => (0, 0),
            };

            let tmp = left_rotate(a, 5) + f + e + k + words[i];
            e = d;
            d = c;
            c = left_rotate(b, 30);
            b = a;
            a = tmp;
        }

        self.state[0] += a;
        self.state[1] += b;
        self.state[2] += c;
        self.state[3] += d;
        self.state[4] += e;
    }

    /// Retrieve digest result.  The output must be large enough to
    /// contain result (20 bytes).
    pub fn output(&self, out: &mut [u8]) {
        // these are unlikely to fail, since we're writing to memory
        #![allow(unused_must_use)]

        let mut m = Sha1 {
            state: self.state.clone(),
            data: Vec::new(),
            len: 0,
        };

        let mut w = Vec::<u8>::new();
        w.write(&*self.data);
        w.write_u8(0x80u8);
        let padding = 64 - ((self.data.len() + 9) % 64);
        for _ in range(0, padding) {
            w.write_u8(0u8);
        }
        w.write_be_u64((self.data.len() as u64 + self.len) * 8);
        for chunk in w[].chunks(64) {
            m.process_block(chunk);
        }

        let mut w = BufWriter::new(out);
        for &n in m.state.iter() {
            w.write_be_u32(n);
        }
    }

    pub fn hexdigest(&self) -> String {
        to_hex(&*self.finish())
    }
}

#[cfg(test)]
mod tests {
    use test::Bencher;
    use super::{Sha1, to_hex};
    use std::hash::{Writer, Hasher};

    #[test]
    fn test_simple() {
        let mut m = Sha1::new();

        let tests = [
            ("The quick brown fox jumps over the lazy dog",
            "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"),
            ("The quick brown fox jumps over the lazy cog",
            "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"),
            ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"),
            ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"),
            ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"),
        ];

        for &(s, ref h) in tests.iter() {
            let data = s.as_bytes();

            m.reset();
            m.write(data);
            let hh = m.hexdigest();

            assert_eq!(hh.len(), h.len());
            assert_eq!(&*hh, *h);
        }
    }

    #[test]
    fn test_dirty_run() {
        let mut m = Sha1::new();

        m.write(b"123");
        let out1 = m.finish();

        m.write(b"123");
        let out2 = m.finish();

        assert!(out1 != out2);
        assert_eq!(&*to_hex(&*out1), "40bd001563085fc35165329ea1ff5c5ecbdbbeef");
        assert_eq!(&*to_hex(&*out2), "601f1889667efaebb33b8c12572835da3f027f78");
    }

    #[bench]
    fn test_sha1_speed(b: &mut Bencher) {
        let mut m = Sha1::new();
        let s = "The quick brown fox jumps over the lazy dog.";
        let n = 1000u64;

        b.bytes = n * s.len() as u64;
        b.iter(|| {
            m.reset();
            for _ in range(0, n) {
                m.write(s.as_bytes());
            }
            assert_eq!(m.hexdigest(), "7ca27655f67fceaa78ed2e645a81c7f1d6e249d2");
        });
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate libc;
extern crate lru_cache;
extern crate wait_timeout;

use lru_cache::LruCache;

use std::error::Error;
use std::fmt;
use std::io::Write;
use std::io;
use std::process::{Command, ExitStatus, Stdio};
use std::str::FromStr;
use std::sync::Mutex;
use std::time::Duration;

use docker::Container;

mod docker;

pub const PLAYPEN_ENV_VAR_NAME: &'static str = "RUST_PLAYPEN_ENV";

/// Error type holding a description
pub struct StringError(pub String);

impl Error for StringError {
    fn description(&self) -> &str {
        &self.0
    }
}

impl fmt::Debug for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.0)
    }
}

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)]
pub enum ReleaseChannel {
    Stable = 0,
    Beta = 1,
    Nightly = 2,
}

impl FromStr for ReleaseChannel {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "stable" => Ok(ReleaseChannel::Stable),
            "beta" => Ok(ReleaseChannel::Beta),
            "nightly" => Ok(ReleaseChannel::Nightly),
            _ => Err(StringError(format!("unknown release channel {}", s))),
        }
    }
}

pub struct Cache {
    cache: Mutex<LruCache<CacheKey, (ExitStatus, Vec<u8>)>>,
}

#[derive(PartialEq, Eq, Hash)]
struct CacheKey {
    channel: ReleaseChannel,
    cmd: String,
    args: Vec<String>,
    env: Vec<(String, String)>,
    input: String,
}

impl Cache {
    pub fn new() -> Cache {
        Cache {
            cache: Mutex::new(LruCache::new(256)),
        }
    }

    /// Helper method for safely invoking a command inside a playpen
    pub fn exec(&self,
                channel: ReleaseChannel,
                cmd: &str,
                args: Vec<String>,
                env: Vec<(String, String)>,
                input: String)
                -> io::Result<(ExitStatus, Vec<u8>)> {
        // Build key to look up
        let key = CacheKey {
            channel: channel,
            cmd: cmd.to_string(),
            args: args,
            env: env,
            input: input,
        };
        let mut cache = self.cache.lock().unwrap();
        if let Some(prev) = cache.get_mut(&key) {
            return Ok(prev.clone())
        }
        drop(cache);

        let chan = match channel {
            ReleaseChannel::Stable => "stable",
            ReleaseChannel::Beta => "beta",
            ReleaseChannel::Nightly => "nightly",
        };
        let container = format!("rust-playpen-{}", chan);

        let container = try!(Container::new(cmd, &key.args, &key.env, &container));

        let tuple = try!(container.run(key.input.as_bytes(), Duration::new(5, 0)));
        let (status, mut output, timeout) = tuple;
        if timeout {
            output.extend_from_slice(b"\ntimeout triggered!");
        }
        let mut cache = self.cache.lock().unwrap();
        cache.insert(key, (status.clone(), output.clone()));
        Ok((status, output))
    }
}

pub enum AsmFlavor {
    Att,
    Intel,
}

impl AsmFlavor {
    pub fn as_str(&self) -> &'static str {
        match *self {
            AsmFlavor::Att => "att",
            AsmFlavor::Intel => "intel",
        }
    }
}

impl FromStr for AsmFlavor {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "att" => Ok(AsmFlavor::Att),
            "intel" => Ok(AsmFlavor::Intel),
            _ => Err(StringError(format!("unknown asm dialect {}", s))),
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum Backtrace {
    Never,
    Always,
    Auto,
}

impl Backtrace {
    pub fn is_requested(&self, debug: bool) -> bool {
        match *self {
            Backtrace::Never => false,
            Backtrace::Always => true,
            Backtrace::Auto => debug,
        }
    }
}

impl FromStr for Backtrace {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "0" => Ok(Backtrace::Never),
            "1" => Ok(Backtrace::Always),
            "2" => Ok(Backtrace::Auto),
            _ => Err(StringError(format!("unknown backtrace setting {}", s))),
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum OptLevel {
    O0,
    O1,
    O2,
    O3,
}

impl OptLevel {
    pub fn as_u8(&self) -> u8 {
        match *self {
            OptLevel::O0 => 0,
            OptLevel::O1 => 1,
            OptLevel::O2 => 2,
            OptLevel::O3 => 3,
        }
    }
}

impl FromStr for OptLevel {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "0" => Ok(OptLevel::O0),
            "1" => Ok(OptLevel::O1),
            "2" => Ok(OptLevel::O2),
            "3" => Ok(OptLevel::O3),
            _ => Err(StringError(format!("unknown optimization level {}", s))),
        }
    }
}

pub enum CompileOutput {
    Asm,
    Llvm,
    Mir,
}

impl CompileOutput {
    pub fn as_opts(&self) -> &'static [&'static str] {
        // We use statics here since the borrow checker complains if we put these directly in the
        // match. Pretty ugly, but rvalue promotion might fix this.
        static ASM: &'static [&'static str] = &["--emit=asm"];
        static LLVM: &'static [&'static str] = &["--emit=llvm-ir"];
        static MIR: &'static [&'static str] = &["-Zunstable-options", "--unpretty=mir"];
        match *self {
            CompileOutput::Asm => ASM,
            CompileOutput::Llvm => LLVM,
            CompileOutput::Mir => MIR,
        }
    }
}

impl FromStr for CompileOutput {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "asm" => Ok(CompileOutput::Asm),
            "llvm-ir" => Ok(CompileOutput::Llvm),
            "mir" => Ok(CompileOutput::Mir),
            _ => Err(StringError(format!("unknown output format {}", s))),
        }
    }
}

/// Highlights compiled rustc output according to the given output format
pub fn highlight(output_format: CompileOutput, output: &str) -> String {
    let lexer = match output_format {
        CompileOutput::Asm => "gas",
        CompileOutput::Llvm => "llvm",
        CompileOutput::Mir => "text",
    };

    let mut child = Command::new("pygmentize")
                            .arg("-l")
                            .arg(lexer)
                            .arg("-f")
                            .arg("html")
                            .stdin(Stdio::piped())
                            .stdout(Stdio::piped())
                            .spawn().unwrap();
    child.stdin.take().unwrap().write_all(output.as_bytes()).unwrap();
    let output = child.wait_with_output().unwrap();
    assert!(output.status.success());
    String::from_utf8(output.stdout).unwrap()
}

#[cfg(test)]
mod tests {
    extern crate env_logger;

    use super::*;

    /// Validate the version and return out with the first line (version) removed
    fn validate_and_remove_version<'a>(out: &'a [u8], expected: Option<&str>) -> &'a [u8] {
        let mut split = out.splitn(2, |&b| b == b'\n');
        let version = split.next().unwrap();
        let out = split.next().unwrap();

        assert!(version.starts_with(b"rustc "));

        if let Some(expectation) = expected {
            assert!(String::from_utf8_lossy(version).contains(expectation));
        }

        out
    }

    #[test]
    fn versions() {
        fn check(chan: ReleaseChannel, expectation: Option<&str>) {
            let cache = Cache::new();
            let input = r#"fn main() {}"#;

            let (status, out) = cache.exec(chan, "/usr/local/bin/evaluate.sh",
                                           vec![], vec![], input.into()).unwrap();

            assert!(status.success());
            validate_and_remove_version(&out.as_ref(), expectation);
        }

        drop(env_logger::init());

        check(ReleaseChannel::Stable, None);
        check(ReleaseChannel::Beta, Some("-beta"));
        check(ReleaseChannel::Nightly, Some("-nightly"));
    }

    #[test]
    fn eval() {
        drop(env_logger::init());

        let cache = Cache::new();
        let input = r#"fn main() { println!("Hello") }"#;
        let (status, out) = cache.exec(ReleaseChannel::Stable,
                                       "/usr/local/bin/evaluate.sh",
                                       Vec::new(),
                                       Vec::new(),
                                       input.to_string()).unwrap();
        assert!(status.success());
        let out = validate_and_remove_version(&out.as_ref(), None);
        assert_eq!(out, &[0xff, b'H', b'e', b'l', b'l', b'o', b'\n']);
    }

    #[test]
    fn timeout() {
        drop(env_logger::init());

        let cache = Cache::new();
        let input = r#"
            fn main() {
                std::thread::sleep_ms(10_000);
            }
        "#;
        let (status, out) = cache.exec(ReleaseChannel::Stable,
                                       "/usr/local/bin/evaluate.sh",
                                       Vec::new(),
                                       Vec::new(),
                                       input.to_string()).unwrap();
        assert!(!status.success());
        assert!(String::from_utf8_lossy(&out).contains("timeout triggered"));
    }

    #[test]
    fn compile() {
        drop(env_logger::init());

        let cache = Cache::new();
        let input = r#"fn main() { println!("Hello") }"#;
        let (status, out) = cache.exec(ReleaseChannel::Stable,
                                       "/usr/local/bin/compile.sh",
                                       vec![String::from("--emit=llvm-ir")],
                                       vec![],
                                       input.to_string()).unwrap();

        assert!(status.success());
        let out = validate_and_remove_version(&out, None);
        let mut split = out.splitn(2, |b| *b == b'\xff');
        let empty: &[u8] = &[];
        assert_eq!(split.next().unwrap(), empty);
        assert!(String::from_utf8(split.next().unwrap().to_vec()).unwrap()
            .contains("target triple"));
    }

    #[test]
    fn fmt() {
        drop(env_logger::init());

        let cache = Cache::new();
        let input = r#"fn main() { println!("Hello") }"#;
        let (status, out) = cache.exec(ReleaseChannel::Stable,
                                       "rustfmt",
                                       Vec::new(),
                                       Vec::new(),
                                       input.to_string()).unwrap();
        assert!(status.success());
        assert!(String::from_utf8(out).unwrap().contains(r#""Hello""#))
    }

    #[test]
    fn pygmentize() {
        drop(env_logger::init());

        assert!(highlight(CompileOutput::Llvm, "target triple").contains("<span"));
    }
}
<commit_msg>Only cache successful responses<commit_after>#[macro_use]
extern crate log;
extern crate libc;
extern crate lru_cache;
extern crate wait_timeout;

use lru_cache::LruCache;

use std::error::Error;
use std::fmt;
use std::io::Write;
use std::io;
use std::process::{Command, ExitStatus, Stdio};
use std::str::FromStr;
use std::sync::Mutex;
use std::time::Duration;

use docker::Container;

mod docker;

pub const PLAYPEN_ENV_VAR_NAME: &'static str = "RUST_PLAYPEN_ENV";

/// Error type holding a description
pub struct StringError(pub String);

impl Error for StringError {
    fn description(&self) -> &str {
        &self.0
    }
}

impl fmt::Debug for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.0)
    }
}

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)]
pub enum ReleaseChannel {
    Stable = 0,
    Beta = 1,
    Nightly = 2,
}

impl FromStr for ReleaseChannel {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "stable" => Ok(ReleaseChannel::Stable),
            "beta" => Ok(ReleaseChannel::Beta),
            "nightly" => Ok(ReleaseChannel::Nightly),
            _ => Err(StringError(format!("unknown release channel {}", s))),
        }
    }
}

pub struct Cache {
    cache: Mutex<LruCache<CacheKey, (ExitStatus, Vec<u8>)>>,
}

#[derive(PartialEq, Eq, Hash)]
struct CacheKey {
    channel: ReleaseChannel,
    cmd: String,
    args: Vec<String>,
    env: Vec<(String, String)>,
    input: String,
}

impl Cache {
    pub fn new() -> Cache {
        Cache {
            cache: Mutex::new(LruCache::new(256)),
        }
    }

    /// Helper method for safely invoking a command inside a playpen
    pub fn exec(&self,
                channel: ReleaseChannel,
                cmd: &str,
                args: Vec<String>,
                env: Vec<(String, String)>,
                input: String)
                -> io::Result<(ExitStatus, Vec<u8>)> {
        // Build key to look up
        let key = CacheKey {
            channel: channel,
            cmd: cmd.to_string(),
            args: args,
            env: env,
            input: input,
        };
        let mut cache = self.cache.lock().unwrap();
        if let Some(prev) = cache.get_mut(&key) {
            return Ok(prev.clone())
        }
        drop(cache);

        let chan = match channel {
            ReleaseChannel::Stable => "stable",
            ReleaseChannel::Beta => "beta",
            ReleaseChannel::Nightly => "nightly",
        };
        let container = format!("rust-playpen-{}", chan);

        let container = try!(Container::new(cmd, &key.args, &key.env, &container));

        let tuple = try!(container.run(key.input.as_bytes(), Duration::new(5, 0)));
        let (status, mut output, timeout) = tuple;
        if timeout {
            output.extend_from_slice(b"\ntimeout triggered!");
        }
        let mut cache = self.cache.lock().unwrap();
        if status.success() {
            cache.insert(key, (status.clone(), output.clone()));
        }
        Ok((status, output))
    }
}

pub enum AsmFlavor {
    Att,
    Intel,
}

impl AsmFlavor {
    pub fn as_str(&self) -> &'static str {
        match *self {
            AsmFlavor::Att => "att",
            AsmFlavor::Intel => "intel",
        }
    }
}

impl FromStr for AsmFlavor {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "att" => Ok(AsmFlavor::Att),
            "intel" => Ok(AsmFlavor::Intel),
            _ => Err(StringError(format!("unknown asm dialect {}", s))),
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum Backtrace {
    Never,
    Always,
    Auto,
}

impl Backtrace {
    pub fn is_requested(&self, debug: bool) -> bool {
        match *self {
            Backtrace::Never => false,
            Backtrace::Always => true,
            Backtrace::Auto => debug,
        }
    }
}

impl FromStr for Backtrace {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "0" => Ok(Backtrace::Never),
            "1" => Ok(Backtrace::Always),
            "2" => Ok(Backtrace::Auto),
            _ => Err(StringError(format!("unknown backtrace setting {}", s))),
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum OptLevel {
    O0,
    O1,
    O2,
    O3,
}

impl OptLevel {
    pub fn as_u8(&self) -> u8 {
        match *self {
            OptLevel::O0 => 0,
            OptLevel::O1 => 1,
            OptLevel::O2 => 2,
            OptLevel::O3 => 3,
        }
    }
}

impl FromStr for OptLevel {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "0" => Ok(OptLevel::O0),
            "1" => Ok(OptLevel::O1),
            "2" => Ok(OptLevel::O2),
            "3" => Ok(OptLevel::O3),
            _ => Err(StringError(format!("unknown optimization level {}", s))),
        }
    }
}

pub enum CompileOutput {
    Asm,
    Llvm,
    Mir,
}

impl CompileOutput {
    pub fn as_opts(&self) -> &'static [&'static str] {
        // We use statics here since the borrow checker complains if we put these directly in the
        // match. Pretty ugly, but rvalue promotion might fix this.
        static ASM: &'static [&'static str] = &["--emit=asm"];
        static LLVM: &'static [&'static str] = &["--emit=llvm-ir"];
        static MIR: &'static [&'static str] = &["-Zunstable-options", "--unpretty=mir"];
        match *self {
            CompileOutput::Asm => ASM,
            CompileOutput::Llvm => LLVM,
            CompileOutput::Mir => MIR,
        }
    }
}

impl FromStr for CompileOutput {
    type Err = StringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "asm" => Ok(CompileOutput::Asm),
            "llvm-ir" => Ok(CompileOutput::Llvm),
            "mir" => Ok(CompileOutput::Mir),
            _ => Err(StringError(format!("unknown output format {}", s))),
        }
    }
}

/// Highlights compiled rustc output according to the given output format
pub fn highlight(output_format: CompileOutput, output: &str) -> String {
    let lexer = match output_format {
        CompileOutput::Asm => "gas",
        CompileOutput::Llvm => "llvm",
        CompileOutput::Mir => "text",
    };

    let mut child = Command::new("pygmentize")
                            .arg("-l")
                            .arg(lexer)
                            .arg("-f")
                            .arg("html")
                            .stdin(Stdio::piped())
                            .stdout(Stdio::piped())
                            .spawn().unwrap();
    child.stdin.take().unwrap().write_all(output.as_bytes()).unwrap();
    let output = child.wait_with_output().unwrap();
    assert!(output.status.success());
    String::from_utf8(output.stdout).unwrap()
}

#[cfg(test)]
mod tests {
    extern crate env_logger;

    use super::*;

    /// Validate the version and return out with the first line (version) removed
    fn validate_and_remove_version<'a>(out: &'a [u8], expected: Option<&str>) -> &'a [u8] {
        let mut split = out.splitn(2, |&b| b == b'\n');
        let version = split.next().unwrap();
        let out = split.next().unwrap();

        assert!(version.starts_with(b"rustc "));

        if let Some(expectation) = expected {
            assert!(String::from_utf8_lossy(version).contains(expectation));
        }

        out
    }

    #[test]
    fn versions() {
        fn check(chan: ReleaseChannel, expectation: Option<&str>) {
            let cache = Cache::new();
            let input = r#"fn main() {}"#;

            let (status, out) = cache.exec(chan, "/usr/local/bin/evaluate.sh",
                                           vec![], vec![], input.into()).unwrap();

            assert!(status.success());
            validate_and_remove_version(&out.as_ref(), expectation);
        }

        drop(env_logger::init());

        check(ReleaseChannel::Stable, None);
        check(ReleaseChannel::Beta, Some("-beta"));
        check(ReleaseChannel::Nightly, Some("-nightly"));
    }

    #[test]
    fn eval() {
        drop(env_logger::init());

        let cache = Cache::new();
        let input = r#"fn main() { println!("Hello") }"#;
        let (status, out) = cache.exec(ReleaseChannel::Stable,
                                       "/usr/local/bin/evaluate.sh",
                                       Vec::new(),
                                       Vec::new(),
                                       input.to_string()).unwrap();
        assert!(status.success());
        let out = validate_and_remove_version(&out.as_ref(), None);
        assert_eq!(out, &[0xff, b'H', b'e', b'l', b'l', b'o', b'\n']);
    }

    #[test]
    fn timeout() {
        drop(env_logger::init());

        let cache = Cache::new();
        let input = r#"
            fn main() {
                std::thread::sleep_ms(10_000);
            }
        "#;
        let (status, out) = cache.exec(ReleaseChannel::Stable,
                                       "/usr/local/bin/evaluate.sh",
                                       Vec::new(),
                                       Vec::new(),
                                       input.to_string()).unwrap();
        assert!(!status.success());
        assert!(String::from_utf8_lossy(&out).contains("timeout triggered"));
    }

    #[test]
    fn compile() {
        drop(env_logger::init());

        let cache = Cache::new();
        let input = r#"fn main() { println!("Hello") }"#;
        let (status, out) = cache.exec(ReleaseChannel::Stable,
                                       "/usr/local/bin/compile.sh",
                                       vec![String::from("--emit=llvm-ir")],
                                       vec![],
                                       input.to_string()).unwrap();

        assert!(status.success());
        let out = validate_and_remove_version(&out, None);
        let mut split = out.splitn(2, |b| *b == b'\xff');
        let empty: &[u8] = &[];
        assert_eq!(split.next().unwrap(), empty);
        assert!(String::from_utf8(split.next().unwrap().to_vec()).unwrap()
            .contains("target triple"));
    }

    #[test]
    fn fmt() {
        drop(env_logger::init());

        let cache = Cache::new();
        let input = r#"fn main() { println!("Hello") }"#;
        let (status, out) = cache.exec(ReleaseChannel::Stable,
                                       "rustfmt",
                                       Vec::new(),
                                       Vec::new(),
                                       input.to_string()).unwrap();
        assert!(status.success());
        assert!(String::from_utf8(out).unwrap().contains(r#""Hello""#))
    }

    #[test]
    fn pygmentize() {
        drop(env_logger::init());

        assert!(highlight(CompileOutput::Llvm, "target triple").contains("<span"));
    }
}
<|endoftext|>