<commit_before>use rand;
use rand::Rng;
use std::collections::VecDeque;

pub enum Content {
    Number(u8),
    Bomb,
    None
}

struct Cell {
    index: u32,
    content: Content,
    revealed: bool
}

impl Cell {
    pub fn clear(&mut self) {
        self.content = Content::None;
        self.revealed = false;
    }

    fn reveal(&mut self) {
        self.revealed = true;
    }
}

pub struct Field {
    cells: Vec<Cell>,
    width: u32,
    height: u32,
    mines: u32,
    size: u32
}

impl Field {
    pub fn new(width: u32, height: u32, mines: u32) -> Field {
        let mut field = Field {
            width: width,
            height: height,
            cells: vec![],
            mines: mines,
            size: width*height
        };
        for i in 0..field.size {
            field.cells.push(Cell{index: i,
                           content: Content::None,
                           revealed: false});
        }
        field.fill();
        field
    }

    fn fill(&mut self) {
        self.clear();
        for _i in 0..self.mines {
            let ind = rand::thread_rng().gen_range(0, self.size);
            self.get_cell_mut(ind).content = Content::Bomb
        }
        let mut i: i32 = -1;
        let w = self.width as i32;
        while i < (self.size - 1) as i32 {
            i += 1;
            match self.get_content_safe(i) {
                Some(&Content::None) => {
                    let ct_bomb = |b| {
                        match b {
                            true => 1,
                            false => 0
                        }
                    };
                     // don`t care about row
                    let mut ct = ct_bomb(self.is_bomb_safe(i-w)) +
                                 ct_bomb(self.is_bomb_safe(i+w));
                    if i % w > 0 { // check left side position
                        ct += ct_bomb(self.is_bomb_safe(i-w-1)) +
                              ct_bomb(self.is_bomb_safe(i-1)) +
                              ct_bomb(self.is_bomb_safe(i+w-1));
                    }
                    if i % w < w - 1 { // check right side position
                        ct += ct_bomb(self.is_bomb_safe(i-w+1)) +
                              ct_bomb(self.is_bomb_safe(i+1)) +
                              ct_bomb(self.is_bomb_safe(i+w+1));
                    }
                    if ct > 0 {
                        self.get_cell_mut(i as u32).content = Content::Number(ct);
                    }
                },
                _ => {}
            }
        }
    }

    fn clear(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).clear();
        }
    }

    pub fn reveal(&mut self, i: u32) -> &Content {
        let cell = self.get_cell_mut(i);
        cell.reveal();
        &cell.content
    }

    pub fn revealed(&self, i: u32) -> bool {
        self.get_cell(i).revealed
    }

    fn get_cell_mut(&mut self, i:u32) -> &mut Cell {
        self.cells.get_mut(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell_mut ({})", i))
    }

    fn get_cell(& self, i:u32) -> &Cell {
        self.cells.get(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell ({})", i))
    }

    fn get_content_safe(&self, i:i32) -> Option<&Content> {
        if (i < 0) || ((i as u32) >= self.size) {
            None
        } else {
            Some(self.get_content(i as u32))
        }
    }

    pub fn get_content(& self, i: u32) -> &Content {
        &self.get_cell(i).content
    }

    fn is_bomb_safe(&self, i: i32) -> bool {
        match self.get_content_safe(i) {
            Some(&Content::Bomb) => true,
            _ => false
        }
    }

    pub fn get_width(&self) -> u32 {
        self.width
    }

    pub fn get_height(&self) -> u32 {
        self.height
    }

    pub fn restart(&mut self) {
        self.fill();
    }

    pub fn reveal_all(&mut self) {
      for i in 0..self.size {
            self.get_cell_mut(i).revealed = true;
        }
    }

    pub fn chain_reveal(&mut self, u: u32) {
        let mut deq = VecDeque::new();
        deq.push_back(u as i32);
        let w = self.width as i32;
        while !deq.is_empty() {
            let i = deq.pop_front().unwrap();
            let mut check = |x| {
                match self.get_content_safe(x) {
                    Some(&Content::None) => {
                        if !self.revealed(x as u32) {
                            deq.push_back(x);
                        }
                        self.reveal(x as u32);
                    },
                    Some(&Content::Number(_n)) => {
                        self.reveal(x as u32);
                    },
                    _ => {}
                }
            };
            // don`t care about row
            check(i-w);
            check(i+w);
            if i % w > 0 { // check left side position
                check(i-w-1);
                check(i-1);
                check(i+w-1);
            }
            if i % w < w - 1 { // check right side position
                check(i-w+1);
                check(i+1);
                check(i+w+1);
            }
        }
    }
}<commit_msg>wip: some code improvements<commit_after>use rand;
use rand::Rng;
use std::collections::VecDeque;

pub enum Content {
    Number(u8),
    Bomb,
    None
}

struct Cell {
    index: u32,
    content: Content,
    revealed: bool
}

impl Cell {
    pub fn clear(&mut self) {
        self.content = Content::None;
        self.revealed = false;
    }

    fn reveal(&mut self) {
        self.revealed = true;
    }
}

pub struct Field {
    cells: Vec<Cell>,
    width: u32,
    height: u32,
    mines: u32,
    size: u32
}

impl Field {
    pub fn new(width: u32, height: u32, mines: u32) -> Field {
        let mut field = Field {
            width: width,
            height: height,
            cells: vec![],
            mines: mines,
            size: width*height
        };
        for i in 0..field.size {
            field.cells.push(Cell{index: i,
                           content: Content::None,
                           revealed: false});
        }
        field.fill();
        field
    }

    fn fill(&mut self) {
        self.clear();
        for _i in 0..self.mines {
            let ind = rand::thread_rng().gen_range(0, self.size);
            self.get_cell_mut(ind).content = Content::Bomb
        }
        let mut i: i32 = -1;
        let w = self.width as i32;
        while i < (self.size - 1) as i32 {
            i += 1;
            match self.get_content_safe(i) {
                Some(&Content::None) => {
                    let ct_bomb = |b| {
                        match b {
                            true => 1,
                            false => 0
                        }
                    };
                     // don`t care about row
                    let mut ct = ct_bomb(self.is_bomb_safe(i-w)) +
                                 ct_bomb(self.is_bomb_safe(i+w));
                    if i % w > 0 { // check left side position
                        ct += ct_bomb(self.is_bomb_safe(i-w-1)) +
                              ct_bomb(self.is_bomb_safe(i-1)) +
                              ct_bomb(self.is_bomb_safe(i+w-1));
                    }
                    if i % w < w - 1 { // check right side position
                        ct += ct_bomb(self.is_bomb_safe(i-w+1)) +
                              ct_bomb(self.is_bomb_safe(i+1)) +
                              ct_bomb(self.is_bomb_safe(i+w+1));
                    }
                    if ct > 0 {
                        self.get_cell_mut(i as u32).content = Content::Number(ct);
                    }
                },
                _ => {}
            }
        }
    }

    fn clear(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).clear();
        }
    }

    pub fn reveal(&mut self, i: u32) -> &Content {
        let cell = self.get_cell_mut(i);
        cell.reveal();
        &cell.content
    }

    pub fn revealed(&self, i: u32) -> bool {
        self.get_cell(i).revealed
    }

    fn get_cell_mut(&mut self, i:u32) -> &mut Cell {
        self.cells.get_mut(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell_mut ({})", i))
    }

    fn get_cell(& self, i:u32) -> &Cell {
        self.cells.get(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell ({})", i))
    }

    fn get_content_safe(&self, i:i32) -> Option<&Content> {
        if (i < 0) || ((i as u32) >= self.size) {
            None
        } else {
            Some(self.get_content(i as u32))
        }
    }

    pub fn get_content(& self, i: u32) -> &Content {
        &self.get_cell(i).content
    }

    fn is_bomb_safe(&self, i: i32) -> bool {
        match self.get_content_safe(i) {
            Some(&Content::Bomb) => true,
            _ => false
        }
    }

    pub fn get_width(&self) -> u32 {
        self.width
    }

    pub fn get_height(&self) -> u32 {
        self.height
    }

    pub fn restart(&mut self) {
        self.fill();
    }

    pub fn reveal_all(&mut self) {
      for i in 0..self.size {
            self.get_cell_mut(i).revealed = true;
        }
    }

    pub fn chain_reveal(&mut self, u: u32) {
        let w = self.width as i32;
        // clojure to check for blank cells
        let mut check = |x, d: &mut VecDeque<i32>| {
            match self.get_content_safe(x) {
                Some(&Content::None) => {
                    if !self.revealed(x as u32) {
                        d.push_back(x);
                    }
                    self.reveal(x as u32);
                },
                Some(&Content::Number(_n)) => {
                    self.reveal(x as u32);
                },
                _ => {}
            }
        };
        // BFS initialize
        let deq = &mut VecDeque::new();
        deq.push_back(u as i32);
        // BFS
        while !deq.is_empty() {
            let i = deq.pop_front().unwrap();
            // don`t care about row
            check(i-w, deq);
            check(i+w, deq);
            if i % w > 0 { // check left side position
                check(i-w-1, deq);
                check(i-1, deq);
                check(i+w-1, deq);
            }
            if i % w < w - 1 { // check right side position
                check(i-w+1, deq);
                check(i+1, deq);
                check(i+w+1, deq);
            }
        }
    }
}<|endoftext|>


<commit_before>use std::fmt;
use std::error;
use std::fmt::Write;
use std::string::String;
use std::result;

#[derive(Debug, Clone, PartialEq)]
pub enum Alignment {
    Left,
    Center,
    Right, // default
    Equal,
}

pub type Result<T> = result::Result<T, FmtError>;

/// LOC-error
#[derive(Debug, PartialEq)]
pub enum FmtError {
    Invalid(String),  // format string is structued incorrectly
    KeyError(String), // key error in formatting string
    TypeError(String),     // invalid type used
}

impl fmt::Display for FmtError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &FmtError::Invalid(ref s) => write!(f, "Invalid({})", s),
            &FmtError::KeyError(ref s) => write!(f, "KeyError({})", s),
            &FmtError::TypeError(ref s) => write!(f, "TypeError({})", s),
        }
    }
}

