<commit_before>use std::fmt;
use std::slice;
use std::mem;
use std::marker::PhantomData;
use approx;
use num;
use channel::{NormalBoundedChannel, ColorChannel, NormalChannelScalar, ChannelFormatCast,
              ChannelCast, PosNormalChannelScalar, PosNormalBoundedChannel};
use color::{Color, Lerp, Invert, Flatten, Bounded};
use convert::FromColor;
use rgb::Rgb;
use linalg::Matrix3;

pub struct YCbCrTag;

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct JpegCoeffs<T>(pub PhantomData<T>);

pub trait YCbCrCoeffs<T>: Clone + PartialEq
    where T: NormalChannelScalar
{
    type OutputScalar: num::Float;
    fn get_transform() -> Matrix3<Self::OutputScalar>;
    fn get_shift() -> (Self::OutputScalar, Self::OutputScalar, Self::OutputScalar);
}

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct YCbCr<T, Coeffs = JpegCoeffs<T>> {
    luma: PosNormalBoundedChannel<T>,
    cb: NormalBoundedChannel<T>,
    cr: NormalBoundedChannel<T>,
    coeffs: PhantomData<Coeffs>,
}

macro_rules! impl_jpeg_coeffs_int {
    ($ty:ident, $flt_ty:ident) => {
        impl YCbCrCoeffs<$ty> for JpegCoeffs<$ty> {
            type OutputScalar = $flt_ty;
            #[inline]
            fn get_transform() -> Matrix3<$flt_ty> {
                Matrix3::new([
                    0.299, 0.587, 0.114,
                    -0.168736, -0.331264, 0.5,
                    0.5, -0.418688, -0.081312]
                )
            }
            #[inline]
            fn get_shift() -> ($flt_ty, $flt_ty, $flt_ty) {
                let center_chan = ((<$ty as NormalChannelScalar>::max_bound() >> 1) + 1) as $flt_ty;
                (0.0,
                center_chan,
                center_chan)
            }
        }
    };
}

macro_rules! impl_jpeg_coeffs_float {
    ($ty:ident) => {
        impl YCbCrCoeffs<$ty> for JpegCoeffs<$ty> {
            type OutputScalar = $ty;

            #[inline]
            fn get_transform() -> Matrix3<$ty> {
                Matrix3::new([
                    0.299, 0.587, 0.114,
                    -0.168736, -0.331264, 0.5,
                    0.5, -0.418688, -0.081312]
                )
            }
            #[inline]
            fn get_shift() -> ($ty, $ty, $ty) {
                (0.0, 0.0, 0.0)
            }
        }
    }
}

impl_jpeg_coeffs_int!(u8, f32);
impl_jpeg_coeffs_int!(u16, f32);
impl_jpeg_coeffs_int!(u32, f32);
impl_jpeg_coeffs_float!(f32);
impl_jpeg_coeffs_float!(f64);

pub type YCbCrJpeg<T> = YCbCr<T, JpegCoeffs<T>>;

impl<T, Coeffs> YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    pub fn from_channels(y: T, cb: T, cr: T) -> Self {
        YCbCr {
            luma: PosNormalBoundedChannel::new(y),
            cb: NormalBoundedChannel::new(cb),
            cr: NormalBoundedChannel::new(cr),
            coeffs: PhantomData,
        }
    }

    impl_color_color_cast_square!(YCbCr {luma, cb, cr},
        chan_traits={NormalChannelScalar,PosNormalChannelScalar},
        phantom={coeffs}, types={Coeffs});

    pub fn luma(&self) -> T {
        self.luma.0.clone()
    }
    pub fn cb(&self) -> T {
        self.cb.0.clone()
    }
    pub fn cr(&self) -> T {
        self.cr.0.clone()
    }
    pub fn luma_mut(&mut self) -> &mut T {
        &mut self.luma.0
    }
    pub fn cb_mut(&mut self) -> &mut T {
        &mut self.cb.0
    }
    pub fn cr_mut(&mut self) -> &mut T {
        &mut self.cr.0
    }
    pub fn set_luma(&mut self, val: T) {
        self.luma.0 = val;
    }
    pub fn set_cb(&mut self, val: T) {
        self.cb.0 = val;
    }
    pub fn set_cr(&mut self, val: T) {
        self.cr.0 = val;
    }
}

impl<T, Coeffs> Color for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    type Tag = YCbCrTag;
    type ChannelsTuple = (T, T, T);

    #[inline]
    fn num_channels() -> u32 {
        3
    }

    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        YCbCr {
            luma: PosNormalBoundedChannel::new(values.0),
            cb: NormalBoundedChannel::new(values.1),
            cr: NormalBoundedChannel::new(values.2),
            coeffs: PhantomData,
        }
    }
    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.luma.0, self.cb.0, self.cr.0)
    }
}

impl<T, Coeffs> Invert for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    impl_color_invert!(YCbCr {luma, cb, cr}, phantom={coeffs});
}

impl<T, Coeffs> Bounded for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    impl_color_bounded!(YCbCr {luma, cb, cr}, phantom={coeffs});
}

impl<T, Coeffs> Lerp for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + Lerp + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    type Position = <T as Lerp>::Position;
    impl_color_lerp_square!(YCbCr {luma, cb, cr}, phantom={coeffs});
}

impl<T, Coeffs> Flatten for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);
    impl_color_from_slice_square!(YCbCr<T> {luma:PosNormalBoundedChannel - 0,
        cb:NormalBoundedChannel - 1, cr:NormalBoundedChannel - 2}, phantom={coeffs});
}
impl<T, Coeffs> approx::ApproxEq for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar + approx::ApproxEq,
          T::Epsilon: Clone,
          Coeffs: YCbCrCoeffs<T>
{
    impl_approx_eq!({luma, cb, cr});
}

impl<T, Coeffs> Default for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar + num::Zero,
          Coeffs: YCbCrCoeffs<T>
{
    impl_color_default!(YCbCr {luma:PosNormalBoundedChannel, cb:NormalBoundedChannel,
        cr:NormalBoundedChannel}, phantom={coeffs});
}

impl<T> fmt::Display for YCbCr<T>
    where T: NormalChannelScalar + PosNormalChannelScalar + fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "YCbCr({}, {}, {})", self.luma, self.cb, self.cr)
    }
}

impl<T, Coeffs> FromColor<Rgb<T>> for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar + num::NumCast + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    fn from_color(from: &Rgb<T>) -> Self {
        let transform = Coeffs::get_transform();

        let (o1, o2, o3) = transform.transform_vector(from.clone().to_tuple());
        let (s1, s2, s3) = Coeffs::get_shift();
        YCbCr::from_channels(o1 + num::cast::<_, T>(s1).unwrap(),
                             o2 + num::cast::<_, T>(s2).unwrap(),
                             o3 + num::cast::<_, T>(s3).unwrap())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use rgb::Rgb;
    use convert::*;
    use color::*;

    #[test]
    fn test_construct() {
        let c1 = YCbCrJpeg::from_channels(0.75, 0.44, 0.21);
        assert_eq!(c1.luma(), 0.75);
        assert_eq!(c1.cb(), 0.44);
        assert_eq!(c1.cr(), 0.21);
        assert_eq!(c1.to_tuple(), (0.75, 0.44, 0.21));
        assert_eq!(YCbCrJpeg::from_tuple(c1.to_tuple()), c1);

        let c2 = YCbCrJpeg::from_channels(0.20, 0.21, 0.33);
        assert_eq!(c2.luma(), 0.20);
        assert_eq!(c2.cb(), 0.21);
        assert_eq!(c2.cr(), 0.33);
        assert_eq!(c2.to_tuple(), (0.20, 0.21, 0.33));
        assert_eq!(YCbCrJpeg::from_tuple(c2.to_tuple()), c2);
    }

    #[test]
    fn test_invert() {
        let c1 = YCbCrJpeg::from_channels(0.33, 0.55, 0.88);
        assert_relative_eq!(c1.invert().invert(), c1, epsilon=1e-6);
        assert_relative_eq!(c1.invert(),
            YCbCrJpeg::from_channels(0.67, -0.55, -0.88), epsilon=1e-6);

        let c2 = YCbCrJpeg::from_channels(0.2, -0.2, 1.0);
        assert_relative_eq!(c2.invert().invert(), c2, epsilon=1e-6);
        assert_relative_eq!(c2.invert(), YCbCrJpeg::from_channels(0.8, 0.2, -1.0));
    }

    #[test]
    fn test_from_rgb() {
        let c1 = Rgb::from_channels(255u8, 255, 255);
        let y1 = YCbCrJpeg::from_color(&c1);
        assert_eq!(y1.luma(), 255u8);
        assert_eq!(y1.cb(), 128);
        assert_eq!(y1.cr(), 128);

        let c2 = Rgb::from_channels(0.5, 0.5, 0.5);
        let y2 = YCbCrJpeg::from_color(&c2);
        assert_relative_eq!(y2, YCbCrJpeg::from_channels(0.5, 0.0, 0.0), epsilon=1e-6);
    }
}
<commit_msg>Finished YCbCr tests.<commit_after>use std::fmt;
use std::slice;
use std::mem;
use std::marker::PhantomData;
use approx;
use num;
use channel::{NormalBoundedChannel, ColorChannel, NormalChannelScalar, ChannelFormatCast,
              ChannelCast, PosNormalChannelScalar, PosNormalBoundedChannel};
use color::{Color, Lerp, Invert, Flatten, Bounded};
use convert::FromColor;
use rgb::Rgb;
use linalg::Matrix3;

pub struct YCbCrTag;

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct JpegCoeffs<T>(pub PhantomData<T>);

pub trait YCbCrCoeffs<T>: Clone + PartialEq
    where T: NormalChannelScalar
{
    type OutputScalar: num::Float;
    fn get_transform() -> Matrix3<Self::OutputScalar>;
    fn get_shift() -> (Self::OutputScalar, Self::OutputScalar, Self::OutputScalar);
}

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct YCbCr<T, Coeffs = JpegCoeffs<T>> {
    luma: PosNormalBoundedChannel<T>,
    cb: NormalBoundedChannel<T>,
    cr: NormalBoundedChannel<T>,
    coeffs: PhantomData<Coeffs>,
}

macro_rules! impl_jpeg_coeffs_int {
    ($ty:ident, $flt_ty:ident) => {
        impl YCbCrCoeffs<$ty> for JpegCoeffs<$ty> {
            type OutputScalar = $flt_ty;
            #[inline]
            fn get_transform() -> Matrix3<$flt_ty> {
                Matrix3::new([
                    0.299, 0.587, 0.114,
                    -0.168736, -0.331264, 0.5,
                    0.5, -0.418688, -0.081312]
                )
            }
            #[inline]
            fn get_shift() -> ($flt_ty, $flt_ty, $flt_ty) {
                let center_chan = ((<$ty as NormalChannelScalar>::max_bound() >> 1) + 1) as $flt_ty;
                (0.0,
                center_chan,
                center_chan)
            }
        }
    };
}