impl error::Error for FmtError {
    fn description(&self) -> &str {
        match self {
            &FmtError::Invalid(_) => "invalid format string",
            &FmtError::KeyError(_) => "invalid key",
            &FmtError::TypeError(_) => "error during type resolution",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

enum Type {
    // integer types
    Bin,
    Char,
    Decimal,
    Octal,
    Hex,
    HexUpper,

    // both
    Number,

    // Floating point types
    Exponent,
    ExponentUpper,
    Fixed,
    General,
    GeneralUppercase,
    Percengage,

    // other types
    None,
    String,
    Debug,
}

<commit_msg>Formatter: all attrs are now private<commit_after>use std::fmt;
use std::error;
use std::fmt::Write;
use std::string::String;
use std::result;

#[derive(Debug, Clone, PartialEq)]
pub enum Alignment {
    Left,
    Center,
    Right, // default
    Equal,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Sign {
    Unspecified,
    Plus,
    Minus,
    Space,
}

pub type Result<T> = result::Result<T, FmtError>;

/// LOC-error
#[derive(Debug, PartialEq)]
pub enum FmtError {
    Invalid(String),  // format string is structued incorrectly
    KeyError(String), // key error in formatting string
    TypeError(String),     // invalid type used
}

impl fmt::Display for FmtError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &FmtError::Invalid(ref s) => write!(f, "Invalid({})", s),
            &FmtError::KeyError(ref s) => write!(f, "KeyError({})", s),
            &FmtError::TypeError(ref s) => write!(f, "TypeError({})", s),
        }
    }
}

impl error::Error for FmtError {
    fn description(&self) -> &str {
        match self {
            &FmtError::Invalid(_) => "invalid format string",
            &FmtError::KeyError(_) => "invalid key",
            &FmtError::TypeError(_) => "error during type resolution",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

enum Type {
    // integer types
    Bin,
    Char,
    Decimal,
    Octal,
    Hex,
    HexUpper,

    // both
    Number,

    // Floating point types
    Exponent,
    ExponentUpper,
    Fixed,
    General,
    GeneralUppercase,
    Percengage,

    // other types
    None,
    String,
    Debug,
}

<|endoftext|>


<commit_before>#![allow(non_snake_case)]

use std::fmt;
use std::mem;
use std::slice;
use num;
use approx;
use channel::{PosFreeChannel, FreeChannelScalar, AngularChannel, AngularChannelScalar,
              ChannelFormatCast, ChannelCast, ColorChannel};
use angle::{Deg, Angle, FromAngle, IntoAngle, Turns, Rad};
use angle;
use color::{Color, PolarColor, FromTuple, Lerp, Bounded, Flatten};
use convert::{GetHue, GetChroma};

pub struct LchuvTag;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Lchuv<T, A = Deg<T>> {
    pub L: PosFreeChannel<T>,
    pub chroma: PosFreeChannel<T>,
    pub hue: AngularChannel<A>,
}

impl<T, A> Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    pub fn from_channels(L: T, chroma: T, hue: A) -> Self {
        Lchuv {
            L: PosFreeChannel::new(L),
            chroma: PosFreeChannel::new(chroma),
            hue: AngularChannel::new(hue),
        }
    }

    impl_color_color_cast_angular!(Lchuv {L, chroma, hue},
        chan_traits={FreeChannelScalar});

    pub fn L(&self) -> T {
        self.L.0.clone()
    }
    pub fn chroma(&self) -> T {
        self.chroma.0.clone()
    }
    pub fn hue(&self) -> A {
        self.hue.0.clone()
    }
    pub fn L_mut(&mut self) -> &mut T {
        &mut self.L.0
    }
    pub fn chroma_mut(&mut self) -> &mut T {
        &mut self.chroma.0
    }
    pub fn hue_mut(&mut self) -> &mut A {
        &mut self.hue.0
    }
    pub fn set_L(&mut self, val: T) {
        self.L.0 = val;
    }
    pub fn set_chroma(&mut self, val: T) {
        self.chroma.0 = val;
    }
    pub fn set_hue(&mut self, val: A) {
        self.hue.0 = val;
    }
}

impl<T, A> Color for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    type Tag = LchuvTag;
    type ChannelsTuple = (T, T, A);

    fn num_channels() -> u32 {
        3
    }
    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.L.0, self.chroma.0, self.hue.0)
    }
}

impl<T, A> PolarColor for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    type Angular = A;
    type Cartesian = T;
}

impl<T, A> FromTuple for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        Lchuv::from_channels(values.0, values.1, values.2)
    }
}

impl<T, A> Lerp for Lchuv<T, A>
    where T: FreeChannelScalar + Lerp,
          A: AngularChannelScalar + Lerp
{
    type Position = A::Position;

    impl_color_lerp_angular!(Lchuv<T> {hue, L, chroma});
}

impl<T, A> Bounded for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    impl_color_bounded!(Lchuv {L, chroma, hue});
}

impl<T, A> Flatten for Lchuv<T, A>
    where T: FreeChannelScalar + num::Float,
          A: AngularChannelScalar + Angle<Scalar = T> + FromAngle<Turns<T>>
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);

    fn from_slice(vals: &[T]) -> Self {
        Lchuv::from_channels(vals[0].clone(),
                             vals[1].clone(),
                             A::from_angle(angle::Turns(vals[2].clone())))
    }
}

impl<T, A> approx::ApproxEq for Lchuv<T, A>
    where T: FreeChannelScalar + approx::ApproxEq<Epsilon = A::Epsilon>,
          A: AngularChannelScalar + approx::ApproxEq,
          A::Epsilon: Clone + num::Float
{
    impl_approx_eq!({L, chroma, hue});
}

impl<T, A> Default for Lchuv<T, A>
    where T: FreeChannelScalar + num::Zero,
          A: AngularChannelScalar + num::Zero
{
    impl_color_default!(Lchuv {hue: AngularChannel,
        L: PosFreeChannel, chroma: PosFreeChannel});
}

impl<T, A> fmt::Display for Lchuv<T, A>
    where T: FreeChannelScalar + fmt::Display,
          A: AngularChannelScalar + fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Lch(uv)({}, {}, {})", self.L, self.chroma, self.hue)
    }
}

impl<T, A> GetChroma for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    type ChromaType = T;
    fn get_chroma(&self) -> T {
        return self.chroma();
    }
}

impl<T, A> GetHue for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    impl_color_get_hue_angular!(Lchuv);
}
<commit_msg>Implemented Lch(uv) -> Luv and back.<commit_after>#![allow(non_snake_case)]

use std::fmt;
use std::mem;
use std::slice;
use num;
use approx;
use channel::{PosFreeChannel, FreeChannelScalar, AngularChannel, AngularChannelScalar,
              ChannelFormatCast, ChannelCast, ColorChannel};
use angle::{Deg, Angle, FromAngle, IntoAngle, Turns, Rad};
use angle;
use color::{Color, PolarColor, FromTuple, Lerp, Bounded, Flatten};
use convert::{GetHue, GetChroma, FromColor};
use luv::Luv;

pub struct LchuvTag;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Lchuv<T, A = Deg<T>> {
    pub L: PosFreeChannel<T>,
    pub chroma: PosFreeChannel<T>,
    pub hue: AngularChannel<A>,
}

impl<T, A> Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    pub fn from_channels(L: T, chroma: T, hue: A) -> Self {
        Lchuv {
            L: PosFreeChannel::new(L),
            chroma: PosFreeChannel::new(chroma),
            hue: AngularChannel::new(hue),
        }
    }

    impl_color_color_cast_angular!(Lchuv {L, chroma, hue},
        chan_traits={FreeChannelScalar});

    pub fn L(&self) -> T {
        self.L.0.clone()
    }
    pub fn chroma(&self) -> T {
        self.chroma.0.clone()
    }
    pub fn hue(&self) -> A {
        self.hue.0.clone()
    }
    pub fn L_mut(&mut self) -> &mut T {
        &mut self.L.0
    }
    pub fn chroma_mut(&mut self) -> &mut T {
        &mut self.chroma.0
    }
    pub fn hue_mut(&mut self) -> &mut A {
        &mut self.hue.0
    }
    pub fn set_L(&mut self, val: T) {
        self.L.0 = val;
    }
    pub fn set_chroma(&mut self, val: T) {
        self.chroma.0 = val;
    }
    pub fn set_hue(&mut self, val: A) {
        self.hue.0 = val;
    }
}

impl<T, A> Color for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    type Tag = LchuvTag;
    type ChannelsTuple = (T, T, A);

    fn num_channels() -> u32 {
        3
    }
    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.L.0, self.chroma.0, self.hue.0)
    }
}

impl<T, A> PolarColor for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    type Angular = A;
    type Cartesian = T;
}

impl<T, A> FromTuple for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        Lchuv::from_channels(values.0, values.1, values.2)
    }
}

impl<T, A> Lerp for Lchuv<T, A>
    where T: FreeChannelScalar + Lerp,
          A: AngularChannelScalar + Lerp
{
    type Position = A::Position;

    impl_color_lerp_angular!(Lchuv<T> {hue, L, chroma});
}

impl<T, A> Bounded for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    impl_color_bounded!(Lchuv {L, chroma, hue});
}

impl<T, A> Flatten for Lchuv<T, A>
    where T: FreeChannelScalar + num::Float,
          A: AngularChannelScalar + Angle<Scalar = T> + FromAngle<Turns<T>>
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);

    fn from_slice(vals: &[T]) -> Self {
        Lchuv::from_channels(vals[0].clone(),
                             vals[1].clone(),
                             A::from_angle(angle::Turns(vals[2].clone())))
    }
}

impl<T, A> approx::ApproxEq for Lchuv<T, A>
    where T: FreeChannelScalar + approx::ApproxEq<Epsilon = A::Epsilon>,
          A: AngularChannelScalar + approx::ApproxEq,
          A::Epsilon: Clone + num::Float
{
    impl_approx_eq!({L, chroma, hue});
}

impl<T, A> Default for Lchuv<T, A>
    where T: FreeChannelScalar + num::Zero,
          A: AngularChannelScalar + num::Zero
{
    impl_color_default!(Lchuv {hue: AngularChannel,
        L: PosFreeChannel, chroma: PosFreeChannel});
}

impl<T, A> fmt::Display for Lchuv<T, A>
    where T: FreeChannelScalar + fmt::Display,
          A: AngularChannelScalar + fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Lch(uv)({}, {}, {})", self.L, self.chroma, self.hue)
    }
}