macro_rules! impl_jpeg_coeffs_float {
    ($ty:ident) => {
        impl YCbCrCoeffs<$ty> for JpegCoeffs<$ty> {
            type OutputScalar = $ty;

            #[inline]
            fn get_transform() -> Matrix3<$ty> {
                Matrix3::new([
                    0.299, 0.587, 0.114,
                    -0.168736, -0.331264, 0.5,
                    0.5, -0.418688, -0.081312]
                )
            }
            #[inline]
            fn get_shift() -> ($ty, $ty, $ty) {
                (0.0, 0.0, 0.0)
            }
        }
    }
}

impl_jpeg_coeffs_int!(u8, f32);
impl_jpeg_coeffs_int!(u16, f32);
impl_jpeg_coeffs_int!(u32, f32);
impl_jpeg_coeffs_float!(f32);
impl_jpeg_coeffs_float!(f64);

pub type YCbCrJpeg<T> = YCbCr<T, JpegCoeffs<T>>;

impl<T, Coeffs> YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    pub fn from_channels(y: T, cb: T, cr: T) -> Self {
        YCbCr {
            luma: PosNormalBoundedChannel::new(y),
            cb: NormalBoundedChannel::new(cb),
            cr: NormalBoundedChannel::new(cr),
            coeffs: PhantomData,
        }
    }

    impl_color_color_cast_square!(YCbCr {luma, cb, cr},
        chan_traits={NormalChannelScalar,PosNormalChannelScalar},
        phantom={coeffs}, types={Coeffs});

    pub fn luma(&self) -> T {
        self.luma.0.clone()
    }
    pub fn cb(&self) -> T {
        self.cb.0.clone()
    }
    pub fn cr(&self) -> T {
        self.cr.0.clone()
    }
    pub fn luma_mut(&mut self) -> &mut T {
        &mut self.luma.0
    }
    pub fn cb_mut(&mut self) -> &mut T {
        &mut self.cb.0
    }
    pub fn cr_mut(&mut self) -> &mut T {
        &mut self.cr.0
    }
    pub fn set_luma(&mut self, val: T) {
        self.luma.0 = val;
    }
    pub fn set_cb(&mut self, val: T) {
        self.cb.0 = val;
    }
    pub fn set_cr(&mut self, val: T) {
        self.cr.0 = val;
    }
}

impl<T, Coeffs> Color for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    type Tag = YCbCrTag;
    type ChannelsTuple = (T, T, T);

    #[inline]
    fn num_channels() -> u32 {
        3
    }

    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        YCbCr {
            luma: PosNormalBoundedChannel::new(values.0),
            cb: NormalBoundedChannel::new(values.1),
            cr: NormalBoundedChannel::new(values.2),
            coeffs: PhantomData,
        }
    }
    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.luma.0, self.cb.0, self.cr.0)
    }
}

impl<T, Coeffs> Invert for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    impl_color_invert!(YCbCr {luma, cb, cr}, phantom={coeffs});
}

impl<T, Coeffs> Bounded for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    impl_color_bounded!(YCbCr {luma, cb, cr}, phantom={coeffs});
}

impl<T, Coeffs> Lerp for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + Lerp + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    type Position = <T as Lerp>::Position;
    impl_color_lerp_square!(YCbCr {luma, cb, cr}, phantom={coeffs});
}

impl<T, Coeffs> Flatten for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);
    impl_color_from_slice_square!(YCbCr<T> {luma:PosNormalBoundedChannel - 0,
        cb:NormalBoundedChannel - 1, cr:NormalBoundedChannel - 2}, phantom={coeffs});
}
impl<T, Coeffs> approx::ApproxEq for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar + approx::ApproxEq,
          T::Epsilon: Clone,
          Coeffs: YCbCrCoeffs<T>
{
    impl_approx_eq!({luma, cb, cr});
}

impl<T, Coeffs> Default for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar + num::Zero,
          Coeffs: YCbCrCoeffs<T>
{
    impl_color_default!(YCbCr {luma:PosNormalBoundedChannel, cb:NormalBoundedChannel,
        cr:NormalBoundedChannel}, phantom={coeffs});
}

impl<T> fmt::Display for YCbCr<T>
    where T: NormalChannelScalar + PosNormalChannelScalar + fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "YCbCr({}, {}, {})", self.luma, self.cb, self.cr)
    }
}

impl<T, Coeffs> FromColor<Rgb<T>> for YCbCr<T, Coeffs>
    where T: NormalChannelScalar + PosNormalChannelScalar + num::NumCast + PosNormalChannelScalar,
          Coeffs: YCbCrCoeffs<T>
{
    fn from_color(from: &Rgb<T>) -> Self {
        let transform = Coeffs::get_transform();

        let (o1, o2, o3) = transform.transform_vector(from.clone().to_tuple());
        let (s1, s2, s3) = Coeffs::get_shift();
        YCbCr::from_channels(o1 + num::cast::<_, T>(s1).unwrap(),
                             o2 + num::cast::<_, T>(s2).unwrap(),
                             o3 + num::cast::<_, T>(s3).unwrap())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use rgb::Rgb;
    use convert::*;
    use color::*;

    #[test]
    fn test_construct() {
        let c1 = YCbCrJpeg::from_channels(0.75, 0.44, 0.21);
        assert_eq!(c1.luma(), 0.75);
        assert_eq!(c1.cb(), 0.44);
        assert_eq!(c1.cr(), 0.21);
        assert_eq!(c1.to_tuple(), (0.75, 0.44, 0.21));
        assert_eq!(YCbCrJpeg::from_tuple(c1.to_tuple()), c1);

        let c2 = YCbCrJpeg::from_channels(0.20, 0.21, 0.33);
        assert_eq!(c2.luma(), 0.20);
        assert_eq!(c2.cb(), 0.21);
        assert_eq!(c2.cr(), 0.33);
        assert_eq!(c2.to_tuple(), (0.20, 0.21, 0.33));
        assert_eq!(YCbCrJpeg::from_tuple(c2.to_tuple()), c2);
    }

    #[test]
    fn test_invert() {
        let c1 = YCbCrJpeg::from_channels(0.33, 0.55, 0.88);
        assert_relative_eq!(c1.invert().invert(), c1, epsilon=1e-6);
        assert_relative_eq!(c1.invert(),
            YCbCrJpeg::from_channels(0.67, -0.55, -0.88), epsilon=1e-6);

        let c2 = YCbCrJpeg::from_channels(0.2, -0.2, 1.0);
        assert_relative_eq!(c2.invert().invert(), c2, epsilon=1e-6);
        assert_relative_eq!(c2.invert(), YCbCrJpeg::from_channels(0.8, 0.2, -1.0));

        let c3 = YCbCrJpeg::from_channels(200u8, 170u8, 50u8);
        assert_eq!(c3.invert().invert(), c3);
        assert_eq!(c3.invert(), YCbCrJpeg::from_channels(55u8, 85u8, 205u8));
    }

    #[test]
    fn test_lerp() {
        let c1 = YCbCrJpeg::from_channels(0.7, -0.4, 0.7);
        let c2 = YCbCrJpeg::from_channels(0.3, 0.2, -0.8);
        assert_relative_eq!(c1.lerp(&c2, 0.0), c1);
        assert_relative_eq!(c1.lerp(&c2, 1.0), c2);
        assert_relative_eq!(c1.lerp(&c2, 0.5), YCbCrJpeg::from_channels(0.5, -0.1, -0.05));
        assert_relative_eq!(c1.lerp(&c2, 0.25), YCbCrJpeg::from_channels(0.6, -0.25, 0.325));

        let c3 = YCbCrJpeg::from_channels(100u8, 210, 25);
        let c4 = YCbCrJpeg::from_channels(200u8, 70, 150);
        assert_eq!(c3.lerp(&c4, 0.0), c3);
        assert_eq!(c3.lerp(&c4, 1.0), c4);
        assert_eq!(c3.lerp(&c4, 0.5), YCbCrJpeg::from_channels(150u8, 140u8, 87));
    }

    #[test]
    fn test_normalize() {
        let c1 = YCbCrJpeg::from_channels(-0.2, -1.3, 1.2);
        assert!(!c1.is_normalized());
        assert_eq!(c1.normalize(), YCbCrJpeg::from_channels(0.0, -1.0, 1.0));
        assert_eq!(c1.normalize().normalize(), c1.normalize());

        let c2 = YCbCrJpeg::from_channels(0.8, -0.8, 0.3);
        assert!(c2.is_normalized());
        assert_eq!(c2.normalize(), c2);
    }

    #[test]
    fn test_flatten() {
        let c1 = YCbCrJpeg::from_channels(0.2, -0.3, 0.45);
        assert_eq!(c1.as_slice(), &[0.2, -0.3, 0.45]);
        assert_eq!(YCbCrJpeg::from_slice(c1.as_slice()), c1);
    }

    #[test]
    fn test_from_rgb() {
        let c1 = Rgb::from_channels(255u8, 255, 255);
        let y1 = YCbCrJpeg::from_color(&c1);
        assert_eq!(y1.luma(), 255u8);
        assert_eq!(y1.cb(), 128);
        assert_eq!(y1.cr(), 128);

        let c2 = Rgb::from_channels(0.5, 0.5, 0.5);
        let y2 = YCbCrJpeg::from_color(&c2);
        assert_relative_eq!(y2, YCbCrJpeg::from_channels(0.5, 0.0, 0.0), epsilon=1e-6);
    }
}
<|endoftext|>


<commit_before>//! This module provides usefull traits that where deprecated in rust

// Note copied from the stdlib under MIT license

use std::ops::{ Add, Div, Mul, Rem, Sub };
use std::num::Int;
use num::{ Float, NumCast };
use std::marker::Reflect;

/// Num trait from old stdlib
pub trait Num: Zero + One + Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + Rem<Output=Self> + PartialEq<Self> { }
impl<A: Zero + One + Add<Output=A> + Sub<Output=A> + Mul<Output=A> + Div<Output=A> + Rem<Output=A> + PartialEq<A>> Num for A { }

/// Zero trait from old stdlib
pub trait Zero: Add<Output=Self> {
    /// Returns the zero value for T
    fn zero() -> Self;
    /// Returns true if zero.
    fn is_zero(&self) -> bool;
}

/// Returns the zero value for T
#[allow(unused)]
pub fn zero<T: Zero>() -> T { Zero::zero() }
macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            fn zero() -> $t { $v }
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}
zero_impl!(usize, 0usize);
zero_impl!(u8,   0u8);
zero_impl!(u16,  0u16);
zero_impl!(u32,  0u32);
zero_impl!(u64,  0u64);
zero_impl!(isize, 0isize);
zero_impl!(i8,  0i8);
zero_impl!(i16, 0i16);
zero_impl!(i32, 0i32);
zero_impl!(i64, 0i64);
zero_impl!(f32, 0.0f32);
zero_impl!(f64, 0.0f64);