impl<T, A> GetChroma for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    type ChromaType = T;
    fn get_chroma(&self) -> T {
        return self.chroma();
    }
}

impl<T, A> GetHue for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar
{
    impl_color_get_hue_angular!(Lchuv);
}

impl<T, A> FromColor<Luv<T>> for Lchuv<T, A>
    where T: FreeChannelScalar,
          A: AngularChannelScalar + FromAngle<Rad<T>> + Angle
{
    fn from_color(from: &Luv<T>) -> Self {
        let L = from.L();
        let c = (from.u() * from.u() + from.v() * from.v()).sqrt();
        let h = A::from_angle(Rad::atan2(from.v(), from.u()));

        Lchuv::from_channels(L, c, <A as Angle>::normalize(h))
    }
}

impl<T, A> FromColor<Lchuv<T, A>> for Luv<T>
    where T: FreeChannelScalar,
          A: AngularChannelScalar + Angle<Scalar = T>
{
    fn from_color(from: &Lchuv<T, A>) -> Self {
        let L = from.L();
        let u = from.chroma() * from.hue().cos();
        let v = from.chroma() * from.hue().sin();

        Luv::from_channels(L, u, v)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use luv::Luv;
    use angle::*;
    use convert::*;

    #[test]
    fn test_from_luv() {
        let c1 = Luv::from_channels(60.0, 30.0, -30.0);
        let t1 = Lchuv::from_color(&c1);
        assert_relative_eq!(t1, Lchuv::from_channels(60.0, 42.4264, Deg(315.0)), epsilon=1e-4);
        assert_relative_eq!(Luv::from_color(&t1), c1, epsilon=1e-4);

        let c2 = Luv::from_channels(75.0, 0.0, 100.0);
        let t2 = Lchuv::from_color(&c2);
        assert_relative_eq!(t2, Lchuv::from_channels(75.0, 100.0, Deg(90.0)), epsilon=1e-4);
        assert_relative_eq!(Luv::from_color(&t2), c2, epsilon=1e-4);

        let c3 = Luv::from_channels(50.0, -45.0, -30.0);
        let t3 = Lchuv::from_color(&c3);
        assert_relative_eq!(t3, Lchuv::from_channels(50.0, 54.0833, Deg(213.6901)), epsilon=1e-4);
        assert_relative_eq!(Luv::from_color(&t3), c3, epsilon=1e-4);

        let c4 = Luv::from_channels(0.0, 0.0, 0.0);
        let t4 = Lchuv::from_color(&c4);
        assert_relative_eq!(t4, Lchuv::from_channels(0.0, 0.0, Rad(0.0)), epsilon=1e-4);
        assert_relative_eq!(Luv::from_color(&t4), c4, epsilon=1e-4);

        let c5 = Luv::from_channels(72.0, -100.0, -100.0);
        let t5 = Lchuv::from_color(&c5);
        assert_relative_eq!(t5, Lchuv::from_channels(72.0, 141.4214, Deg(225.0)), epsilon=1e-4);
        assert_relative_eq!(Luv::from_color(&t5), c5, epsilon=1e-4);

        let c6 = Luv::from_channels(88.0, 0.0, 0.0);
        let t6 = Lchuv::from_color(&c6);
        assert_relative_eq!(t6, Lchuv::from_channels(88.0, 0.0, Deg(0.0)), epsilon=1e-6);
        assert_relative_eq!(Luv::from_color(&t6), c6, epsilon=1e-4);
    }

    #[test]
    fn test_to_luv() {
        let c1 = Lchuv::from_channels(50.0, 70.0, Turns(0.5));
        let t1 = Luv::from_color(&c1);
        assert_relative_eq!(t1, Luv::from_channels(50.0, -70.0, 0.0), epsilon=1e-4);
        assert_relative_eq!(Lchuv::from_color(&t1), c1, epsilon=1e-4);

        let c2 = Lchuv::from_channels(66.0, 75.0, Deg(35.35335335));
        let t2 = Luv::from_color(&c2);
        assert_relative_eq!(t2, Luv::from_channels(66.0, 61.1699, 43.3963), epsilon=1e-4);
        assert_relative_eq!(Lchuv::from_color(&t2), c2, epsilon=1e-4);

        let c3 = Lchuv::from_channels(100.0, 100.0, Deg(155.0));
        let t3 = Luv::from_color(&c3);
        assert_relative_eq!(t3, Luv::from_channels(100.0, -90.6308, 42.2618), epsilon=1e-4);
        assert_relative_eq!(Lchuv::from_color(&t3), c3, epsilon=1e-4);

        let c4 = Lchuv::from_channels(23.0, 70.0, Deg(222.0));
        let t4 = Luv::from_color(&c4);
        assert_relative_eq!(t4, Luv::from_channels(23.0, -52.0201, -46.8391), epsilon=1e-4);
        assert_relative_eq!(Lchuv::from_color(&t4), c4, epsilon=1e-4);
    }
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use syntax::ast::*;
use syntax::visit::{Visitor, walk_expr};
use std::collections::HashSet;

use utils::{snippet, span_lint, get_parent_expr};

declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn,
               "for-looping over a range of indices where an iterator over items would do" }

declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn,
               "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" }

#[derive(Copy, Clone)]
pub struct LoopsPass;

impl LintPass for LoopsPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let Some((pat, arg, body)) = recover_for_loop(expr) {
            // check for looping over a range and then indexing a sequence with it
            // -> the iteratee must be a range literal
            if let ExprRange(_, _) = arg.node {
                // the var must be a single name
                if let PatIdent(_, ref ident, _) = pat.node {
                    let mut visitor = VarVisitor { cx: cx, var: ident.node.name,
                                                   indexed: HashSet::new(), nonindex: false };
                    walk_expr(&mut visitor, body);
                    // linting condition: we only indexed one variable
                    if visitor.indexed.len() == 1 {
                        let indexed = visitor.indexed.into_iter().next().expect("Len was nonzero, but no contents found");
                        if visitor.nonindex {
                            span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!(
                                "the loop variable `{}` is used to index `{}`. Consider using \
                                 `for ({}, item) in {}.iter().enumerate()` or similar iterators.",
                                ident.node.name, indexed, ident.node.name, indexed));
                        } else {
                            span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!(
                                "the loop variable `{}` is only used to index `{}`. \
                                 Consider using `for item in &{}` or similar iterators.",
                                ident.node.name, indexed, indexed));
                        }
                    }
                }
            }

            // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
            if let ExprMethodCall(ref method, _, ref args) = arg.node {
                // just the receiver, no arguments to iter() or iter_mut()
                if args.len() == 1 {
                    let method_name = method.node.name;
                    if method_name == "iter" {
                        let object = snippet(cx, args[0].span, "_");
                        span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!(
                            "it is more idiomatic to loop over `&{}` instead of `{}.iter()`",
                            object, object));
                    } else if method_name == "iter_mut" {
                        let object = snippet(cx, args[0].span, "_");
                        span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!(
                            "it is more idiomatic to loop over `&mut {}` instead of `{}.iter_mut()`",
                            object, object));
                    }
                }
            }
        }
    }
}

/// Recover the essential nodes of a desugared for loop:
/// `for pat in arg { body }` becomes `(pat, arg, body)`.
fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> {
    if_let_chain! {
        [
            let ExprMatch(ref iterexpr, ref arms, _) = expr.node,
            let ExprCall(_, ref iterargs) = iterexpr.node,
            iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(),
            let ExprLoop(ref block, _) = arms[0].body.node,
            block.stmts.is_empty(),
            let Some(ref loopexpr) = block.expr,
            let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node,
            innerarms.len() == 2 && innerarms[0].pats.len() == 1,
            let PatEnum(_, Some(ref somepats)) = innerarms[0].pats[0].node,
            somepats.len() == 1
        ], {
            return Some((&*somepats[0],
                         &*iterargs[0],
                         &*innerarms[0].body));
        }
    }
    None
}

struct VarVisitor<'v, 't: 'v> {
    cx: &'v Context<'v, 't>, // context reference
    var: Name,               // var name to look for as index
    indexed: HashSet<Name>,  // indexed variables
    nonindex: bool,          // has the var been used otherwise?
}

impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> {
    fn visit_expr(&mut self, expr: &'v Expr) {
        if let ExprPath(None, ref path) = expr.node {
            if path.segments.len() == 1 && path.segments[0].identifier.name == self.var {
                // we are referencing our variable! now check if it's as an index
                if_let_chain! {
                    [
                        let Some(parexpr) = get_parent_expr(self.cx, expr),
                        let ExprIndex(ref seqexpr, _) = parexpr.node,
                        let ExprPath(None, ref seqvar) = seqexpr.node,
                        seqvar.segments.len() == 1
                    ], {
                        self.indexed.insert(seqvar.segments[0].identifier.name);
                        return;  // no need to walk further
                    }
                }
                // we are not indexing anything, record that
                self.nonindex = true;
                return;
            }
        }
        walk_expr(self, expr);
    }
}
<commit_msg>loops: fix two trailing periods in lint msgs<commit_after>use rustc::lint::*;
use syntax::ast::*;
use syntax::visit::{Visitor, walk_expr};
use std::collections::HashSet;

use utils::{snippet, span_lint, get_parent_expr};

declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn,
               "for-looping over a range of indices where an iterator over items would do" }

declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn,
               "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" }

#[derive(Copy, Clone)]
pub struct LoopsPass;

impl LintPass for LoopsPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let Some((pat, arg, body)) = recover_for_loop(expr) {
            // check for looping over a range and then indexing a sequence with it
            // -> the iteratee must be a range literal
            if let ExprRange(_, _) = arg.node {
                // the var must be a single name
                if let PatIdent(_, ref ident, _) = pat.node {
                    let mut visitor = VarVisitor { cx: cx, var: ident.node.name,
                                                   indexed: HashSet::new(), nonindex: false };
                    walk_expr(&mut visitor, body);
                    // linting condition: we only indexed one variable
                    if visitor.indexed.len() == 1 {
                        let indexed = visitor.indexed.into_iter().next().expect("Len was nonzero, but no contents found");
                        if visitor.nonindex {
                            span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!(
                                "the loop variable `{}` is used to index `{}`. Consider using \
                                 `for ({}, item) in {}.iter().enumerate()` or similar iterators",
                                ident.node.name, indexed, ident.node.name, indexed));
                        } else {
                            span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!(
                                "the loop variable `{}` is only used to index `{}`. \
                                 Consider using `for item in &{}` or similar iterators",
                                ident.node.name, indexed, indexed));
                        }
                    }
                }
            }

            // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
            if let ExprMethodCall(ref method, _, ref args) = arg.node {
                // just the receiver, no arguments to iter() or iter_mut()
                if args.len() == 1 {
                    let method_name = method.node.name;
                    if method_name == "iter" {
                        let object = snippet(cx, args[0].span, "_");
                        span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!(
                            "it is more idiomatic to loop over `&{}` instead of `{}.iter()`",
                            object, object));
                    } else if method_name == "iter_mut" {
                        let object = snippet(cx, args[0].span, "_");
                        span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!(
                            "it is more idiomatic to loop over `&mut {}` instead of `{}.iter_mut()`",
                            object, object));
                    }
                }
            }
        }
    }
}

/// Recover the essential nodes of a desugared for loop:
/// `for pat in arg { body }` becomes `(pat, arg, body)`.
fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> {
    if_let_chain! {
        [
            let ExprMatch(ref iterexpr, ref arms, _) = expr.node,
            let ExprCall(_, ref iterargs) = iterexpr.node,
            iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(),
            let ExprLoop(ref block, _) = arms[0].body.node,
            block.stmts.is_empty(),
            let Some(ref loopexpr) = block.expr,
            let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node,
            innerarms.len() == 2 && innerarms[0].pats.len() == 1,
            let PatEnum(_, Some(ref somepats)) = innerarms[0].pats[0].node,
            somepats.len() == 1
        ], {
            return Some((&*somepats[0],
                         &*iterargs[0],
                         &*innerarms[0].body));
        }
    }
    None
}

struct VarVisitor<'v, 't: 'v> {
    cx: &'v Context<'v, 't>, // context reference
    var: Name,               // var name to look for as index
    indexed: HashSet<Name>,  // indexed variables
    nonindex: bool,          // has the var been used otherwise?
}

impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> {
    fn visit_expr(&mut self, expr: &'v Expr) {
        if let ExprPath(None, ref path) = expr.node {
            if path.segments.len() == 1 && path.segments[0].identifier.name == self.var {
                // we are referencing our variable! now check if it's as an index
                if_let_chain! {
                    [
                        let Some(parexpr) = get_parent_expr(self.cx, expr),
                        let ExprIndex(ref seqexpr, _) = parexpr.node,
                        let ExprPath(None, ref seqvar) = seqexpr.node,
                        seqvar.segments.len() == 1
                    ], {
                        self.indexed.insert(seqvar.segments[0].identifier.name);
                        return;  // no need to walk further
                    }
                }
                // we are not indexing anything, record that
                self.nonindex = true;
                return;
            }
        }
        walk_expr(self, expr);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Martin Grabmueller. See the LICENSE file at the
// top-level directory of this distribution for license information.

//! Simple implementation of an LZ4-like compressor.

use std::io::{Read, Write};
use std::collections::HashMap;

use error::Error;

const INDEX_BIT_COUNT: usize = 12;
const LENGTH_BIT_COUNT: usize = 8;
const WINDOW_SIZE: usize = 1 << INDEX_BIT_COUNT;
const RAW_LOOK_AHEAD_SIZE: usize = 1 << LENGTH_BIT_COUNT;
const BREAK_EVEN: usize = (1 + INDEX_BIT_COUNT + LENGTH_BIT_COUNT) / 9;
const LOOK_AHEAD_SIZE: usize = RAW_LOOK_AHEAD_SIZE + BREAK_EVEN;

pub struct Compressor<R, W> {
    input: R,
    output: W,
    hash_table: HashMap<u32, usize>,
    window: [u8; WINDOW_SIZE],
    hashes: [u32; WINDOW_SIZE],
    next: [Option<usize>; WINDOW_SIZE],
    literals: Vec<u8>,
    lookups: usize,
    lin_lookups: usize,
}

impl<R, W> Compressor<R, W> {
    pub fn new(r: R, w: W) -> Compressor<R, W> {
        Compressor {
            input: r,
            output: w,
            hash_table: HashMap::new(),
            window: [0; WINDOW_SIZE],
            hashes: [0; WINDOW_SIZE],
            next: [None; WINDOW_SIZE],
            literals: Vec::new(),
            lookups: 0,
            lin_lookups: 0,
        }
    }

    pub fn finish(self) -> W {
//        println!("lookups: {}", self.lookups);
//        println!("lin_lookups: {}", self.lin_lookups);
        self.output
    }
}

impl<R: Read, W: Write> Compressor<R, W> {
    fn hash_at(&self, p: usize) -> u32 {
        ((self.window[self.mod_window(p)] as u32) << 24) +
            ((self.window[self.mod_window(p + 1)] as u32) << 16) +
            ((self.window[self.mod_window(p + 2)] as u32) << 8) +
            (self.window[self.mod_window(p + 3)] as u32)
    }

    fn getc(&mut self) -> Result<Option<u8>, Error> {
        let mut buf = [0u8; 1];
        let n = try!(self.input.read(&mut buf[..]));
        if n == 1 {
            Ok(Some(buf[0]))
        } else {
            Ok(None)
        }
    }

    fn delete_string(&mut self, pos: usize) {
        let hsh = self.hashes[pos];
        self.hash_table.remove(&hsh);
        if let Some(next_pos) = self.next[pos] {
            self.hash_table.insert(self.hashes[next_pos], next_pos);
        }
        self.hashes[pos] = 0;
        self.next[pos] = None;
    }

    fn get_longest_match(&mut self, hsh: u32, current_pos: usize,
                         look_ahead_bytes: usize) -> Option<(usize, usize)> {
        self.lookups += 1;
        let res =
            if let Some(hpos) = self.hash_table.get(&hsh) {
                let mut max_pos = *hpos;
                let mut max_len = 4;
                let mut pos = max_pos;
                let mut iterations = 0;
                loop {
                    let mut len = 0;
                    for i in 0..look_ahead_bytes {
                        if self.window[self.mod_window(max_pos + i)] == self.window[self.mod_window(current_pos + i)] {
                            len += 1;
                        } else {
                            break;
                        }
                    }
                    if len > max_len {
                        max_len = len;
                        max_pos = pos;
                    }
                    if let Some(npos) = self.next[pos] {
                        pos = npos;
                        self.lin_lookups += 1;
                    } else {
                        break;
                    }
                    iterations += 1;
                    if iterations > 20 {
                        break;
                    }
                }
                Some((max_pos, max_len))
            } else {
                None
            };
        if let Some((p, _)) = res {
            self.hash_table.insert(hsh, current_pos);
            self.hashes[current_pos] = hsh;
            self.next[current_pos] = Some(p);
        } else {
            self.hash_table.insert(hsh, current_pos);
            self.hashes[current_pos] = hsh;
            self.next[current_pos] = None;
        }
        res
    }

    fn add_string(&mut self, pos: usize, look_ahead_bytes: usize,
                  match_pos: &mut usize) -> usize {
        if look_ahead_bytes < 4 {
            *match_pos = 0;
            0
        } else {
            let hsh = self.hash_at(pos);
            if let Some((hpos, hlen)) = self.get_longest_match(hsh, pos, look_ahead_bytes) {
                *match_pos = hpos;
                hlen
            } else {
                *match_pos = 0;
                0
            }
        }
    }

    fn mod_window(&self, p: usize) -> usize {
        p % WINDOW_SIZE
    }

    pub fn process(&mut self) -> Result<(), Error> {
        let mut current_position = 0;
        let mut look_ahead_bytes =
            try!(self.input.read(&mut self.window[..LOOK_AHEAD_SIZE]));

        let mut match_length = 0;
        let mut match_position = 0;
        let mut replace_count;
        let _ = self.add_string(current_position, look_ahead_bytes,
                                &mut match_position);
        while look_ahead_bytes > 0 {
            if match_length > look_ahead_bytes {
                match_length = look_ahead_bytes;
            }
            if match_length <= BREAK_EVEN {

                self.literals.push(self.window[current_position]);
                replace_count = 1;

            } else {
                try!(self.emit(match_position, match_length));

                replace_count = match_length;
            }
            for _ in 0..replace_count {

                let cp = self.mod_window(current_position + LOOK_AHEAD_SIZE);
                self.delete_string(cp);

                if let Some(c) = try!(self.getc()) {
                    self.window[self.mod_window(current_position + LOOK_AHEAD_SIZE)] = c;
                } else {
                    look_ahead_bytes -= 1;
                }
                current_position = self.mod_window(current_position + 1);
                if look_ahead_bytes > 0 {
                    match_length = self.add_string(current_position, look_ahead_bytes,
                                                   &mut match_position);
                }
            }
        }

        if self.literals.len() > 0 {
            try!(self.emit(0, 0));
        }

        Ok(())
    }

    fn emit(&mut self, match_pos: usize, match_len: usize) -> Result<(), Error> {
        let (lit_tok, lit_extra) =
            if self.literals.len() > 14 {
                (15u8, Some(self.literals.len()))
            } else {
                (self.literals.len() as u8, None)
            };
        let (match_tok, match_extra) =
            if match_len > 14 {
                (15u8, Some(match_len))
            } else {
                (match_len as u8, None)
            };
        let token = (lit_tok << 4) | match_tok;
        try!(self.output.write(&[token]));
        if let Some(mut le) = lit_extra {
            while le >= 255 {
                try!(self.output.write(&[255]));
                le -= 255;
            }
            try!(self.output.write(&[le as u8]));
        }
        if self.literals.len() > 0 {
            try!(self.output.write(&self.literals));
            self.literals.truncate(0);
        }
        if let Some(mut me) = match_extra {
            while me >= 255 {
                try!(self.output.write(&[255]));
                me -= 255;
            }
            try!(self.output.write(&[me as u8]));
        }
        if match_len > 0 {
            let mut mp = match_pos;
            while mp >= 255 {
                try!(self.output.write(&[255]));
                mp -= 255;
            }
            try!(self.output.write(&[mp as u8]));
        }
        Ok(())
    }
}

pub struct Decompressor<R, W> {
    input: R,
    output: W,
    window: [u8; WINDOW_SIZE],
}

impl<R, W> Decompressor<R, W> {
    pub fn new(r: R, w: W) -> Decompressor<R, W> {
        Decompressor {
            input: r,
            output: w,
            window: [0; WINDOW_SIZE],
        }
    }

    pub fn finish(self) -> W {
        self.output
    }
}

impl<R: Read, W: Write> Decompressor<R, W> {
    fn getc(&mut self) -> Result<Option<u8>, Error> {
        let mut buf = [0u8; 1];
        let n = try!(self.input.read(&mut buf[..]));
        if n == 1 {
            Ok(Some(buf[0]))
        } else {
            Ok(None)
        }
    }

    fn mod_window(&self, p: usize) -> usize {
        p % WINDOW_SIZE
    }

    fn get_len(&mut self) -> Result<(usize, usize), Error> {
        let mut llen = 0;
        let mut l: usize = 0;
        if let Some(mut c) = try!(self.getc()) {
            llen += 1;
            while c == 255 {
                l += 255;
                if let Some(cc) = try!(self.getc()) {
                    llen += 1;
                    c = cc;
                } else {
                    return Err(Error::UnexpectedEof);
                }
            }
            l += c as usize;
        }
        Ok((l, llen))
    }

    pub fn process(&mut self) -> Result<(), Error> {
        let mut current_position = 0;
        loop {
            if let Some(token) = try!(self.getc()) {
                let lit_tok = token >> 4;
                let match_tok = token & 0x0f;
                let (lit_len, extra_lit_len) =
                    if lit_tok == 15 {
                        try!(self.get_len())
                    } else {
                        (lit_tok as usize, 0)
                    };
                let mut lit: Vec<u8> = Vec::new();
                let mut mtch: Vec<u8> = Vec::new();
                for _ in 0..lit_len {
                    if let Some(c) = try!(self.getc()) {
                        self.window[current_position] = c;
                        try!(self.output.write(&[c]));
                        current_position = self.mod_window(current_position + 1);
                        lit.push(c);
                    } else {
                        return Err(Error::UnexpectedEof);
                    }
                }
                let (match_len, extra_match_len) =
                    if match_tok == 15 {
                        try!(self.get_len())

                    } else {
                        (match_tok as usize, 0)
                    };
                let (match_pos, match_pos_len) = try!(self.get_len());
//                println!("literal length: {}, match length: {}, match pos: {}",
//                         lit_len, match_len, match_pos);
                for i in 0..match_len {
                    let c = self.window[self.mod_window(match_pos + i)];
                    self.window[current_position] = c;
                    try!(self.output.write(&[c]));
                    current_position = self.mod_window(current_position + 1);
                    mtch.push(c);
                }
                let enc_len = 1 + extra_lit_len + lit_len + extra_match_len + match_pos_len;
                let dec_len = lit_len + match_len;
                println!("{:?} {:?}; {} -> {}", String::from_utf8_lossy(&lit), String::from_utf8_lossy(&mtch), enc_len, dec_len);
            } else {
                break;
            }
        }
        Ok(())
    }
}

pub fn compress<R: Read, W: Write>(input: R, output: W) -> Result<W, Error> {
    let mut compressor = Compressor::new(input, output);
    try!(compressor.process());
    Ok(compressor.finish())
}

pub fn decompress<R: Read, W: Write>(input: R, output: W) -> Result<W, Error> {
    let mut decompressor = Decompressor::new(input, output);
    try!(decompressor.process());
    Ok(decompressor.finish())
}

#[cfg(test)]
mod tests {
    use ::std::io::Cursor;
    use super::{compress, decompress};

    #[test]
    fn compress_empty() {
    }

    #[test]
    fn compress_decompress() {
        let input = include_bytes!("lzmg1.rs");
        let result = compress(Cursor::new(&input[..]), vec![]).unwrap();

        let dec_result = decompress(Cursor::new(&result[..]), vec![]).unwrap();
        assert_eq!(&input[..], &dec_result[..]);
    }
}
<commit_msg>Cleanup, lzmg1 still broken though.<commit_after>// Copyright 2016 Martin Grabmueller. See the LICENSE file at the
// top-level directory of this distribution for license information.

//! Simple implementation of an LZ4-like compressor.

use std::io::{Read, Write};
use std::collections::HashMap;

use error::Error;

const INDEX_BIT_COUNT: usize = 12;
const LENGTH_BIT_COUNT: usize = 8;
const WINDOW_SIZE: usize = 1 << INDEX_BIT_COUNT;
const RAW_LOOK_AHEAD_SIZE: usize = 1 << LENGTH_BIT_COUNT;
const BREAK_EVEN: usize = (1 + INDEX_BIT_COUNT + LENGTH_BIT_COUNT) / 9;
const LOOK_AHEAD_SIZE: usize = RAW_LOOK_AHEAD_SIZE + BREAK_EVEN;

pub struct Compressor<R, W> {
    input: R,
    output: W,
    hash_table: HashMap<u32, usize>,
    window: [u8; WINDOW_SIZE],
    hashes: [u32; WINDOW_SIZE],
    next: [Option<usize>; WINDOW_SIZE],
    literals: Vec<u8>,
    lookups: usize,
    lin_lookups: usize,
}

impl<R, W> Compressor<R, W> {
    pub fn new(r: R, w: W) -> Compressor<R, W> {
        Compressor {
            input: r,
            output: w,
            hash_table: HashMap::new(),
            window: [0; WINDOW_SIZE],
            hashes: [0; WINDOW_SIZE],
            next: [None; WINDOW_SIZE],
            literals: Vec::new(),
            lookups: 0,
            lin_lookups: 0,
        }
    }

    pub fn finish(self) -> W {
//        println!("lookups: {}", self.lookups);
//        println!("lin_lookups: {}", self.lin_lookups);
        self.output
    }
}

impl<R: Read, W: Write> Compressor<R, W> {
    fn hash_at(&self, p: usize) -> u32 {
        ((self.window[self.mod_window(p)] as u32) << 24) +
            ((self.window[self.mod_window(p + 1)] as u32) << 16) +
            ((self.window[self.mod_window(p + 2)] as u32) << 8) +
            (self.window[self.mod_window(p + 3)] as u32)
    }

    fn getc(&mut self) -> Result<Option<u8>, Error> {
        let mut buf = [0u8; 1];
        let n = try!(self.input.read(&mut buf[..]));
        if n == 1 {
            Ok(Some(buf[0]))
        } else {
            Ok(None)
        }
    }

    fn delete_string(&mut self, pos: usize) {
        let hsh = self.hashes[pos];
        self.hash_table.remove(&hsh);
        if let Some(next_pos) = self.next[pos] {
            self.hash_table.insert(self.hashes[next_pos], next_pos);
        }
        self.hashes[pos] = 0;
        self.next[pos] = None;
    }

    fn get_longest_match(&mut self, hsh: u32, current_pos: usize,
                         look_ahead_bytes: usize) -> Option<(usize, usize)> {
        self.lookups += 1;
        let res =
            if let Some(hpos) = self.hash_table.get(&hsh) {
                let mut max_pos = *hpos;
                let mut max_len = 4;
                let mut pos = max_pos;
                let mut iterations = 0;
                loop {
                    let mut len = 0;
                    for i in 0..look_ahead_bytes {
                        if self.window[self.mod_window(max_pos + i)] == self.window[self.mod_window(current_pos + i)] {
                            len += 1;
                        } else {
                            break;
                        }
                    }
                    if len > max_len {
                        max_len = len;
                        max_pos = pos;
                    }
                    if let Some(npos) = self.next[pos] {
                        pos = npos;
                        self.lin_lookups += 1;
                    } else {
                        break;
                    }
                    iterations += 1;
                    if iterations > 10 {
                        break;
                    }
                }
                Some((max_pos, max_len))
            } else {
                None
            };
        if let Some((p, _)) = res {
            self.hash_table.insert(hsh, current_pos);
            self.hashes[current_pos] = hsh;
            self.next[current_pos] = Some(p);
        } else {
            self.hash_table.insert(hsh, current_pos);
            self.hashes[current_pos] = hsh;
            self.next[current_pos] = None;
        }
        res
    }

    fn add_string(&mut self, pos: usize, look_ahead_bytes: usize,
                  match_pos: &mut usize) -> usize {
        if look_ahead_bytes < 4 {
            *match_pos = 0;
            0
        } else {
            let hsh = self.hash_at(pos);
            if let Some((hpos, hlen)) = self.get_longest_match(hsh, pos, look_ahead_bytes) {
                *match_pos = hpos;
                hlen
            } else {
                *match_pos = 0;
                0
            }
        }
    }

    fn mod_window(&self, p: usize) -> usize {
        p % WINDOW_SIZE
    }

    pub fn process(&mut self) -> Result<(), Error> {
        let mut current_position = 0;
        let mut look_ahead_bytes =
            try!(self.input.read(&mut self.window[..LOOK_AHEAD_SIZE]));

        let mut match_length = 0;
        let mut match_position = 0;
        let mut replace_count;
        let _ = self.add_string(current_position, look_ahead_bytes,
                                &mut match_position);
        while look_ahead_bytes > 0 {
            if match_length > look_ahead_bytes {
                match_length = look_ahead_bytes;
            }
            if match_length <= BREAK_EVEN {

                self.literals.push(self.window[current_position]);
                replace_count = 1;

            } else {
                try!(self.emit(match_position, match_length));

                replace_count = match_length;
            }
            for _ in 0..replace_count {

                let cp = self.mod_window(current_position + LOOK_AHEAD_SIZE);
                self.delete_string(cp);

                if let Some(c) = try!(self.getc()) {
                    self.window[self.mod_window(current_position + LOOK_AHEAD_SIZE)] = c;
                } else {
                    look_ahead_bytes -= 1;
                }
                current_position = self.mod_window(current_position + 1);
                if look_ahead_bytes > 0 {
                    match_length = self.add_string(current_position, look_ahead_bytes,
                                                   &mut match_position);
                }
            }
        }

        if self.literals.len() > 0 {
            try!(self.emit(0, 0));
        }

        Ok(())
    }

    fn emit(&mut self, match_pos: usize, match_len: usize) -> Result<(), Error> {
        let (lit_tok, lit_extra) =
            if self.literals.len() > 14 {
                (15u8, Some(self.literals.len()))
            } else {
                (self.literals.len() as u8, None)
            };
        let (match_tok, match_extra) =
            if match_len > 14 {
                (15u8, Some(match_len))
            } else {
                (match_len as u8, None)
            };
        let token = (lit_tok << 4) | match_tok;
        try!(self.output.write(&[token]));
        if let Some(mut le) = lit_extra {
            while le >= 255 {
                try!(self.output.write(&[255]));
                le -= 255;
            }
            try!(self.output.write(&[le as u8]));
        }
        if self.literals.len() > 0 {
            try!(self.output.write(&self.literals));
            self.literals.truncate(0);
        }
        if let Some(mut me) = match_extra {
            while me >= 255 {
                try!(self.output.write(&[255]));
                me -= 255;
            }
            try!(self.output.write(&[me as u8]));
        }
        if match_len > 0 {
            let mut mp = match_pos;
            while mp >= 255 {
                try!(self.output.write(&[255]));
                mp -= 255;
            }
            try!(self.output.write(&[mp as u8]));
        }
        Ok(())
    }
}

pub struct Decompressor<R, W> {
    input: R,
    output: W,
    window: [u8; WINDOW_SIZE],
}

impl<R, W> Decompressor<R, W> {
    pub fn new(r: R, w: W) -> Decompressor<R, W> {
        Decompressor {
            input: r,
            output: w,
            window: [0; WINDOW_SIZE],
        }
    }

    pub fn finish(self) -> W {
        self.output
    }
}

impl<R: Read, W: Write> Decompressor<R, W> {
    fn getc(&mut self) -> Result<Option<u8>, Error> {
        let mut buf = [0u8; 1];
        let n = try!(self.input.read(&mut buf[..]));
        if n == 1 {
            Ok(Some(buf[0]))
        } else {
            Ok(None)
        }
    }

    fn mod_window(&self, p: usize) -> usize {
        p % WINDOW_SIZE
    }

    fn get_len(&mut self) -> Result<(usize, usize), Error> {
        let mut llen = 0;
        let mut l: usize = 0;
        if let Some(mut c) = try!(self.getc()) {
            llen += 1;
            while c == 255 {
                l += 255;
                if let Some(cc) = try!(self.getc()) {
                    llen += 1;
                    c = cc;
                } else {
                    return Err(Error::UnexpectedEof);
                }
            }
            l += c as usize;
        }
        Ok((l, llen))
    }

    pub fn process(&mut self) -> Result<(), Error> {
        let mut current_position = 0;
        loop {
            if let Some(token) = try!(self.getc()) {
                let lit_tok = token >> 4;
                let match_tok = token & 0x0f;
                let (lit_len, _extra_lit_len) =
                    if lit_tok == 15 {
                        try!(self.get_len())
                    } else {
                        (lit_tok as usize, 0)
                    };
                let mut lit: Vec<u8> = Vec::new();
                let mut mtch: Vec<u8> = Vec::new();
                for _ in 0..lit_len {
                    if let Some(c) = try!(self.getc()) {
                        self.window[current_position] = c;
                        try!(self.output.write(&[c]));
                        current_position = self.mod_window(current_position + 1);
                        lit.push(c);
                    } else {
                        return Err(Error::UnexpectedEof);
                    }
                }
                let (match_len, _extra_match_len) =
                    if match_tok == 15 {
                        try!(self.get_len())

                    } else {
                        (match_tok as usize, 0)
                    };
                let (match_pos, _match_pos_len) = try!(self.get_len());
//                println!("literal length: {}, match length: {}, match pos: {}",
//                         lit_len, match_len, match_pos);
                for i in 0..match_len {
                    let c = self.window[self.mod_window(match_pos + i)];
                    self.window[current_position] = c;
                    try!(self.output.write(&[c]));
                    current_position = self.mod_window(current_position + 1);
                    mtch.push(c);
                }
//                let enc_len = 1 + extra_lit_len + lit_len + extra_match_len + match_pos_len;
//                let dec_len = lit_len + match_len;
//                println!("{:?} {:?}; {} -> {}", String::from_utf8_lossy(&lit), String::from_utf8_lossy(&mtch), enc_len, dec_len);
            } else {
                break;
            }
        }
        Ok(())
    }
}

pub fn compress<R: Read, W: Write>(input: R, output: W) -> Result<W, Error> {
    let mut compressor = Compressor::new(input, output);
    try!(compressor.process());
    Ok(compressor.finish())
}

pub fn decompress<R: Read, W: Write>(input: R, output: W) -> Result<W, Error> {
    let mut decompressor = Decompressor::new(input, output);
    try!(decompressor.process());
    Ok(decompressor.finish())
}

#[cfg(test)]
mod tests {
    use ::std::io::Cursor;
    use super::{compress, decompress};

    #[test]
    fn compress_empty() {
    }

    #[test]
    fn compress_decompress() {
        let input = include_bytes!("lzmg1.rs");
        let result = compress(Cursor::new(&input[..]), vec![]).unwrap();

        let dec_result = decompress(Cursor::new(&result[..]), vec![]).unwrap();
        assert_eq!(&input[..], &dec_result[..]);
    }
}
<|endoftext|>


<commit_before>//! Types representing for data which will be retrieved from the driver.
//! Currently this data is expected to look like a JSON object but this may be
//! changed in the future. Driver authors must cast the data they retrieve from
//! the driver to these types.

use linear_map::LinearMap;

/// The atomic level of a pointer.
pub type Key = String;

/// Represents a JSON pointer to a document property.
pub type Pointer = Vec<Key>;

/// Various value types. Based on types in the [JSON standard][1] (see section
/// 5).
///
/// [1]: http://ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
#[derive(PartialEq, Debug)]
pub enum Value {
  /// The abscense of any value.
  Null,
  /// True or false.
  Boolean(bool),
  /// A numeric value, float, integer, whatever.
  Number(f64),
  /// A list of characters.
  String(String),
  /// A list of values.
  Array(Vec<Value>),
  /// A map of key/value pairs. Stored as a vector of tuples for performance
  /// and to maintain key ordering.
  Object(LinearMap<Key, Value>)
}

/// A schema detailing what the data received from the driver (or inserted
/// into the driver) should be. Inspired after [JSON Schema][1]. A reference
/// on JSON Schema type-specific validations used in this enum may be found
/// [here][2].
///
/// [1]: http://json-schema.org
/// [2]: http://spacetelescope.github.io/understanding-json-schema/reference/type.html
pub enum Schema {
  /// There is no schema. No validations should occur.
  None,
  /// Represents the absence of any value.
  Null,
  /// Represents a binary true/false value.
  Boolean,
  /// Represents a numeric type.
  Number {
    /// Forces the number to be a multiple of another. This helps in specifying
    /// integers if this value is `Some(1)` for example.
    multiple_of: Option<f32>,
    /// The minimum value the number can be.
    minimum: Option<f64>,
    /// The maximum value the number can be.
    maximum: Option<f64>
  },
  String {
    /// The mimimum length of characters in the string.
    min_length: Option<u64>,
    /// The maximum length of characters in the string.
    max_length: Option<u64>,
    /// A regular expression pattern to validate the string against.
    // TODO: Use a regex crate.
    pattern: Option<String>
  },
  /// Represents a set of any type.
  Array {
    /// A schema which all items in the array must match.
    items: Box<Schema>
  },
  /// Represents any tuple of values.
  Tuple {
    /// Schemas which each tuple value (in the same place) must comply with.
    items: Vec<Schema>,
    /// Whether or not there can be more items in the tuple.
    additional_items: bool
  },
  /// Represents a set of key/value pairs.
  Object {
    /// Schemas associated to the object properties.
    properties: LinearMap<Key, Schema>,
    /// Properties that are required to be in the object.
    required: Vec<Key>,
    /// Whether or not there may be extra properties outside of the ones
    /// defined by the properties map.
    additional_properties: bool
  },
  /// Represents a value which *must* be one of the defined values.
  Enum(Vec<Value>)
}
<commit_msg>docs: add extra array docs<commit_after>//! Types representing for data which will be retrieved from the driver.
//! Currently this data is expected to look like a JSON object but this may be
//! changed in the future. Driver authors must cast the data they retrieve from
//! the driver to these types.

use linear_map::LinearMap;

/// The atomic level of a pointer.
pub type Key = String;

/// Represents a JSON pointer to a document property.
pub type Pointer = Vec<Key>;

/// Various value types. Based on types in the [JSON standard][1] (see section
/// 5).
///
/// [1]: http://ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
#[derive(PartialEq, Debug)]
pub enum Value {
  /// The abscense of any value.
  Null,
  /// True or false.
  Boolean(bool),
  /// A numeric value, float, integer, whatever.
  Number(f64),
  /// A list of characters.
  String(String),
  /// A map of key/value pairs. Stored as a vector of tuples for performance
  /// and to maintain key ordering.
  Object(LinearMap<Key, Value>),
  /// A list of values. Just a value, but using *only* integer keys.
  Array(Vec<Value>)
}

/// A schema detailing what the data received from the driver (or inserted
/// into the driver) should be. Inspired after [JSON Schema][1]. A reference
/// on JSON Schema type-specific validations used in this enum may be found
/// [here][2].
///
/// [1]: http://json-schema.org
/// [2]: http://spacetelescope.github.io/understanding-json-schema/reference/type.html
pub enum Schema {
  /// There is no schema. No validations should occur.
  None,
  /// Represents the absence of any value.
  Null,
  /// Represents a binary true/false value.
  Boolean,
  /// Represents a numeric type.
  Number {
    /// Forces the number to be a multiple of another. This helps in specifying
    /// integers if this value is `Some(1)` for example.
    multiple_of: Option<f32>,
    /// The minimum value the number can be.
    minimum: Option<f64>,
    /// The maximum value the number can be.
    maximum: Option<f64>
  },
  String {
    /// The mimimum length of characters in the string.
    min_length: Option<u64>,
    /// The maximum length of characters in the string.
    max_length: Option<u64>,
    /// A regular expression pattern to validate the string against.
    // TODO: Use a regex crate.
    pattern: Option<String>
  },
  /// Represents a set of any type.
  Array {
    /// A schema which all items in the array must match.
    items: Box<Schema>
  },
  /// Represents any tuple of values.
  Tuple {
    /// Schemas which each tuple value (in the same place) must comply with.
    items: Vec<Schema>,
    /// Whether or not there can be more items in the tuple.
    additional_items: bool
  },
  /// Represents a set of key/value pairs.
  Object {
    /// Schemas associated to the object properties.
    properties: LinearMap<Key, Schema>,
    /// Properties that are required to be in the object.
    required: Vec<Key>,
    /// Whether or not there may be extra properties outside of the ones
    /// defined by the properties map.
    additional_properties: bool
  },
  /// Represents a value which *must* be one of the defined values.
  Enum(Vec<Value>)
}
<|endoftext|>


<commit_before>//! Module: czmq-zcert

use {czmq_sys, Error, ErrorKind, Result, ZList};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::{error, fmt, ptr, slice};
use zmsg::ZMsgable;

const KEY_SIZE: usize = 32;

pub struct ZCert {
    zcert: *mut czmq_sys::zcert_t,
    owned: bool,
}

unsafe impl Send for ZCert {}
unsafe impl Sync for ZCert {}

impl Drop for ZCert {
    fn drop(&mut self) {
        if self.owned {
            unsafe { czmq_sys::zcert_destroy(&mut self.zcert) };
        }
    }
}

impl ZCert {
    pub fn new() -> Result<ZCert> {
        let zcert = unsafe { czmq_sys::zcert_new() };

        if zcert == ptr::null_mut() {
            return Err(Error::new(ErrorKind::NullPtr, ZCertError::Instantiate));
        }

        Ok(ZCert {
            zcert: zcert,
            owned: true,
        })
    }

    pub fn from_keys(public_key: &[u8], secret_key: &[u8]) -> ZCert {
        ZCert {
            zcert: unsafe { czmq_sys::zcert_new_from(public_key.as_ptr(), secret_key.as_ptr()) },
            owned: true,
        }
    }

    pub fn from_raw(zcert: *mut czmq_sys::zcert_t, owned: bool) -> ZCert {
        ZCert {
            zcert: zcert,
            owned: owned,
        }
    }

    pub fn into_raw(mut self) -> *mut czmq_sys::zcert_t {
        self.owned = false;
        self.zcert
    }

    pub fn load(filename: &str) -> Result<ZCert> {
        let filename_c = try!(CString::new(filename));
        let zcert = unsafe { czmq_sys::zcert_load(filename_c.as_ptr()) };

        if zcert == ptr::null_mut() {
            return Err(Error::new(ErrorKind::NullPtr, ZCertError::InvalidCert(filename_c.into_string().unwrap())));
        }

        Ok(ZCert {
            zcert: zcert,
            owned: true,
        })
    }

    pub fn public_key<'a>(&'a self) -> &'a [u8] {
        unsafe {
            let ptr = czmq_sys::zcert_public_key(self.zcert);
            slice::from_raw_parts(ptr, KEY_SIZE)
        }
    }

    pub fn secret_key<'a>(&'a self) -> &'a [u8] {
        unsafe {
            let ptr = czmq_sys::zcert_secret_key(self.zcert);
            slice::from_raw_parts(ptr, KEY_SIZE)
        }
    }

    pub fn public_txt<'a>(&'a self) -> &'a str {
        unsafe {
            let ptr = czmq_sys::zcert_public_txt(self.zcert);
            CStr::from_ptr(ptr as *const c_char).to_str().unwrap_or("")
        }
    }

    pub fn secret_txt<'a>(&'a self) -> &'a str {
        unsafe {
            let ptr = czmq_sys::zcert_secret_txt(self.zcert);
            CStr::from_ptr(ptr as *const c_char).to_str().unwrap_or("")
        }
    }

    pub fn set_meta(&self, key: &str, value: &str) {
        let key_c = CString::new(key).unwrap_or(CString::new("").unwrap());
        let value_c = CString::new(value).unwrap_or(CString::new("").unwrap());

        unsafe { czmq_sys::zcert_set_meta(self.zcert, key_c.as_ptr(), "%s\0".as_ptr() as *const i8, value_c.as_ptr()) };
    }

    pub fn meta<'a>(&'a self, key: &str) -> Result<Option<&'a str>> {
        let key_c = try!(CString::new(key));

        let value = unsafe {
            let ptr = czmq_sys::zcert_meta(self.zcert, key_c.as_ptr());
            CStr::from_ptr(ptr as *const c_char)
        };

        match value.to_str() {
            Ok(s) => Ok(Some(s)),
            Err(_) => Ok(None),
        }
    }

    pub fn meta_keys<'a>(&'a self) -> ZList {
        let ptr = unsafe { czmq_sys::zcert_meta_keys(self.zcert) };
        ZList::from_raw(ptr)
    }

    pub fn save(&self, filename: &str) -> Result<()> {
        let filename_c = try!(CString::new(filename));

        unsafe {
            let rc = czmq_sys::zcert_save(self.zcert, filename_c.as_ptr());
            if rc == -1 {
                Err(Error::new(ErrorKind::NonZero, ZCertError::SavePath(filename_c.into_string().unwrap())))
            } else {
                Ok(())
            }
        }
    }

    pub fn save_public(&self, filename: &str) -> Result<()> {
        let filename_c = try!(CString::new(filename));

        unsafe {
            let rc = czmq_sys::zcert_save_public(self.zcert, filename_c.as_ptr());
            if rc == -1 {
                Err(Error::new(ErrorKind::NonZero, ZCertError::SavePath(filename_c.into_string().unwrap())))
            } else {
                Ok(())
            }
        }
    }

    pub fn save_secret(&self, filename: &str) -> Result<()> {
        let filename_c = try!(CString::new(filename));

        unsafe {
            let rc = czmq_sys::zcert_save_secret(self.zcert, filename_c.as_ptr());
            if rc == -1 {
                Err(Error::new(ErrorKind::NonZero, ZCertError::SavePath(filename_c.into_string().unwrap())))
            } else {
                Ok(())
            }
        }
    }

    pub fn apply<S: ZMsgable>(&self, sock: &S) {
        unsafe { czmq_sys::zcert_apply(self.zcert, sock.borrow_raw()) };
    }

    pub fn dup(&self) -> ZCert {
        let ptr = unsafe { czmq_sys::zcert_dup(self.zcert) };

        ZCert {
            zcert: ptr,
            owned: true,
        }
    }

    pub fn eq(&self, cert: &ZCert) -> bool {
        let result = unsafe { czmq_sys::zcert_eq(self.zcert, cert.zcert) };
        result == 1
    }

    pub fn print(&self) {
        unsafe { czmq_sys::zcert_print(self.zcert) };
    }
}