/// Primitive trait from old stdlib, added max_value
pub trait Primitive: Copy + NumCast + Num + PartialOrd<Self> + Clone + Reflect {
    /// The maximum value of primitive.
    fn max_value() -> Self;
}

impl Primitive for usize {
    fn max_value() -> usize { Int::max_value() }
}
impl Primitive for u8 {
    fn max_value() -> u8 { Int::max_value() }
}
impl Primitive for u16 {
    fn max_value() -> u16 { Int::max_value() }
}
impl Primitive for u32 {
    fn max_value() -> u32 { Int::max_value() }
}
impl Primitive for u64 {
    fn max_value() -> u64 { Int::max_value() }
}
impl Primitive for isize {
    fn max_value() -> isize { Int::max_value() }
}
impl Primitive for i8 {
    fn max_value() -> i8 { Int::max_value() }
}
impl Primitive for i16 {
    fn max_value() -> i16 { Int::max_value() }
}
impl Primitive for i32 {
    fn max_value() -> i32 { Int::max_value() }
}
impl Primitive for i64 {
    fn max_value() -> i64 { Int::max_value() }
}
impl Primitive for f32 {
    fn max_value() -> f32 { Float::max_value() }
}
impl Primitive for f64 {
    fn max_value() -> f64 { Float::max_value() }
}

/// One trait from old stdlib, added max_value
pub trait One: Mul<Output=Self> {
    /// Returns the unit value of Self
    fn one() -> Self;
}
/// Returns the unit value of T
#[allow(unused)]
pub fn one<T: One>() -> T { One::one() }
macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            fn one() -> $t { $v }
        }
    }
}
one_impl!(usize, 1usize);
one_impl!(u8,  1u8);
one_impl!(u16, 1u16);
one_impl!(u32, 1u32);
one_impl!(u64, 1u64);
one_impl!(isize, 1isize);
one_impl!(i8,  1i8);
one_impl!(i16, 1i16);
one_impl!(i32, 1i32);
one_impl!(i64, 1i64);
one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64);
<commit_msg>Got rid of `std::num::Int`<commit_after>//! This module provides usefull traits that where deprecated in rust

// Note copied from the stdlib under MIT license

use std::ops::{ Add, Div, Mul, Rem, Sub };
use num::{ Float, NumCast };
use std::marker::Reflect;

/// Num trait from old stdlib
pub trait Num: Zero + One + Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + Rem<Output=Self> + PartialEq<Self> { }
impl<A: Zero + One + Add<Output=A> + Sub<Output=A> + Mul<Output=A> + Div<Output=A> + Rem<Output=A> + PartialEq<A>> Num for A { }

/// Zero trait from old stdlib
pub trait Zero: Add<Output=Self> {
    /// Returns the zero value for T
    fn zero() -> Self;
    /// Returns true if zero.
    fn is_zero(&self) -> bool;
}

/// Returns the zero value for T
#[allow(unused)]
pub fn zero<T: Zero>() -> T { Zero::zero() }
macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            fn zero() -> $t { $v }
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}
zero_impl!(usize, 0usize);
zero_impl!(u8,   0u8);
zero_impl!(u16,  0u16);
zero_impl!(u32,  0u32);
zero_impl!(u64,  0u64);
zero_impl!(isize, 0isize);
zero_impl!(i8,  0i8);
zero_impl!(i16, 0i16);
zero_impl!(i32, 0i32);
zero_impl!(i64, 0i64);
zero_impl!(f32, 0.0f32);
zero_impl!(f64, 0.0f64);

/// Primitive trait from old stdlib, added max_value
pub trait Primitive: Copy + NumCast + Num + PartialOrd<Self> + Clone + Reflect {
    /// The maximum value of primitive.
    fn max_value() -> Self;
}

impl Primitive for usize {
    fn max_value() -> usize { usize::max_value() }
}
impl Primitive for u8 {
    fn max_value() -> u8 { u8::max_value() }
}
impl Primitive for u16 {
    fn max_value() -> u16 { u16::max_value() }
}
impl Primitive for u32 {
    fn max_value() -> u32 { u32::max_value() }
}
impl Primitive for u64 {
    fn max_value() -> u64 { u64::max_value() }
}
impl Primitive for isize {
    fn max_value() -> isize { isize::max_value() }
}
impl Primitive for i8 {
    fn max_value() -> i8 { i8::max_value() }
}
impl Primitive for i16 {
    fn max_value() -> i16 { i16::max_value() }
}
impl Primitive for i32 {
    fn max_value() -> i32 { i32::max_value() }
}
impl Primitive for i64 {
    fn max_value() -> i64 { i64::max_value() }
}
impl Primitive for f32 {
    fn max_value() -> f32 { Float::max_value() }
}
impl Primitive for f64 {
    fn max_value() -> f64 { Float::max_value() }
}

/// One trait from old stdlib, added max_value
pub trait One: Mul<Output=Self> {
    /// Returns the unit value of Self
    fn one() -> Self;
}
/// Returns the unit value of T
#[allow(unused)]
pub fn one<T: One>() -> T { One::one() }
macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            fn one() -> $t { $v }
        }
    }
}
one_impl!(usize, 1usize);
one_impl!(u8,  1u8);
one_impl!(u16, 1u16);
one_impl!(u32, 1u32);
one_impl!(u64, 1u64);
one_impl!(isize, 1isize);
one_impl!(i8,  1i8);
one_impl!(i16, 1i16);
one_impl!(i32, 1i32);
one_impl!(i64, 1i64);
one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64);
<|endoftext|>


<commit_before>extern crate nom_sql;

use std::fs::File;
use std::path::Path;
use std::io::Read;

fn parse_queryset(queries: Vec<String>) -> (i32, i32) {
    let mut parsed_ok = Vec::new();
    let mut parsed_err = 0;
    for query in queries.iter() {
        println!("Trying to parse '{}': ", &query);
        match nom_sql::parser::parse_query(&query) {
            Ok(_) => {
                println!("ok");
                parsed_ok.push(query);
            }
            Err(_) => {
                println!("failed");
                parsed_err += 1;
            }
        }
    }

    println!("Parsing failed: {} queries", parsed_err);
    println!("Parsed successfully: {} queries", parsed_ok.len());
    println!("\nSuccessfully parsed queries:");
    for q in parsed_ok.iter() {
        println!("{:?}", q);
    }

    (parsed_ok.len() as i32, parsed_err)
}

fn test_queries_from_file(f: &Path, name: &str) -> Result<i32, i32> {
    let mut f = File::open(f).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<String> = s.lines()
        .filter(|l| !l.is_empty() && !l.starts_with("#"))
        .map(|l| if !(l.ends_with("\n") || l.ends_with(";")) {
            String::from(l) + "\n"
        } else {
            String::from(l)
        })
        .collect();
    println!("Loaded {} {} queries", lines.len(), name);

    // Try parsing them all
    let (ok, _) = parse_queryset(lines);

    // For the moment, we're always good
    Ok(ok)
}

#[test]
fn hotcrp_queries() {
    assert!(test_queries_from_file(Path::new("tests/hotcrp-queries.txt"), "HotCRP").is_ok());
}

#[test]
fn hyrise_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/hyrise-test-queries.txt"), "HyRise").is_ok());
}

#[test]
fn tpcw_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/tpc-w-queries.txt"), "TPC-W").is_ok());
}

#[test]
fn finkelstein82_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/finkelstein82.txt"), "Finkelstein 1982")
        .is_ok())
}

#[test]
fn mediawiki_schema() {
    let mut f = File::open(Path::new("tests/mediawiki-schema.txt")).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<&str> = s.lines()
        .map(str::trim)
        .filter(|l| {
            !l.is_empty() && !l.starts_with("#") && !l.starts_with("--") && !l.starts_with("DROP")
        })
        .collect();
    let mut q = String::new();
    let mut queries = Vec::new();
    for l in lines {
        if !l.ends_with(";") {
            q.push_str(l);
        } else {
            // end of query
            q.push_str(l);
            queries.push(q.clone());
            q = String::new();
        }
    }
    println!("Loaded {} table definitions", queries.len());

    // Try parsing them all
    let (ok, fail) = parse_queryset(queries);

    // There are 17 CREATE TABLE queries in the schema
    assert_eq!(ok, 17);
    assert_eq!(fail, 0);
}
<commit_msg>Add TPC-W table schema unit test<commit_after>extern crate nom_sql;

use std::fs::File;
use std::path::Path;
use std::io::Read;

fn parse_queryset(queries: Vec<String>) -> (i32, i32) {
    let mut parsed_ok = Vec::new();
    let mut parsed_err = 0;
    for query in queries.iter() {
        println!("Trying to parse '{}': ", &query);
        match nom_sql::parser::parse_query(&query) {
            Ok(_) => {
                println!("ok");
                parsed_ok.push(query);
            }
            Err(_) => {
                println!("failed");
                parsed_err += 1;
            }
        }
    }

    println!("Parsing failed: {} queries", parsed_err);
    println!("Parsed successfully: {} queries", parsed_ok.len());
    println!("\nSuccessfully parsed queries:");
    for q in parsed_ok.iter() {
        println!("{:?}", q);
    }

    (parsed_ok.len() as i32, parsed_err)
}

fn test_queries_from_file(f: &Path, name: &str) -> Result<i32, i32> {
    let mut f = File::open(f).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<String> = s.lines()
        .filter(|l| !l.is_empty() && !l.starts_with("#"))
        .map(|l| if !(l.ends_with("\n") || l.ends_with(";")) {
            String::from(l) + "\n"
        } else {
            String::from(l)
        })
        .collect();
    println!("Loaded {} {} queries", lines.len(), name);

    // Try parsing them all
    let (ok, _) = parse_queryset(lines);

    // For the moment, we're always good
    Ok(ok)
}

#[test]
fn hotcrp_queries() {
    assert!(test_queries_from_file(Path::new("tests/hotcrp-queries.txt"), "HotCRP").is_ok());
}

#[test]
fn hyrise_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/hyrise-test-queries.txt"), "HyRise").is_ok());
}

#[test]
fn tpcw_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/tpc-w-queries.txt"), "TPC-W").is_ok());
}