#[derive(Debug)]
pub enum ZCertError {
    Instantiate,
    InvalidCert(String),
    SavePath(String),
}

impl fmt::Display for ZCertError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ZCertError::Instantiate => write!(f, "Could not instantiate new ZCert struct"),
            ZCertError::InvalidCert(ref e) => write!(f, "Could not open certificate at path: {}", e),
            ZCertError::SavePath(ref e) => write!(f, "Could not save certificate file to path: {}", e),
        }
    }
}

impl error::Error for ZCertError {
    fn description(&self) -> &str {
        match *self {
            ZCertError::Instantiate => "Could not instantiate new ZCert struct",
            ZCertError::InvalidCert(_) => "Certificate was invalid or non-existent",
            ZCertError::SavePath(_) => "Could not save certificate file to given path",
        }
    }
}

#[cfg(test)]
mod tests {
    use {ZSock, zsys_init};
    use super::*;
    use zmq;

    const PUBLIC_TXT: &'static str = "Ko9/&3Uw)$U]Zyp>+4$-i/yaDea2QqlDPGl-&V1s";
    const SECRET_TXT: &'static str = "[MfOo!1^1N}zZY/x{[A6^9>VRC.+O6vX&]zYvDC-";

    #[test]
    fn test_public_key() {
        let cert = create_cert();
        let key = cert.public_key();
        let test_key = zmq::z85_decode(PUBLIC_TXT);

        let mut iter = 0;
        for _ in key.iter() {
            assert_eq!(key[iter], test_key[iter]);
            iter += 1;
        }
    }

    #[test]
    fn test_secret_key() {
        let cert = create_cert();
        let key = cert.secret_key();
        let test_key = zmq::z85_decode(SECRET_TXT);

        let mut iter = 0;
        for _ in key.iter() {
            assert_eq!(key[iter], test_key[iter]);
            iter += 1;
        }
    }

    #[test]
    fn test_public_txt() {
        let cert = create_cert();
        assert_eq!(cert.public_txt(), PUBLIC_TXT);
    }

    #[test]
    fn test_secret_txt() {
        let cert = create_cert();
        assert_eq!(cert.secret_txt(), SECRET_TXT);
    }

    #[test]
    fn test_getset_meta() {
        let cert = create_cert();
        cert.set_meta("moo", "cow");
        assert_eq!(cert.meta("moo").unwrap().unwrap(), "cow");
    }

    #[test]
    fn test_meta_keys() {
        let cert = create_cert();
        assert!(cert.meta_keys().to_vec().len() == 0);
        cert.set_meta("moo", "cow");
        let keys = cert.meta_keys();
        assert_eq!(keys.to_vec().first().unwrap(), &"moo");
    }

    #[test]
    fn test_apply_zmq() {
        let cert = create_cert();
        let mut ctx = zmq::Context::new();
        let sock = ctx.socket(zmq::REQ).unwrap();
        cert.apply(&sock);
        assert_eq!(sock.get_curve_publickey().unwrap().unwrap(), PUBLIC_TXT);
        assert_eq!(sock.get_curve_secretkey().unwrap().unwrap(), SECRET_TXT);
    }