#[test]
fn tpcw_test_tables() {
    let res = test_queries_from_file(Path::new("tests/tpc-w-tables.txt"), "TPC-W tables");
    assert!(res.is_ok());
    // There are 10 tables
    assert_eq!(res.unwrap(), 10);
}

#[test]
fn finkelstein82_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/finkelstein82.txt"), "Finkelstein 1982")
        .is_ok())
}

#[test]
fn mediawiki_schema() {
    let mut f = File::open(Path::new("tests/mediawiki-schema.txt")).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<&str> = s.lines()
        .map(str::trim)
        .filter(|l| {
            !l.is_empty() && !l.starts_with("#") && !l.starts_with("--") && !l.starts_with("DROP")
        })
        .collect();
    let mut q = String::new();
    let mut queries = Vec::new();
    for l in lines {
        if !l.ends_with(";") {
            q.push_str(l);
        } else {
            // end of query
            q.push_str(l);
            queries.push(q.clone());
            q = String::new();
        }
    }
    println!("Loaded {} table definitions", queries.len());

    // Try parsing them all
    let (ok, fail) = parse_queryset(queries);

    // There are 17 CREATE TABLE queries in the schema
    assert_eq!(ok, 17);
    assert_eq!(fail, 0);
}
<|endoftext|>


<commit_before>extern crate tvdb;
extern crate rand;

use tvdb::{Tvdb, EpisodeId, TvdbResult, TvdbError};

const APIKEY: &'static str = "0629B785CE550C8D";

#[test]
fn search() {
    return;
    let api = Tvdb::new(APIKEY.to_owned());
    let sr = api.search("scrubs");
    assert!(sr.ok().unwrap().data[0].series_name == "Scrubs");
}

#[test]
fn nonexist() {
    let api = Tvdb::new(APIKEY);
    let sr = api.search("ladlkgdklfgsdfglk");
    assert!(sr.is_err());
}

#[test]
fn lookup_by_epid(){
    let api = Tvdb::new(APIKEY);
    api.login();
    let ep = api.episode(EpisodeId::new(184603, "en"));
    println!("Episode: {:?}", ep);
    assert!(ep.unwrap().episode_name == "My Mentor");
}

#[test]
fn lookup_by_u32(){
    let api = Tvdb::new(APIKEY);
    api.login().unwrap();
    let ep = api.episode(184603);
    println!("Episode; {:?}", ep);
    assert!(ep.unwrap().episode_name == "My Mentor");
}

#[test]
fn random_series(){
    // Opening a bunch of ~random series to check for panicing
    use rand::{Rng, SeedableRng, StdRng};

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);
    for _ in 1..10{
        let rid = rng.gen_range::<u32>(1, 20000);
        println!("Getting series {}", rid);

        let api = Tvdb::new(APIKEY);
        let ep = api.episode(EpisodeId::new(rid, "en"));
        println!("{:?}", ep);
        match ep{
            Ok(ep) => println!("{}", ep.episode_name),
            Err(e) => println!("{:?}", e),
        }
    }
}

#[derive(Debug,Clone)]
struct DummyRequestClient;

impl DummyRequestClient{
    pub fn new() -> DummyRequestClient{
        return DummyRequestClient{};
    }
}
use tvdb::RequestClient;
impl RequestClient for DummyRequestClient{
    fn get_url(&self, url: &str, jwt_token: Option<String>) -> TvdbResult<String>{
        return Err(TvdbError::CommunicationError{reason: "Fake error!".into()});
    }
}

#[test]
fn custom_http_client() {
    let c = DummyRequestClient::new();

    let mut api = Tvdb::new(APIKEY);
    api.set_http_client(&c);

    let result = api.search("scrubs");
    println!("{:?}", result);

    match result{
        Ok(_) => panic!("Expected error"),
        Err(e) => (
            match e {
                TvdbError::CommunicationError{reason: _} => (),
                _ => panic!("Unexpected"),
            }
        ),
    }
}
<commit_msg>Fix unchecked login call<commit_after>extern crate tvdb;
extern crate rand;

use tvdb::{Tvdb, EpisodeId, TvdbResult, TvdbError};

const APIKEY: &'static str = "0629B785CE550C8D";

#[test]
fn search() {
    return;
    let api = Tvdb::new(APIKEY.to_owned());
    let sr = api.search("scrubs");
    assert!(sr.ok().unwrap().data[0].series_name == "Scrubs");
}

#[test]
fn nonexist() {
    let api = Tvdb::new(APIKEY);
    let sr = api.search("ladlkgdklfgsdfglk");
    assert!(sr.is_err());
}

#[test]
fn lookup_by_epid(){
    let api = Tvdb::new(APIKEY);
    api.login().unwrap();
    let ep = api.episode(EpisodeId::new(184603, "en"));
    println!("Episode: {:?}", ep);
    assert!(ep.unwrap().episode_name == "My Mentor");
}

#[test]
fn lookup_by_u32(){
    let api = Tvdb::new(APIKEY);
    api.login().unwrap();
    let ep = api.episode(184603);
    println!("Episode; {:?}", ep);
    assert!(ep.unwrap().episode_name == "My Mentor");
}

#[test]
fn random_series(){
    // Opening a bunch of ~random series to check for panicing
    use rand::{Rng, SeedableRng, StdRng};

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);
    for _ in 1..10{
        let rid = rng.gen_range::<u32>(1, 20000);
        println!("Getting series {}", rid);

        let api = Tvdb::new(APIKEY);
        let ep = api.episode(EpisodeId::new(rid, "en"));
        println!("{:?}", ep);
        match ep{
            Ok(ep) => println!("{}", ep.episode_name),
            Err(e) => println!("{:?}", e),
        }
    }
}

#[derive(Debug,Clone)]
struct DummyRequestClient;

impl DummyRequestClient{
    pub fn new() -> DummyRequestClient{
        return DummyRequestClient{};
    }
}
use tvdb::RequestClient;
impl RequestClient for DummyRequestClient{
    fn get_url(&self, url: &str, jwt_token: Option<String>) -> TvdbResult<String>{
        return Err(TvdbError::CommunicationError{reason: "Fake error!".into()});
    }
}

#[test]
fn custom_http_client() {
    let c = DummyRequestClient::new();

    let mut api = Tvdb::new(APIKEY);
    api.set_http_client(&c);

    let result = api.search("scrubs");
    println!("{:?}", result);

    match result{
        Ok(_) => panic!("Expected error"),
        Err(e) => (
            match e {
                TvdbError::CommunicationError{reason: _} => (),
                _ => panic!("Unexpected"),
            }
        ),
    }
}
<|endoftext|>


<commit_before>// TODO: COPYRIGHT, USE & AUTHORS
// TODO: RUST DOCS!

extern crate rust_monster;
#[macro_use]
extern crate log;
extern crate env_logger;
#[cfg(test)]
mod tests
{
    use rust_monster::ga::ga_core::{GeneticAlgorithm, GASolution, GAFactory, DEBUG_FLAG};
    use rust_monster::ga::ga_population::{GAPopulation, GAPopulationSortOrder, GAPopulationSortBasis};
    use rust_monster::ga::ga_simple::{SimpleGeneticAlgorithm, SimpleGeneticAlgorithmCfg};

    use env_logger;
    use std::sync::{Once, ONCE_INIT};

    static INIT: Once = ONCE_INIT;
    const VAL: f32 = 3.14159;

    struct TestSolution
    {
        fitness: f32
    }
    impl GASolution for TestSolution
    {
        fn new() -> TestSolution
        {
            TestSolution{ fitness: VAL }
        }

        fn clone(&self) -> Self { TestSolution::new() }
        fn evaluate(&mut self) -> f32 { self.fitness }
    #[allow(unused_variables)]
        fn crossover(&self, other : &Self) -> Self { TestSolution::new() }
    #[allow(unused_variables)]
        fn mutate(&mut self, pm : f32) {}
        fn fitness(&self) -> f32 { (1.0 / self.fitness) }
        fn score(&self) -> f32 { self.fitness }
    }

    #[allow(dead_code)]
    struct TestFactory
    {
        starting_fitness: f32
    }
    impl GAFactory<TestSolution> for TestFactory
    {
        fn initial_population(&mut self) -> GAPopulation<TestSolution> {
            GAPopulation::new(vec![TestSolution { fitness: self.starting_fitness }], GAPopulationSortOrder::HighIsBest)
        }
    }

////////////////////////////////////////
// Utility functions

    fn ga_test_setup()
    {
        // This is only called once, works nicely as a Setup mechanism
        // TODO: Can we do somethign similar for teardown?
        INIT.call_once(||{
            env_logger::init().unwrap();
        });
    }

    fn simple_ga_validation(sga:&mut SimpleGeneticAlgorithm<TestSolution>)
    {
        sga.initialize();
        assert_eq!(sga.step(), 1);
        assert_eq!(sga.done(), false);
        assert_eq!(sga.population().size(), 1);
        assert_eq!(sga.population().best().score(), VAL);
    }

////////////////////////////////////////
// Tests

    #[test]
    fn init_test_with_initial_population()
    {
        ga_test_setup();
        let initial_population = GAPopulation::new(vec![TestSolution { fitness: VAL}], GAPopulationSortOrder::HighIsBest);
        let mut ga : SimpleGeneticAlgorithm<TestSolution> =
                     SimpleGeneticAlgorithm::new(SimpleGeneticAlgorithmCfg {
                                                   d_seed : 1,
                                                   flags : DEBUG_FLAG,
                                                   max_generations: 100,
                                                   ..Default::default()
                                                 },
                                                 None,
                                                 Some(initial_population)
                                                 );
        simple_ga_validation(&mut ga);
    }

    #[test]
    fn init_test_with_factory()
    {
        ga_test_setup();
        let mut factory = TestFactory { starting_fitness: VAL };
        let mut ga : SimpleGeneticAlgorithm<TestSolution> =
                     SimpleGeneticAlgorithm::new(SimpleGeneticAlgorithmCfg {
                                                   d_seed : 1,
                                                   flags : DEBUG_FLAG,
                                                   max_generations: 100,
                                                   ..Default::default()
                                                 },
                                                 Some(&mut factory as &mut GAFactory<TestSolution>),
                                                 None
                                                 );
        simple_ga_validation(&mut ga);
    }

    #[test]
    #[should_panic]
    #[allow(unused_variables)]
    fn init_test_missing_args()
    {
        ga_test_setup();
        let ga : SimpleGeneticAlgorithm<TestSolution> =
                 SimpleGeneticAlgorithm::new(SimpleGeneticAlgorithmCfg {
                                               d_seed : 1,
                                               flags : DEBUG_FLAG,
                                               max_generations: 100,
                                               ..Default::default()
                                             },
                                             None,
                                             None
                                             );
        // Not reached
    }