    #[test]
    fn test_apply_zsock() {
        zsys_init();

        let cert = create_cert();
        let sock = ZSock::new_rep("inproc://zcert_test_apply_zsock").unwrap();
        cert.apply(&sock);
        assert_eq!(sock.curve_publickey().unwrap().unwrap(), PUBLIC_TXT);
        assert_eq!(sock.curve_secretkey().unwrap().unwrap(), SECRET_TXT);
    }

    #[test]
    fn test_dup() {
        let cert = create_cert();
        let dup = cert.dup();
        assert_eq!(cert.secret_txt(), dup.secret_txt());
    }

    #[test]
    fn test_eq() {
        let c1 = create_cert();
        let c2 = create_cert();
        assert!(c1.eq(&c2));
    }

    fn create_cert() -> ZCert {
        let public_key = zmq::z85_decode(PUBLIC_TXT);
        let secret_key = zmq::z85_decode(SECRET_TXT);
        ZCert::from_keys(&public_key, &secret_key)
    }
}
<commit_msg>Add method ZCert::from_txt for generating certs from plain text strings<commit_after>//! Module: czmq-zcert

use {czmq_sys, Error, ErrorKind, Result, ZList, zmq};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::{error, fmt, ptr, slice};
use zmsg::ZMsgable;

const KEY_SIZE: usize = 32;