    #[test]
    #[should_panic]
    fn init_test_empty_initial_pop()
    {
        ga_test_setup();
        let empty_initial_population : GAPopulation<TestSolution> = GAPopulation::new(vec![], GAPopulationSortOrder::HighIsBest);
        let mut ga : SimpleGeneticAlgorithm<TestSolution> =
                     SimpleGeneticAlgorithm::new(SimpleGeneticAlgorithmCfg {
                                                   d_seed : 1,
                                                   flags : DEBUG_FLAG,
                                                   max_generations: 100,
                                                   ..Default::default()
                                                 },
                                                 None,
                                                 Some(empty_initial_population)
                                                 );
        ga.initialize()
        //Not reached
    }

    // This test should live in the ga_population file directly,
    // but since it requires GASolution objects it is here for now.
    // Maybe we could use a Mocking library.
    // TODO: This doesn't go here.
    #[test]
    fn test_sort_population()
    {
        let f = VAL;
        let f_m = VAL - 1.0;
        let i_f = 1.0 / f;
        let i_f_m = 1.0 / f_m;

        let mut population = GAPopulation::new(vec![TestSolution { fitness: f }, TestSolution { fitness: f_m }], GAPopulationSortOrder::HighIsBest);
        population.sort();

        //TestSolution's Fitness is the inverse of the Score (F = 1/S)
        assert_eq!(population.individual(0, GAPopulationSortBasis::Raw).score(), f);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Raw).score(), f_m);
        assert_eq!(population.individual(0, GAPopulationSortBasis::Scaled).fitness(), i_f_m);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Scaled).fitness(), i_f);
    }
}
<commit_msg>Add RankSelector test.<commit_after>// TODO: COPYRIGHT, USE & AUTHORS
// TODO: RUST DOCS!

extern crate rust_monster;
#[macro_use]
extern crate log;
extern crate env_logger;
#[cfg(test)]
mod tests
{
    use rust_monster::ga::ga_core::{GeneticAlgorithm, GASolution, GAFactory, DEBUG_FLAG};
    use rust_monster::ga::ga_population::{GAPopulation, GAPopulationSortOrder, GAPopulationSortBasis};
    use rust_monster::ga::ga_simple::{SimpleGeneticAlgorithm, SimpleGeneticAlgorithmCfg};
    use rust_monster::ga::ga_selectors::{GASelector, GARankSelector};

    use env_logger;
    use std::sync::{Once, ONCE_INIT};

    static INIT: Once = ONCE_INIT;
    const VAL: f32 = 3.14159;

    struct TestSolution
    {
        fitness: f32
    }
    impl GASolution for TestSolution
    {
        fn new() -> TestSolution
        {
            TestSolution{ fitness: VAL }
        }

        fn clone(&self) -> Self { TestSolution::new() }
        fn evaluate(&mut self) -> f32 { self.fitness }
    #[allow(unused_variables)]
        fn crossover(&self, other : &Self) -> Self { TestSolution::new() }
    #[allow(unused_variables)]
        fn mutate(&mut self, pm : f32) {}
        fn fitness(&self) -> f32 { (1.0 / self.fitness) }
        fn score(&self) -> f32 { self.fitness }
    }

    #[allow(dead_code)]
    struct TestFactory
    {
        starting_fitness: f32
    }
    impl GAFactory<TestSolution> for TestFactory
    {
        fn initial_population(&mut self) -> GAPopulation<TestSolution> {
            GAPopulation::new(vec![TestSolution { fitness: self.starting_fitness }], GAPopulationSortOrder::HighIsBest)
        }
    }

////////////////////////////////////////
// Utility functions

    fn ga_test_setup()
    {
        // This is only called once, works nicely as a Setup mechanism
        // TODO: Can we do somethign similar for teardown?
        INIT.call_once(||{
            env_logger::init().unwrap();
        });
    }

    fn simple_ga_validation(sga:&mut SimpleGeneticAlgorithm<TestSolution>)
    {
        sga.initialize();
        assert_eq!(sga.step(), 1);
        assert_eq!(sga.done(), false);
        assert_eq!(sga.population().size(), 1);
        assert_eq!(sga.population().best(GAPopulationSortBasis::Scaled).score(), VAL);
    }

////////////////////////////////////////
// Tests

    #[test]
    fn init_test_with_initial_population()
    {
        ga_test_setup();
        let initial_population = GAPopulation::new(vec![TestSolution { fitness: VAL}], GAPopulationSortOrder::HighIsBest);
        let mut ga : SimpleGeneticAlgorithm<TestSolution> =
                     SimpleGeneticAlgorithm::new(SimpleGeneticAlgorithmCfg {
                                                   d_seed : 1,
                                                   flags : DEBUG_FLAG,
                                                   max_generations: 100,
                                                   ..Default::default()
                                                 },
                                                 None,
                                                 Some(initial_population)
                                                 );
        simple_ga_validation(&mut ga);
    }

    #[test]
    fn init_test_with_factory()
    {
        ga_test_setup();
        let mut factory = TestFactory { starting_fitness: VAL };
        let mut ga : SimpleGeneticAlgorithm<TestSolution> =
                     SimpleGeneticAlgorithm::new(SimpleGeneticAlgorithmCfg {
                                                   d_seed : 1,
                                                   flags : DEBUG_FLAG,
                                                   max_generations: 100,
                                                   ..Default::default()
                                                 },
                                                 Some(&mut factory as &mut GAFactory<TestSolution>),
                                                 None
                                                 );
        simple_ga_validation(&mut ga);
    }

    #[test]
    #[should_panic]
    #[allow(unused_variables)]
    fn init_test_missing_args()
    {
        ga_test_setup();
        let ga : SimpleGeneticAlgorithm<TestSolution> =
                 SimpleGeneticAlgorithm::new(SimpleGeneticAlgorithmCfg {
                                               d_seed : 1,
                                               flags : DEBUG_FLAG,
                                               max_generations: 100,
                                               ..Default::default()
                                             },
                                             None,
                                             None
                                             );
        // Not reached
    }

    #[test]
    #[should_panic]
    fn init_test_empty_initial_pop()
    {
        ga_test_setup();
        let empty_initial_population : GAPopulation<TestSolution> = GAPopulation::new(vec![], GAPopulationSortOrder::HighIsBest);
        let mut ga : SimpleGeneticAlgorithm<TestSolution> =
                     SimpleGeneticAlgorithm::new(SimpleGeneticAlgorithmCfg {
                                                   d_seed : 1,
                                                   flags : DEBUG_FLAG,
                                                   max_generations: 100,
                                                   ..Default::default()
                                                 },
                                                 None,
                                                 Some(empty_initial_population)
                                                 );
        ga.initialize()
        //Not reached
    }

    // This test should live in the ga_population file directly,
    // but since it requires GASolution objects it is here for now.
    // Maybe we could use a Mocking library.
    // TODO: This doesn't go here.
    #[test]
    fn test_sort_population()
    {
        let f = VAL;
        let f_m = VAL - 1.0;
        let i_f = 1.0 / f;
        let i_f_m = 1.0 / f_m;

        let mut population = GAPopulation::new(vec![TestSolution { fitness: f }, TestSolution { fitness: f_m }], GAPopulationSortOrder::HighIsBest);
        population.sort();

        //TestSolution's Fitness is the inverse of the Score (F = 1/S)
        assert_eq!(population.individual(0, GAPopulationSortBasis::Raw).score(), f);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Raw).score(), f_m);
        assert_eq!(population.individual(0, GAPopulationSortBasis::Scaled).fitness(), i_f_m);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Scaled).fitness(), i_f);
    }

    #[test]
    #[allow(unused_variables)]
    fn test_rank_selector()
    {
        let f = VAL;
        let f_m = VAL - 1.0;
        let i_f = 1.0 / f;
        let i_f_m = 1.0 / f_m;

        let mut population
          = GAPopulation::new(vec![TestSolution { fitness: f },
                                   TestSolution { fitness: f_m }],
                              GAPopulationSortOrder::HighIsBest);

        let mut rank_selector = GARankSelector { population: &mut population };

        // Best Raw score is that of 1st solution.
        assert_eq!(rank_selector.select(GAPopulationSortBasis::Raw).score(), f);
        // Best Scaled score is that of 2nd solution (because fitness is inverse of score). Weird. In this case, LowIsBest.
        assert_eq!(rank_selector.select(GAPopulationSortBasis::Scaled).fitness(), i_f_m);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A definition of `BinaryValue` trait and implementations for common types.

use std::{borrow::Cow, io::Read};

use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
use chrono::{DateTime, NaiveDateTime, Utc};
use failure::{self, format_err};
use rust_decimal::Decimal;
use uuid::Uuid;

use super::UniqueHash;
use exonum_crypto::{Hash, PublicKey};

/// A type that can be (de)serialized as a value in the blockchain storage.
///
/// If you need to implement `BinaryValue` for your types, use little-endian encoding
/// for integer types for compatibility with modern architectures.
///
/// # Examples
///
/// Implementing `BinaryValue` for the type:
///
/// ```
/// use std::{borrow::Cow, io::{Read, Write}};
/// use byteorder::{LittleEndian, ReadBytesExt, ByteOrder};
/// use failure;
/// use exonum_merkledb::BinaryValue;
///
/// #[derive(Clone)]
/// struct Data {
///     a: i16,
///     b: u32,
/// }
///
/// impl BinaryValue for Data {
///     fn to_bytes(&self) -> Vec<u8> {
///         let mut buf = vec![0_u8; 6];
///         LittleEndian::write_i16(&mut buf[0..2], self.a);
///         LittleEndian::write_u32(&mut buf[2..6], self.b);
///         buf
///     }
///
///     fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
///         let mut buf = bytes.as_ref();
///         let a = buf.read_i16::<LittleEndian>()?;
///         let b = buf.read_u32::<LittleEndian>()?;
///         Ok(Self { a, b })
///     }
/// }
/// # fn main() {}
/// ```
pub trait BinaryValue: Sized {
    /// Serializes the given value to the vector of bytes.
    fn to_bytes(&self) -> Vec<u8>;
    /// TODO
    fn into_bytes(self) -> Vec<u8> {
        self.to_bytes()
    }
    /// Deserializes the value from the given bytes array.
    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error>;
}

macro_rules! impl_binary_form_scalar {
    ($type:tt, $read:ident) => {
        impl BinaryValue for $type {
            fn to_bytes(&self) -> Vec<u8> {
                vec![*self as u8]
            }

            fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                bytes.as_ref().$read().map_err(From::from)
            }
        }

        impl UniqueHash for $type {}
    };
    ($type:tt, $write:ident, $read:ident, $len:expr) => {
        impl BinaryValue for $type {
            fn to_bytes(&self) -> Vec<u8> {
                let mut v = vec![0; $len];
                LittleEndian::$write(&mut v, *self);
                v
            }

            fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                bytes.as_ref().$read::<LittleEndian>().map_err(From::from)
            }
        }

        impl UniqueHash for $type {}
    };
}

// Unsigned scalar types
impl_binary_form_scalar! { u8,  read_u8 }
impl_binary_form_scalar! { u16, write_u16, read_u16, 2 }
impl_binary_form_scalar! { u32, write_u32, read_u32, 4 }
impl_binary_form_scalar! { u64, write_u64, read_u64, 8 }
// Signed scalar types
impl_binary_form_scalar! { i8,  read_i8 }
impl_binary_form_scalar! { i16, write_i16, read_i16, 2 }
impl_binary_form_scalar! { i32, write_i32, read_i32, 4 }
impl_binary_form_scalar! { i64, write_i64, read_i64, 8 }

/// No-op implementation.
impl BinaryValue for () {
    fn to_bytes(&self) -> Vec<u8> {
        Vec::default()
    }

    fn from_bytes(_bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Ok(())
    }
}

impl UniqueHash for () {}

impl BinaryValue for bool {
    fn to_bytes(&self) -> Vec<u8> {
        vec![*self as u8]
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let value = bytes.as_ref();
        assert_eq!(value.len(), 1);

        match value[0] {
            0 => Ok(false),
            1 => Ok(true),
            value => Err(format_err!("Invalid value for bool: {}", value)),
        }
    }
}

impl UniqueHash for bool {}

impl BinaryValue for Vec<u8> {
    fn to_bytes(&self) -> Vec<u8> {
        self.clone()
    }

    fn into_bytes(self) -> Vec<u8> {
        self
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Ok(bytes.into_owned())
    }
}

impl UniqueHash for Vec<u8> {}

impl BinaryValue for String {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_owned()
    }

    fn into_bytes(self) -> Vec<u8> {
        Self::into_bytes(self)
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_utf8(bytes.into_owned()).map_err(From::from)
    }
}

impl UniqueHash for String {}

impl BinaryValue for Hash {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).ok_or_else(|| format_err!("Unable to decode value"))
    }
}

impl BinaryValue for PublicKey {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).ok_or_else(|| format_err!("Unable to decode value"))
    }
}

impl UniqueHash for PublicKey {}

// FIXME Maybe we should remove this implementations

impl BinaryValue for DateTime<Utc> {
    fn to_bytes(&self) -> Vec<u8> {
        let secs = self.timestamp();
        let nanos = self.timestamp_subsec_nanos();

        let mut buffer = vec![0; 12];
        LittleEndian::write_i64(&mut buffer[0..8], secs);
        LittleEndian::write_u32(&mut buffer[8..12], nanos);
        buffer
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut value = bytes.as_ref();
        let secs = value.read_i64::<LittleEndian>()?;
        let nanos = value.read_u32::<LittleEndian>()?;
        Ok(Self::from_utc(
            NaiveDateTime::from_timestamp(secs, nanos),
            Utc,
        ))
    }
}

impl UniqueHash for DateTime<Utc> {}

impl BinaryValue for Uuid {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Uuid {}

impl BinaryValue for Decimal {
    fn to_bytes(&self) -> Vec<u8> {
        self.serialize().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut value = bytes.as_ref();
        let mut buf: [u8; 16] = [0; 16];
        value.read_exact(&mut buf)?;
        Ok(Self::deserialize(buf))
    }
}

impl UniqueHash for Decimal {}

#[cfg(test)]
mod tests {
    use std::fmt::Debug;
    use std::str::FromStr;

    use chrono::Duration;

    use super::*;

    fn assert_round_trip_eq<T: BinaryValue + PartialEq + Debug>(values: &[T]) {
        for value in values {
            let bytes = value.to_bytes();
            assert_eq!(
                *value,
                <T as BinaryValue>::from_bytes(bytes.into()).unwrap()
            );
        }
    }

    macro_rules! impl_test_binary_form_scalar_unsigned {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    macro_rules! impl_test_binary_form_scalar_signed {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), -1, 0, 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    // Impl tests for unsigned scalar types
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u8,  u8 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u32, u32 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u16, u16 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u64, u64 }

    // Impl tests for signed scalar types
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i8,  i8 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i16, i16 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i32, i32 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i64, i64 }

    // Tests for the other types

    #[test]
    fn test_binary_form_vec_u8() {
        let values = [vec![], vec![1], vec![1, 2, 3], vec![255; 100]];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_bool_correct() {
        let values = [true, false];
        assert_round_trip_eq(&values);
    }

    #[test]
    #[should_panic(expected = "Invalid value for bool: 2")]
    fn test_binary_form_bool_incorrect() {
        let bytes = 2_u8.to_bytes();
        <bool as BinaryValue>::from_bytes(bytes.into()).unwrap();
    }

    #[test]
    fn test_binary_form_string() {
        let values: Vec<_> = ["", "e", "2", "hello"]
            .iter()
            .map(|v| v.to_string())
            .collect();
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_datetime() {
        use chrono::TimeZone;

        let times = [
            Utc.timestamp(0, 0),
            Utc.timestamp(13, 23),
            Utc::now(),
            Utc::now() + Duration::seconds(17) + Duration::nanoseconds(15),
            Utc.timestamp(0, 999_999_999),
            Utc.timestamp(0, 1_500_000_000), // leap second
        ];
        assert_round_trip_eq(&times);
    }

    #[test]
    fn test_binary_form_uuid() {
        let values = [
            Uuid::nil(),
            Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
            Uuid::parse_str("0000002a-000c-0005-0c03-0938362b0809").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_decimal() {
        let values = [
            Decimal::from_str("3.14").unwrap(),
            Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28),
            Decimal::new(9497628354687268, 12),
            Decimal::from_str("0").unwrap(),
            Decimal::from_str("-0.000000000000000000019").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }
}
<commit_msg>Update documentation<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A definition of `BinaryValue` trait and implementations for common types.

use std::{borrow::Cow, io::Read};

use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
use chrono::{DateTime, NaiveDateTime, Utc};
use failure::{self, format_err};
use rust_decimal::Decimal;
use uuid::Uuid;

use super::UniqueHash;
use exonum_crypto::{Hash, PublicKey};

/// A type that can be (de)serialized as a value in the blockchain storage.
///
/// If you need to implement `BinaryValue` for your types, use little-endian encoding
/// for integer types for compatibility with modern architectures.
///
/// # Examples
///
/// Implementing `BinaryValue` for the type:
///
/// ```
/// use std::{borrow::Cow, io::{Read, Write}};
/// use byteorder::{LittleEndian, ReadBytesExt, ByteOrder};
/// use failure;
/// use exonum_merkledb::BinaryValue;
///
/// #[derive(Clone)]
/// struct Data {
///     a: i16,
///     b: u32,
/// }
///
/// impl BinaryValue for Data {
///     fn to_bytes(&self) -> Vec<u8> {
///         let mut buf = vec![0_u8; 6];
///         LittleEndian::write_i16(&mut buf[0..2], self.a);
///         LittleEndian::write_u32(&mut buf[2..6], self.b);
///         buf
///     }
///
///     fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
///         let mut buf = bytes.as_ref();
///         let a = buf.read_i16::<LittleEndian>()?;
///         let b = buf.read_u32::<LittleEndian>()?;
///         Ok(Self { a, b })
///     }
/// }
/// # fn main() {}
/// ```
pub trait BinaryValue: Sized {
    /// Serializes the given value to the vector of bytes.
    fn to_bytes(&self) -> Vec<u8>;
    /// Consumes and serializes the given value to the vector of bytes.
    /// This method is faster with the wrapped values,
    /// thus if you wouldn't use value after serialization use it.
    fn into_bytes(self) -> Vec<u8> {
        self.to_bytes()
    }
    /// Deserializes the value from the given bytes array.
    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error>;
}

macro_rules! impl_binary_form_scalar {
    ($type:tt, $read:ident) => {
        impl BinaryValue for $type {
            fn to_bytes(&self) -> Vec<u8> {
                vec![*self as u8]
            }

            fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                bytes.as_ref().$read().map_err(From::from)
            }
        }

        impl UniqueHash for $type {}
    };
    ($type:tt, $write:ident, $read:ident, $len:expr) => {
        impl BinaryValue for $type {
            fn to_bytes(&self) -> Vec<u8> {
                let mut v = vec![0; $len];
                LittleEndian::$write(&mut v, *self);
                v
            }

            fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                bytes.as_ref().$read::<LittleEndian>().map_err(From::from)
            }
        }

        impl UniqueHash for $type {}
    };
}

// Unsigned scalar types
impl_binary_form_scalar! { u8,  read_u8 }
impl_binary_form_scalar! { u16, write_u16, read_u16, 2 }
impl_binary_form_scalar! { u32, write_u32, read_u32, 4 }
impl_binary_form_scalar! { u64, write_u64, read_u64, 8 }
// Signed scalar types
impl_binary_form_scalar! { i8,  read_i8 }
impl_binary_form_scalar! { i16, write_i16, read_i16, 2 }
impl_binary_form_scalar! { i32, write_i32, read_i32, 4 }
impl_binary_form_scalar! { i64, write_i64, read_i64, 8 }

/// No-op implementation.
impl BinaryValue for () {
    fn to_bytes(&self) -> Vec<u8> {
        Vec::default()
    }

    fn from_bytes(_bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Ok(())
    }
}

impl UniqueHash for () {}

impl BinaryValue for bool {
    fn to_bytes(&self) -> Vec<u8> {
        vec![*self as u8]
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let value = bytes.as_ref();
        assert_eq!(value.len(), 1);

        match value[0] {
            0 => Ok(false),
            1 => Ok(true),
            value => Err(format_err!("Invalid value for bool: {}", value)),
        }
    }
}

impl UniqueHash for bool {}

impl BinaryValue for Vec<u8> {
    fn to_bytes(&self) -> Vec<u8> {
        self.clone()
    }

    fn into_bytes(self) -> Vec<u8> {
        self
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Ok(bytes.into_owned())
    }
}

impl UniqueHash for Vec<u8> {}

impl BinaryValue for String {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_owned()
    }

    fn into_bytes(self) -> Vec<u8> {
        Self::into_bytes(self)
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_utf8(bytes.into_owned()).map_err(From::from)
    }
}

impl UniqueHash for String {}

impl BinaryValue for Hash {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).ok_or_else(|| format_err!("Unable to decode value"))
    }
}