pub struct ZCert {
    zcert: *mut czmq_sys::zcert_t,
    owned: bool,
}

unsafe impl Send for ZCert {}
unsafe impl Sync for ZCert {}

impl Drop for ZCert {
    fn drop(&mut self) {
        if self.owned {
            unsafe { czmq_sys::zcert_destroy(&mut self.zcert) };
        }
    }
}

impl ZCert {
    pub fn new() -> Result<ZCert> {
        let zcert = unsafe { czmq_sys::zcert_new() };

        if zcert == ptr::null_mut() {
            return Err(Error::new(ErrorKind::NullPtr, ZCertError::Instantiate));
        }

        Ok(ZCert {
            zcert: zcert,
            owned: true,
        })
    }

    pub fn from_keys(public_key: &[u8], secret_key: &[u8]) -> ZCert {
        ZCert {
            zcert: unsafe { czmq_sys::zcert_new_from(public_key.as_ptr(), secret_key.as_ptr()) },
            owned: true,
        }
    }

    pub fn from_txt(public_txt: &str, secret_txt: &str) -> ZCert {
        ZCert::from_keys(&zmq::z85_decode(public_txt), &zmq::z85_decode(secret_txt))
    }

    pub fn from_raw(zcert: *mut czmq_sys::zcert_t, owned: bool) -> ZCert {
        ZCert {
            zcert: zcert,
            owned: owned,
        }
    }

    pub fn into_raw(mut self) -> *mut czmq_sys::zcert_t {
        self.owned = false;
        self.zcert
    }

    pub fn load(filename: &str) -> Result<ZCert> {
        let filename_c = try!(CString::new(filename));
        let zcert = unsafe { czmq_sys::zcert_load(filename_c.as_ptr()) };

        if zcert == ptr::null_mut() {
            return Err(Error::new(ErrorKind::NullPtr, ZCertError::InvalidCert(filename_c.into_string().unwrap())));
        }

        Ok(ZCert {
            zcert: zcert,
            owned: true,
        })
    }

    pub fn public_key<'a>(&'a self) -> &'a [u8] {
        unsafe {
            let ptr = czmq_sys::zcert_public_key(self.zcert);
            slice::from_raw_parts(ptr, KEY_SIZE)
        }
    }

    pub fn secret_key<'a>(&'a self) -> &'a [u8] {
        unsafe {
            let ptr = czmq_sys::zcert_secret_key(self.zcert);
            slice::from_raw_parts(ptr, KEY_SIZE)
        }
    }

    pub fn public_txt<'a>(&'a self) -> &'a str {
        unsafe {
            let ptr = czmq_sys::zcert_public_txt(self.zcert);
            CStr::from_ptr(ptr as *const c_char).to_str().unwrap_or("")
        }
    }

    pub fn secret_txt<'a>(&'a self) -> &'a str {
        unsafe {
            let ptr = czmq_sys::zcert_secret_txt(self.zcert);
            CStr::from_ptr(ptr as *const c_char).to_str().unwrap_or("")
        }
    }

    pub fn set_meta(&self, key: &str, value: &str) {
        let key_c = CString::new(key).unwrap_or(CString::new("").unwrap());
        let value_c = CString::new(value).unwrap_or(CString::new("").unwrap());

        unsafe { czmq_sys::zcert_set_meta(self.zcert, key_c.as_ptr(), "%s\0".as_ptr() as *const i8, value_c.as_ptr()) };
    }

    pub fn meta<'a>(&'a self, key: &str) -> Result<Option<&'a str>> {
        let key_c = try!(CString::new(key));

        let value = unsafe {
            let ptr = czmq_sys::zcert_meta(self.zcert, key_c.as_ptr());
            CStr::from_ptr(ptr as *const c_char)
        };

        match value.to_str() {
            Ok(s) => Ok(Some(s)),
            Err(_) => Ok(None),
        }
    }

    pub fn meta_keys<'a>(&'a self) -> ZList {
        let ptr = unsafe { czmq_sys::zcert_meta_keys(self.zcert) };
        ZList::from_raw(ptr)
    }

    pub fn save(&self, filename: &str) -> Result<()> {
        let filename_c = try!(CString::new(filename));

        unsafe {
            let rc = czmq_sys::zcert_save(self.zcert, filename_c.as_ptr());
            if rc == -1 {
                Err(Error::new(ErrorKind::NonZero, ZCertError::SavePath(filename_c.into_string().unwrap())))
            } else {
                Ok(())
            }
        }
    }

    pub fn save_public(&self, filename: &str) -> Result<()> {
        let filename_c = try!(CString::new(filename));

        unsafe {
            let rc = czmq_sys::zcert_save_public(self.zcert, filename_c.as_ptr());
            if rc == -1 {
                Err(Error::new(ErrorKind::NonZero, ZCertError::SavePath(filename_c.into_string().unwrap())))
            } else {
                Ok(())
            }
        }
    }

    pub fn save_secret(&self, filename: &str) -> Result<()> {
        let filename_c = try!(CString::new(filename));

        unsafe {
            let rc = czmq_sys::zcert_save_secret(self.zcert, filename_c.as_ptr());
            if rc == -1 {
                Err(Error::new(ErrorKind::NonZero, ZCertError::SavePath(filename_c.into_string().unwrap())))
            } else {
                Ok(())
            }
        }
    }

    pub fn apply<S: ZMsgable>(&self, sock: &S) {
        unsafe { czmq_sys::zcert_apply(self.zcert, sock.borrow_raw()) };
    }

    pub fn dup(&self) -> ZCert {
        let ptr = unsafe { czmq_sys::zcert_dup(self.zcert) };

        ZCert {
            zcert: ptr,
            owned: true,
        }
    }

    pub fn eq(&self, cert: &ZCert) -> bool {
        let result = unsafe { czmq_sys::zcert_eq(self.zcert, cert.zcert) };
        result == 1
    }

    pub fn print(&self) {
        unsafe { czmq_sys::zcert_print(self.zcert) };
    }
}

#[derive(Debug)]
pub enum ZCertError {
    Instantiate,
    InvalidCert(String),
    SavePath(String),
}

impl fmt::Display for ZCertError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ZCertError::Instantiate => write!(f, "Could not instantiate new ZCert struct"),
            ZCertError::InvalidCert(ref e) => write!(f, "Could not open certificate at path: {}", e),
            ZCertError::SavePath(ref e) => write!(f, "Could not save certificate file to path: {}", e),
        }
    }
}

impl error::Error for ZCertError {
    fn description(&self) -> &str {
        match *self {
            ZCertError::Instantiate => "Could not instantiate new ZCert struct",
            ZCertError::InvalidCert(_) => "Certificate was invalid or non-existent",
            ZCertError::SavePath(_) => "Could not save certificate file to given path",
        }
    }
}

#[cfg(test)]
mod tests {
    use {ZSock, zsys_init};
    use super::*;
    use zmq;

    const PUBLIC_TXT: &'static str = "Ko9/&3Uw)$U]Zyp>+4$-i/yaDea2QqlDPGl-&V1s";
    const SECRET_TXT: &'static str = "[MfOo!1^1N}zZY/x{[A6^9>VRC.+O6vX&]zYvDC-";

    #[test]
    fn test_public_key() {
        let cert = create_cert();
        let key = cert.public_key();
        let test_key = zmq::z85_decode(PUBLIC_TXT);

        let mut iter = 0;
        for _ in key.iter() {
            assert_eq!(key[iter], test_key[iter]);
            iter += 1;
        }
    }

    #[test]
    fn test_secret_key() {
        let cert = create_cert();
        let key = cert.secret_key();
        let test_key = zmq::z85_decode(SECRET_TXT);

        let mut iter = 0;
        for _ in key.iter() {
            assert_eq!(key[iter], test_key[iter]);
            iter += 1;
        }
    }

    #[test]
    fn test_public_txt() {
        let cert = create_cert();
        assert_eq!(cert.public_txt(), PUBLIC_TXT);
    }

    #[test]
    fn test_secret_txt() {
        let cert = create_cert();
        assert_eq!(cert.secret_txt(), SECRET_TXT);
    }

    #[test]
    fn test_getset_meta() {
        let cert = create_cert();
        cert.set_meta("moo", "cow");
        assert_eq!(cert.meta("moo").unwrap().unwrap(), "cow");
    }

    #[test]
    fn test_meta_keys() {
        let cert = create_cert();
        assert!(cert.meta_keys().to_vec().len() == 0);
        cert.set_meta("moo", "cow");
        let keys = cert.meta_keys();
        assert_eq!(keys.to_vec().first().unwrap(), &"moo");
    }

    #[test]
    fn test_apply_zmq() {
        let cert = create_cert();
        let mut ctx = zmq::Context::new();
        let sock = ctx.socket(zmq::REQ).unwrap();
        cert.apply(&sock);
        assert_eq!(sock.get_curve_publickey().unwrap().unwrap(), PUBLIC_TXT);
        assert_eq!(sock.get_curve_secretkey().unwrap().unwrap(), SECRET_TXT);
    }

    #[test]
    fn test_apply_zsock() {
        zsys_init();

        let cert = create_cert();
        let sock = ZSock::new_rep("inproc://zcert_test_apply_zsock").unwrap();
        cert.apply(&sock);
        assert_eq!(sock.curve_publickey().unwrap().unwrap(), PUBLIC_TXT);
        assert_eq!(sock.curve_secretkey().unwrap().unwrap(), SECRET_TXT);
    }

    #[test]
    fn test_dup() {
        let cert = create_cert();
        let dup = cert.dup();
        assert_eq!(cert.secret_txt(), dup.secret_txt());
    }

    #[test]
    fn test_eq() {
        let c1 = create_cert();
        let c2 = create_cert();
        assert!(c1.eq(&c2));
    }

    fn create_cert() -> ZCert {
        ZCert::from_txt(PUBLIC_TXT, SECRET_TXT)
    }
}
<|endoftext|>