impl BinaryValue for PublicKey {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).ok_or_else(|| format_err!("Unable to decode value"))
    }
}

impl UniqueHash for PublicKey {}

// FIXME Maybe we should remove this implementations

impl BinaryValue for DateTime<Utc> {
    fn to_bytes(&self) -> Vec<u8> {
        let secs = self.timestamp();
        let nanos = self.timestamp_subsec_nanos();

        let mut buffer = vec![0; 12];
        LittleEndian::write_i64(&mut buffer[0..8], secs);
        LittleEndian::write_u32(&mut buffer[8..12], nanos);
        buffer
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut value = bytes.as_ref();
        let secs = value.read_i64::<LittleEndian>()?;
        let nanos = value.read_u32::<LittleEndian>()?;
        Ok(Self::from_utc(
            NaiveDateTime::from_timestamp(secs, nanos),
            Utc,
        ))
    }
}

impl UniqueHash for DateTime<Utc> {}

impl BinaryValue for Uuid {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Uuid {}

impl BinaryValue for Decimal {
    fn to_bytes(&self) -> Vec<u8> {
        self.serialize().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut value = bytes.as_ref();
        let mut buf: [u8; 16] = [0; 16];
        value.read_exact(&mut buf)?;
        Ok(Self::deserialize(buf))
    }
}

impl UniqueHash for Decimal {}

#[cfg(test)]
mod tests {
    use std::fmt::Debug;
    use std::str::FromStr;

    use chrono::Duration;

    use super::*;

    fn assert_round_trip_eq<T: BinaryValue + PartialEq + Debug>(values: &[T]) {
        for value in values {
            let bytes = value.to_bytes();
            assert_eq!(
                *value,
                <T as BinaryValue>::from_bytes(bytes.into()).unwrap()
            );
        }
    }

    macro_rules! impl_test_binary_form_scalar_unsigned {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    macro_rules! impl_test_binary_form_scalar_signed {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), -1, 0, 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    // Impl tests for unsigned scalar types
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u8,  u8 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u32, u32 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u16, u16 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u64, u64 }

    // Impl tests for signed scalar types
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i8,  i8 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i16, i16 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i32, i32 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i64, i64 }

    // Tests for the other types

    #[test]
    fn test_binary_form_vec_u8() {
        let values = [vec![], vec![1], vec![1, 2, 3], vec![255; 100]];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_bool_correct() {
        let values = [true, false];
        assert_round_trip_eq(&values);
    }

    #[test]
    #[should_panic(expected = "Invalid value for bool: 2")]
    fn test_binary_form_bool_incorrect() {
        let bytes = 2_u8.to_bytes();
        <bool as BinaryValue>::from_bytes(bytes.into()).unwrap();
    }

    #[test]
    fn test_binary_form_string() {
        let values: Vec<_> = ["", "e", "2", "hello"]
            .iter()
            .map(|v| v.to_string())
            .collect();
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_datetime() {
        use chrono::TimeZone;

        let times = [
            Utc.timestamp(0, 0),
            Utc.timestamp(13, 23),
            Utc::now(),
            Utc::now() + Duration::seconds(17) + Duration::nanoseconds(15),
            Utc.timestamp(0, 999_999_999),
            Utc.timestamp(0, 1_500_000_000), // leap second
        ];
        assert_round_trip_eq(&times);
    }

    #[test]
    fn test_binary_form_uuid() {
        let values = [
            Uuid::nil(),
            Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
            Uuid::parse_str("0000002a-000c-0005-0c03-0938362b0809").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_decimal() {
        let values = [
            Decimal::from_str("3.14").unwrap(),
            Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28),
            Decimal::new(9497628354687268, 12),
            Decimal::from_str("0").unwrap(),
            Decimal::from_str("-0.000000000000000000019").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }
}
<|endoftext|>


<commit_before>extern crate itertools;

use itertools::Itertools;
use itertools::EitherOrBoth::{Both, Left, Right};
#[cfg(feature = "unstable")]
use itertools::ZipTrusted;
use itertools::free::zip_eq;

#[test]
fn zip_longest_fused()
{
    let a = [Some(1), None, Some(3), Some(4)];
    let b = [1, 2, 3];

    let unfused = a.iter().batching(|mut it| *it.next().unwrap())
        .zip_longest(b.iter().cloned());
    itertools::assert_equal(unfused,
                       vec![Both(1, 1), Right(2), Right(3)]);
}

#[cfg(feature = "unstable")]
#[test]
fn test_zip_longest_size_hint() {
    let c = (1..10).cycle();
    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let v2 = &[10, 11, 12];

    assert_eq!(c.zip_longest(v.iter()).size_hint(), (std::usize::MAX, None));

    assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10)));
}

#[test]
fn test_double_ended_zip_longest() {
    let xs = [1, 2, 3, 4, 5, 6];
    let ys = [1, 2, 3, 7];
    let a = xs.iter().map(|&x| x);
    let b = ys.iter().map(|&x| x);
    let mut it = a.zip_longest(b);
    assert_eq!(it.next(), Some(Both(1, 1)));
    assert_eq!(it.next(), Some(Both(2, 2)));
    assert_eq!(it.next_back(), Some(Left(6)));
    assert_eq!(it.next_back(), Some(Left(5)));
    assert_eq!(it.next_back(), Some(Both(4, 7)));
    assert_eq!(it.next(), Some(Both(3, 3)));
    assert_eq!(it.next(), None);
}

#[cfg(feature = "unstable")]
#[test]
fn ziptrusted_1() {
    let mut xs = [0; 6];
    let mut ys = [0; 8];
    let mut zs = [0; 7];

    xs.iter_mut().set_from(0..);
    ys.iter_mut().set_from(0..);
    zs.iter_mut().set_from(0..);

    let it = ZipTrusted::new((xs.iter(), ys.iter()));
    assert_eq!(it.size_hint(), (6, Some(6)));
    itertools::assert_equal(it, xs.iter().zip(ys.iter()));

    let it = ZipTrusted::new((xs.iter(), ys.iter(), zs.iter()));
    assert_eq!(it.size_hint(), (6, Some(6)));
    itertools::assert_equal(it, xs.iter()
                             .zip(ys.iter())
                             .zip(zs.iter())
                             .map(|((a, b), c)| (a, b, c)));
}

#[test]
fn zipslices() {
    use itertools::ZipSlices;

    let xs = [1, 2, 3, 4, 5, 6];
    let ys = [1, 2, 3, 7];
    itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys));

    let xs = [1, 2, 3, 4, 5, 6];
    let mut ys = [0; 6];
    for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
        *y = *x;
    }
    itertools::assert_equal(&xs, &ys);
}

#[should_panic]
#[test]
fn zip_eq_panic1()
{
    let a = [1, 2];
    let b = [1, 2, 3];

    zip_eq(&a, &b).count();
}

#[should_panic]
#[test]
fn zip_eq_panic2()
{
    let a = None::<i32>;
    let b = [1, 2, 3];

    zip_eq(&a, &b).count();
}

<commit_msg>Fix zip_eq test<commit_after>extern crate itertools;

use itertools::Itertools;
use itertools::EitherOrBoth::{Both, Left, Right};
#[cfg(feature = "unstable")]
use itertools::ZipTrusted;
use itertools::free::zip_eq;

#[test]
fn zip_longest_fused()
{
    let a = [Some(1), None, Some(3), Some(4)];
    let b = [1, 2, 3];

    let unfused = a.iter().batching(|mut it| *it.next().unwrap())
        .zip_longest(b.iter().cloned());
    itertools::assert_equal(unfused,
                       vec![Both(1, 1), Right(2), Right(3)]);
}

#[cfg(feature = "unstable")]
#[test]
fn test_zip_longest_size_hint() {
    let c = (1..10).cycle();
    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let v2 = &[10, 11, 12];

    assert_eq!(c.zip_longest(v.iter()).size_hint(), (std::usize::MAX, None));

    assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10)));
}

#[test]
fn test_double_ended_zip_longest() {
    let xs = [1, 2, 3, 4, 5, 6];
    let ys = [1, 2, 3, 7];
    let a = xs.iter().map(|&x| x);
    let b = ys.iter().map(|&x| x);
    let mut it = a.zip_longest(b);
    assert_eq!(it.next(), Some(Both(1, 1)));
    assert_eq!(it.next(), Some(Both(2, 2)));
    assert_eq!(it.next_back(), Some(Left(6)));
    assert_eq!(it.next_back(), Some(Left(5)));
    assert_eq!(it.next_back(), Some(Both(4, 7)));
    assert_eq!(it.next(), Some(Both(3, 3)));
    assert_eq!(it.next(), None);
}

#[cfg(feature = "unstable")]
#[test]
fn ziptrusted_1() {
    let mut xs = [0; 6];
    let mut ys = [0; 8];
    let mut zs = [0; 7];

    xs.iter_mut().set_from(0..);
    ys.iter_mut().set_from(0..);
    zs.iter_mut().set_from(0..);

    let it = ZipTrusted::new((xs.iter(), ys.iter()));
    assert_eq!(it.size_hint(), (6, Some(6)));
    itertools::assert_equal(it, xs.iter().zip(ys.iter()));

    let it = ZipTrusted::new((xs.iter(), ys.iter(), zs.iter()));
    assert_eq!(it.size_hint(), (6, Some(6)));
    itertools::assert_equal(it, xs.iter()
                             .zip(ys.iter())
                             .zip(zs.iter())
                             .map(|((a, b), c)| (a, b, c)));
}

#[test]
fn zipslices() {
    use itertools::ZipSlices;

    let xs = [1, 2, 3, 4, 5, 6];
    let ys = [1, 2, 3, 7];
    itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys));

    let xs = [1, 2, 3, 4, 5, 6];
    let mut ys = [0; 6];
    for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
        *y = *x;
    }
    itertools::assert_equal(&xs, &ys);
}

#[should_panic]
#[test]
fn zip_eq_panic1()
{
    let a = [1, 2];
    let b = [1, 2, 3];

    zip_eq(&a, &b).count();
}

#[should_panic]
#[test]
fn zip_eq_panic2()
{
    let a: [i32; 0] = [];
    let b = [1, 2, 3];

    zip_eq(&a, &b).count();
}

<|endoftext|>


<commit_before>//! Formats a DOM structure to a Writer
//!
//! ### Example
//! ```
//! use document::Document;
//! use document::writer::format_document;
//!
//! let doc = Document::new();
//!
//! let hello = doc.new_element("hello".to_string());
//! hello.set_attribute("planet".to_string(), "Earth".to_string());
//! doc.root().append_child(hello);
//!
//! let mut output = std::io::stdio::stdout();
//! format_document(&doc, &mut output).ok().expect("unable to output XML");
//! ```
//!
//! ### Known issues
//!
//! Output is not escaped in any way,
//! it's very easy to create malformed XML!
//!
//! ### Potential options to support
//!
//! - Space before `/>`
//! - Single vs double quotes
//! - Fixed ordering of attributes

use std::io::IoResult;

use super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};
use super::{ElementRootChild,CommentRootChild,PIRootChild};

enum Content {
    Element(super::Element),
    ElementEnd(String),
    Text(super::Text),
    Comment(super::Comment),
    ProcessingInstruction(super::ProcessingInstruction),
}

fn format_element<W : Writer>(element: super::Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
    try!(write!(writer, "<{}", element.name()));

    for attr in element.attributes().iter() {
        try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
    }

    let mut children = element.children();
    if children.is_empty() {
        writer.write_str("/>")
    } else {
        try!(writer.write_str(">"));

        todo.push(ElementEnd(element.name()));
        children.reverse();
        let x = children.into_iter().map(|c| match c {
            ElementElementChild(element) => Element(element),
            TextElementChild(t)          => Text(t),
            CommentElementChild(c)       => Comment(c),
            PIElementChild(p)            => ProcessingInstruction(p),
        }).collect();
        todo.push_all_move(x);

        Ok(())
    }
}

fn format_comment<W : Writer>(comment: super::Comment, writer: &mut W) -> IoResult<()> {
    write!(writer, "<!--{}-->", comment.text())
}

fn format_processing_instruction<W : Writer>(pi: super::ProcessingInstruction, writer: &mut W) -> IoResult<()> {
    match pi.value() {
        None    => write!(writer, "<?{}?>", pi.target()),
        Some(v) => write!(writer, "<?{} {}?>", pi.target(), v),
    }
}

fn format_one<W : Writer>(content: Content, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
    match content {
        Element(e)               => format_element(e, todo, writer),
        ElementEnd(name)         => write!(writer, "</{}>", name),
        Text(t)                  => writer.write_str(t.text().as_slice()),
        Comment(c)               => format_comment(c, writer),
        ProcessingInstruction(p) => format_processing_instruction(p, writer),
    }
}

fn format_body<W : Writer>(element: super::Element, writer: &mut W) -> IoResult<()> {
    let mut todo = vec![Element(element)];

    while ! todo.is_empty() {
        try!(format_one(todo.pop().unwrap(), &mut todo, writer));
    }

    Ok(())
}

/// Formats a document into a Writer
pub fn format_document<W : Writer>(doc: &super::Document, writer: &mut W) -> IoResult<()> {
    try!(writer.write_str("<?xml version='1.0'?>"));

    for child in doc.root().children().into_iter() {
        try!(match child {
            ElementRootChild(e) => format_body(e, writer),
            CommentRootChild(c) => format_comment(c, writer),
            PIRootChild(p)      => format_processing_instruction(p, writer),
        })
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use std::io::MemWriter;

    use super::super::Document;
    use super::format_document;

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }

    #[test]
    fn nested_text() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let text = d.new_text("A fine day to you!".to_string());
        hello.append_child(text);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
    }

    #[test]
    fn nested_comment() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let comment = d.new_comment(" Fill this in ".to_string());
        hello.append_child(comment);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><!-- Fill this in --></hello>");
    }

    #[test]
    fn nested_processing_instruction_without_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), None);
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display?></hello>");
    }

    #[test]
    fn nested_processing_instruction_with_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), Some("screen".to_string()));
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display screen?></hello>");
    }

    #[test]
    fn top_level_comment() {
        let d = Document::new();
        let comment = d.new_comment(" Fill this in ".to_string());
        d.root().append_child(comment);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><!-- Fill this in -->");
    }

    #[test]
    fn top_level_processing_instruction() {
        let d = Document::new();
        let pi = d.new_processing_instruction("display".to_string(), None);
        d.root().append_child(pi);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><?display?>");
    }
}
<commit_msg>Remove deprecated `Vec.push_all_move` call<commit_after>//! Formats a DOM structure to a Writer
//!
//! ### Example
//! ```
//! use document::Document;
//! use document::writer::format_document;
//!
//! let doc = Document::new();
//!
//! let hello = doc.new_element("hello".to_string());
//! hello.set_attribute("planet".to_string(), "Earth".to_string());
//! doc.root().append_child(hello);
//!
//! let mut output = std::io::stdio::stdout();
//! format_document(&doc, &mut output).ok().expect("unable to output XML");
//! ```
//!
//! ### Known issues
//!
//! Output is not escaped in any way,
//! it's very easy to create malformed XML!
//!
//! ### Potential options to support
//!
//! - Space before `/>`
//! - Single vs double quotes
//! - Fixed ordering of attributes

use std::io::IoResult;

use super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};
use super::{ElementRootChild,CommentRootChild,PIRootChild};

enum Content {
    Element(super::Element),
    ElementEnd(String),
    Text(super::Text),
    Comment(super::Comment),
    ProcessingInstruction(super::ProcessingInstruction),
}

fn format_element<W : Writer>(element: super::Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
    try!(write!(writer, "<{}", element.name()));

    for attr in element.attributes().iter() {
        try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
    }

    let mut children = element.children();
    if children.is_empty() {
        writer.write_str("/>")
    } else {
        try!(writer.write_str(">"));

        todo.push(ElementEnd(element.name()));
        children.reverse();
        let x = children.into_iter().map(|c| match c {
            ElementElementChild(element) => Element(element),
            TextElementChild(t)          => Text(t),
            CommentElementChild(c)       => Comment(c),
            PIElementChild(p)            => ProcessingInstruction(p),
        });
        todo.extend(x);

        Ok(())
    }
}

fn format_comment<W : Writer>(comment: super::Comment, writer: &mut W) -> IoResult<()> {
    write!(writer, "<!--{}-->", comment.text())
}

fn format_processing_instruction<W : Writer>(pi: super::ProcessingInstruction, writer: &mut W) -> IoResult<()> {
    match pi.value() {
        None    => write!(writer, "<?{}?>", pi.target()),
        Some(v) => write!(writer, "<?{} {}?>", pi.target(), v),
    }
}

fn format_one<W : Writer>(content: Content, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
    match content {
        Element(e)               => format_element(e, todo, writer),
        ElementEnd(name)         => write!(writer, "</{}>", name),
        Text(t)                  => writer.write_str(t.text().as_slice()),
        Comment(c)               => format_comment(c, writer),
        ProcessingInstruction(p) => format_processing_instruction(p, writer),
    }
}

fn format_body<W : Writer>(element: super::Element, writer: &mut W) -> IoResult<()> {
    let mut todo = vec![Element(element)];

    while ! todo.is_empty() {
        try!(format_one(todo.pop().unwrap(), &mut todo, writer));
    }

    Ok(())
}

/// Formats a document into a Writer
pub fn format_document<W : Writer>(doc: &super::Document, writer: &mut W) -> IoResult<()> {
    try!(writer.write_str("<?xml version='1.0'?>"));

    for child in doc.root().children().into_iter() {
        try!(match child {
            ElementRootChild(e) => format_body(e, writer),
            CommentRootChild(c) => format_comment(c, writer),
            PIRootChild(p)      => format_processing_instruction(p, writer),
        })
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use std::io::MemWriter;

    use super::super::Document;
    use super::format_document;

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }

    #[test]
    fn nested_text() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let text = d.new_text("A fine day to you!".to_string());
        hello.append_child(text);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
    }

    #[test]
    fn nested_comment() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let comment = d.new_comment(" Fill this in ".to_string());
        hello.append_child(comment);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><!-- Fill this in --></hello>");
    }

    #[test]
    fn nested_processing_instruction_without_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), None);
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display?></hello>");
    }

    #[test]
    fn nested_processing_instruction_with_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), Some("screen".to_string()));
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display screen?></hello>");
    }

    #[test]
    fn top_level_comment() {
        let d = Document::new();
        let comment = d.new_comment(" Fill this in ".to_string());
        d.root().append_child(comment);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><!-- Fill this in -->");
    }

    #[test]
    fn top_level_processing_instruction() {
        let d = Document::new();
        let pi = d.new_processing_instruction("display".to_string(), None);
        d.root().append_child(pi);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><?display?>");
    }
}
<|endoftext|>


<commit_before>extern crate mp4parse;

use std::env;
use std::fs::File;
use std::io::BufReader;

fn dump_file(filename: &String) {
    let file = match File::open(filename) {
        Ok(file) => file,
        _ => {
            println!("ERROR: invalid path '{}'", filename);
            return;
        }
    };
    let mut reader = BufReader::new(file);
    let mut context = mp4parse::MediaContext::new();
    // Turn on debug output.
    context.trace(true);
    // Read all boxes.
    match mp4parse::read_mp4(&mut reader, &mut context) {
        Ok(_) => {},
        Err(mp4parse::Error::Io(e)) => {
            println!("I/O ERROR: {:?}", e);
            panic!(e);
        },
        Err(e) => {
            println!("ERROR: {:?}", e);
        },
    }
    println!("-- result of parsing '{}' --\n{:?}", filename, context);
}

fn main() {
    for filename in env::args().skip(1) {
        println!("-- dump of '{}' --", filename);
        dump_file(&filename);
        println!("-- end of '{}' --", filename);
    }
}
<commit_msg>Make examples/dump.rs quiet by default.  Use -v for verbose mode.<commit_after>extern crate mp4parse;

use std::env;
use std::fs::File;
use std::io::BufReader;

fn dump_file(filename: &String, verbose: bool) {
    let file = match File::open(filename) {
        Ok(file) => file,
        _ => {
            println!("ERROR: invalid path '{}'", filename);
            return;
        }
    };
    let mut reader = BufReader::new(file);
    let mut context = mp4parse::MediaContext::new();
    // Turn on debug output.
    if verbose {
        context.trace(true);
    }
    // Read all boxes.
    match mp4parse::read_mp4(&mut reader, &mut context) {
        Ok(_) => {},
        Err(mp4parse::Error::Io(e)) => {
            println!("I/O ERROR: {:?} in '{}'", e, filename);
            panic!(e);
        },
        Err(e) => {
            println!("ERROR: {:?} in '{}'", e, filename);
        },
    }
    if verbose {
        println!("-- result of parsing '{}' --\n{:?}", filename, context);
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        return;
    }
    let (skip, verbose) = if args[1] == "-v" {
        (2, true)
    } else {
        (1, false)
    };
    for filename in args.iter().skip(skip) {
        if verbose {
            println!("-- dump of '{}' --", filename);
        }
        dump_file(&filename, verbose);
        if verbose {
            println!("-- end of '{}' --", filename);
        }
    }
}
<|endoftext|>