<commit_before>use std::mem;
use std::slice;
use std::fmt;
use approx;
use num;
use num::Float;
use channel::{BoundedChannel, BoundedChannelScalarTraits, ColorChannel, ChannelFormatCast,
              ChannelCast};
use color::{Color, HomogeneousColor, Lerp, Flatten, Bounded};
use convert::FromColor;
use rgb::Rgb;

pub struct RgiTag;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
pub struct Rgi<T> {
    red: BoundedChannel<T>,
    green: BoundedChannel<T>,
    intensity: BoundedChannel<T>,
}

impl<T> Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    pub fn from_channels(red: T, green: T, intensity: T) -> Self {
        let zero = num::cast(0.0).unwrap();
        if red + green > num::cast(1.0).unwrap() || red + green < num::cast(0.0).unwrap() {
            panic!("rgi channels must sum to exactly 1.0");
        }
        assert!(red >= zero);
        assert!(green >= zero);
        Rgi {
            red: BoundedChannel(red),
            green: BoundedChannel(green),
            intensity: BoundedChannel(intensity),
        }
    }

    impl_color_color_cast_square!(Rgi {red, green, intensity});

    pub fn red(&self) -> T {
        self.red.0.clone()
    }
    pub fn green(&self) -> T {
        self.green.0.clone()
    }
    pub fn blue(&self) -> T {
        num::cast::<_, T>(1.0).unwrap() - self.green() - self.red()
    }
    pub fn intensity(&self) -> T {
        self.intensity.0.clone()
    }
    pub fn intensity_mut(&mut self) -> &mut T {
        &mut self.intensity.0
    }
    pub fn set_red(&mut self, val: T) {
        let (red, green, _) = Self::rescale_channels(val, self.green(), self.blue());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_green(&mut self, val: T) {
        let (green, red, _) = Self::rescale_channels(val, self.red(), self.blue());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_blue(&mut self, val: T) {
        let (_, red, green) = Self::rescale_channels(val, self.red(), self.green());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_intensity(&mut self, val: T) {
        self.intensity.0 = val;
    }

    fn rescale_channels(primary: T, c2: T, c3: T) -> (T, T, T) {
        let new_primary = primary;
        if new_primary > BoundedChannel::max_bound() || new_primary < BoundedChannel::min_bound() {
            panic!("rgi color channels must be 1.0 or below");
        }

        let zero = num::cast(0.0).unwrap();
        let rem_scale = c2 + c3;
        let rem = num::cast::<_, T>(1.0).unwrap() - new_primary;
        if rem_scale > zero {
            (new_primary, (c2 / rem_scale) * rem, (c3 / rem_scale) * rem)
        } else {
            let one_half = num::cast(0.5).unwrap();
            (new_primary, rem * one_half, rem * one_half)
        }
    }
}

impl<T> Color for Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    type Tag = RgiTag;
    type ChannelsTuple = (T, T, T);

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

    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        Rgi {
            red: BoundedChannel(values.0),
            green: BoundedChannel(values.1),
            intensity: BoundedChannel(values.2),
        }
    }
    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.red.0, self.green.0, self.intensity.0)
    }
}

impl<T> HomogeneousColor for Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    type ChannelFormat = T;

    impl_color_homogeneous_color_square!(Rgi<T> {red, green, intensity});
}

impl<T> Lerp for Rgi<T>
    where T: BoundedChannelScalarTraits + Lerp + Float
{
    type Position = <T as Lerp>::Position;
    impl_color_lerp_square!(Rgi {red, green, intensity});
}

impl<T> Flatten for Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);
    impl_color_from_slice_square!(Rgi<T> {red:0, green:1, intensity:2});
}

impl<T> Bounded for Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    impl_color_bounded!(Rgi {red, green, intensity});
}

impl<T> approx::ApproxEq for Rgi<T>
    where T: BoundedChannelScalarTraits + approx::ApproxEq + Float,
          T::Epsilon: Clone
{
    impl_approx_eq!({red, green, intensity});
}

impl<T> Default for Rgi<T>
    where T: BoundedChannelScalarTraits + num::Zero + Float
{
    impl_color_default!(Rgi {red:BoundedChannel, green:BoundedChannel,
        intensity:BoundedChannel});
}

impl<T> fmt::Display for Rgi<T>
    where T: BoundedChannelScalarTraits + fmt::Display + Float
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rgi({}, {}, {})", self.red, self.green, self.intensity)
    }
}

impl<T> FromColor<Rgb<T>> for Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    fn from_color(from: &Rgb<T>) -> Self {
        let zero = num::cast(0.0).unwrap();
        let sum = from.red() + from.green() + from.blue();

        if sum != zero {
            let r = from.red() / sum;
            let g = from.green() / sum;

            let i = num::cast::<_, T>(1.0 / 3.0).unwrap() * sum;

            Rgi::from_channels(r, g, i)
        } else {
            Rgi::from_channels(zero, zero, zero)
        }
    }
}

impl<T> FromColor<Rgi<T>> for Rgb<T>
    where T: BoundedChannelScalarTraits + Float
{
    fn from_color(from: &Rgi<T>) -> Self {
        let sum = from.intensity() * num::cast(3.0).unwrap();
        let red = from.red() * sum;
        let green = from.green() * sum;
        let blue = from.blue() * sum;

        Rgb::from_channels(red, green, blue)
    }
}

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

    #[test]
    fn test_construct() {
        let c1 = Rgi::from_channels(0.5, 0.2, 1.0);
        assert_relative_eq!(c1.red(), 0.5);
        assert_relative_eq!(c1.green(), 0.2);
        assert_relative_eq!(c1.blue(), 0.3);
        assert_relative_eq!(c1.intensity(), 1.0);
        assert_eq!(c1.to_tuple(), (0.5, 0.2, 1.0));
        assert_relative_eq!(Rgi::from_tuple(c1.to_tuple()), c1);

        let c2 = Rgi::from_channels(0.0, 0.0, 0.5);
        assert_relative_eq!(c2.red(), 0.0);
        assert_relative_eq!(c2.green(), 0.0);
        assert_relative_eq!(c2.blue(), 1.0);
        assert_relative_eq!(c2.intensity(), 0.5);
        assert_eq!(c2.to_tuple(), (0.0, 0.0, 0.5));

        let c3 = Rgi::from_channels(0.7, 0.3, 0.0);
        assert_relative_eq!(c3.red(), 0.7);
        assert_relative_eq!(c3.green(), 0.3);
        assert_relative_eq!(c3.blue(), 0.0);
        assert_relative_eq!(c3.intensity(), 0.0);
        assert_eq!(c3.to_tuple(), (0.7, 0.3, 0.0));
        assert_relative_eq!(Rgi::from_tuple(c3.to_tuple()), c3);
    }

    #[test]
    fn test_set_channels() {
        let mut c1 = Rgi::from_channels(0.3, 0.2, 0.5);
        c1.set_red(0.6);
        assert_relative_eq!(c1.red(), 0.6);
        assert_relative_eq!(c1.green(), 0.1142857, epsilon=1e-6);
        assert_relative_eq!(c1.blue(), 0.2857143, epsilon=1e-6);
        assert_relative_eq!(c1.intensity(), 0.5);

        let mut c2 = Rgi::from_channels(0.333333, 0.333333, 0.9);
        c2.set_green(0.5);
        assert_relative_eq!(c2.red(), 0.25, epsilon=1e-6);
        assert_relative_eq!(c2.green(), 0.5, epsilon=1e-6);
        assert_relative_eq!(c2.blue(), 0.25, epsilon=1e-6);
        assert_relative_eq!(c2.intensity(), 0.9, epsilon=1e-6);
        c2.set_green(1.0);
        assert_relative_eq!(c2.red(), 0.0, epsilon=1e-6);
        assert_relative_eq!(c2.green(), 1.0, epsilon=1e-6);
        assert_relative_eq!(c2.blue(), 0.0, epsilon=1e-6);

        let mut c3 = Rgi::from_channels(0.6, 0.3, 0.83);
        c3.set_blue(0.7);
        assert_relative_eq!(c3.red(), 0.2, epsilon=1e-6);
        assert_relative_eq!(c3.green(), 0.1, epsilon=1e-6);
        assert_relative_eq!(c3.blue(), 0.7, epsilon=1e-6);
        assert_relative_eq!(c3.intensity(), 0.83, epsilon=1e-6);

        let mut c4 = Rgi::from_channels(1.0, 0.0, 0.6);
        c4.set_red(0.5);
        assert_relative_eq!(c4.red(), 0.5);
        assert_relative_eq!(c4.green(), 0.25);
        assert_relative_eq!(c4.blue(), 0.25);
    }

    #[test]
    fn test_flatten() {
        let c1 = Rgi::from_channels(0.2, 0.5, 0.6);
        assert_eq!(c1.as_slice(), &[0.2, 0.5, 0.6]);
        assert_relative_eq!(Rgi::from_slice(c1.as_slice()), c1);
    }

    #[test]
    fn test_normalize() {
        let c1 = Rgi::from_channels(0.5, 0.2, 0.8);
        assert_relative_eq!(c1.normalize(), c1);
        assert!(c1.is_normalized());
        let c2 = Rgi::from_channels(0.0, 0.0, 1.2);
        assert_relative_eq!(c2.normalize(), Rgi::from_channels(0.0, 0.0, 1.0));
        assert!(!c2.is_normalized());
    }

    #[test]
    #[should_panic]
    fn test_constructor_oob_panic() {
        let mut c1 = Rgi::from_channels(0.7, 0.4, 0.9);
        c1.set_blue(0.0);
    }

    #[test]
    #[should_panic]
    fn test_red_setter_oob_panic() {
        let mut c1 = Rgi::from_channels(0.2, 0.3, 0.8);
        c1.set_red(1.2);
    }
    #[test]
    #[should_panic]
    fn test_green_setter_oob_panic() {
        let mut c1 = Rgi::from_channels(0.2, 0.3, 0.8);
        c1.set_green(1.00000000001);
    }

    #[test]
    fn test_lerp() {
        let c1 = Rgi::from_channels(0.3, 0.6, 0.5);
        let c2 = Rgi::from_channels(0.1, 0.4, 1.0);
        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), Rgi::from_channels(0.2, 0.5, 0.75));
        assert_relative_eq!(c1.lerp(&c2, 0.75), Rgi::from_channels(0.15, 0.45, 0.875),
            epsilon=1e-5);
    }

    #[test]
    fn test_from_to_rgb() {
        let test_data = test::build_hwb_test_data();
        for item in test_data.iter() {
            let rgi = Rgi::from_color(&item.rgb);
            let rgb = Rgb::from_color(&rgi);
            assert_relative_eq!(rgb, item.rgb, epsilon=1e-6);
        }

        let rgb1 = Rgb::from_channels(0.50, 0.50, 1.0);
        let rgi1 = Rgi::from_color(&rgb1);
        assert_relative_eq!(rgi1, Rgi::from_channels(0.25, 0.25, 0.6666666666),
                            epsilon=1e-6);
        assert_relative_eq!(Rgb::from_color(&rgi1), rgb1);

        let rgb2 = Rgb::from_channels(0.00, 0.00, 0.00);
        let rgi2 = Rgi::from_color(&rgb2);
        assert_relative_eq!(rgi2, Rgi::from_channels(0.0, 0.0, 0.0));
        assert_relative_eq!(Rgb::from_color(&rgi2), rgb2);

        let rgb3 = Rgb::from_channels(1.0, 1.0, 1.0);
        let rgi3 = Rgi::from_color(&rgb3);
        assert_relative_eq!(rgi3, Rgi::from_channels(0.333333, 0.333333, 1.0),
                            epsilon=1e-5);
        assert_relative_eq!(Rgb::from_color(&rgi3), rgb3);
    }

    #[test]
    fn color_cast() {
        let c1 = Rgi::from_channels(0.6f32, 0.2, 0.9);
        assert_relative_eq!(c1.color_cast(), c1);
        assert_relative_eq!(c1.color_cast::<f64>().color_cast(), c1);
        assert_relative_eq!(c1.color_cast(), Rgi::from_channels(0.6, 0.2, 0.9),
            epsilon=1e-6);
    }
}
<commit_msg>Remove HomogeneousColor impl from rgi.<commit_after>use std::mem;
use std::slice;
use std::fmt;
use approx;
use num;
use num::Float;
use channel::{BoundedChannel, BoundedChannelScalarTraits, ColorChannel, ChannelFormatCast,
              ChannelCast};
use color::{Color, HomogeneousColor, Lerp, Flatten, Bounded};
use convert::FromColor;
use rgb::Rgb;

pub struct RgiTag;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
pub struct Rgi<T> {
    red: BoundedChannel<T>,
    green: BoundedChannel<T>,
    intensity: BoundedChannel<T>,
}

impl<T> Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    pub fn from_channels(red: T, green: T, intensity: T) -> Self {
        let zero = num::cast(0.0).unwrap();
        if red + green > num::cast(1.0).unwrap() || red + green < num::cast(0.0).unwrap() {
            panic!("rgi channels must sum to exactly 1.0");
        }
        assert!(red >= zero);
        assert!(green >= zero);
        Rgi {
            red: BoundedChannel(red),
            green: BoundedChannel(green),
            intensity: BoundedChannel(intensity),
        }
    }

    impl_color_color_cast_square!(Rgi {red, green, intensity});

    pub fn red(&self) -> T {
        self.red.0.clone()
    }
    pub fn green(&self) -> T {
        self.green.0.clone()
    }
    pub fn blue(&self) -> T {
        num::cast::<_, T>(1.0).unwrap() - self.green() - self.red()
    }
    pub fn intensity(&self) -> T {
        self.intensity.0.clone()
    }
    pub fn intensity_mut(&mut self) -> &mut T {
        &mut self.intensity.0
    }
    pub fn set_red(&mut self, val: T) {
        let (red, green, _) = Self::rescale_channels(val, self.green(), self.blue());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_green(&mut self, val: T) {
        let (green, red, _) = Self::rescale_channels(val, self.red(), self.blue());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_blue(&mut self, val: T) {
        let (_, red, green) = Self::rescale_channels(val, self.red(), self.green());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_intensity(&mut self, val: T) {
        self.intensity.0 = val;
    }

    fn rescale_channels(primary: T, c2: T, c3: T) -> (T, T, T) {
        let new_primary = primary;
        if new_primary > BoundedChannel::max_bound() || new_primary < BoundedChannel::min_bound() {
            panic!("rgi color channels must be 1.0 or below");
        }

        let zero = num::cast(0.0).unwrap();
        let rem_scale = c2 + c3;
        let rem = num::cast::<_, T>(1.0).unwrap() - new_primary;
        if rem_scale > zero {
            (new_primary, (c2 / rem_scale) * rem, (c3 / rem_scale) * rem)
        } else {
            let one_half = num::cast(0.5).unwrap();
            (new_primary, rem * one_half, rem * one_half)
        }
    }
}

impl<T> Color for Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    type Tag = RgiTag;
    type ChannelsTuple = (T, T, T);

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

    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        Rgi {
            red: BoundedChannel(values.0),
            green: BoundedChannel(values.1),
            intensity: BoundedChannel(values.2),
        }
    }
    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.red.0, self.green.0, self.intensity.0)
    }
}

impl<T> Lerp for Rgi<T>
    where T: BoundedChannelScalarTraits + Lerp + Float
{
    type Position = <T as Lerp>::Position;
    impl_color_lerp_square!(Rgi {red, green, intensity});
}

impl<T> Flatten for Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);
    impl_color_from_slice_square!(Rgi<T> {red:0, green:1, intensity:2});
}

impl<T> Bounded for Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    impl_color_bounded!(Rgi {red, green, intensity});
}

impl<T> approx::ApproxEq for Rgi<T>
    where T: BoundedChannelScalarTraits + approx::ApproxEq + Float,
          T::Epsilon: Clone
{
    impl_approx_eq!({red, green, intensity});
}

impl<T> Default for Rgi<T>
    where T: BoundedChannelScalarTraits + num::Zero + Float
{
    impl_color_default!(Rgi {red:BoundedChannel, green:BoundedChannel,
        intensity:BoundedChannel});
}

impl<T> fmt::Display for Rgi<T>
    where T: BoundedChannelScalarTraits + fmt::Display + Float
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rgi({}, {}, {})", self.red, self.green, self.intensity)
    }
}

impl<T> FromColor<Rgb<T>> for Rgi<T>
    where T: BoundedChannelScalarTraits + Float
{
    fn from_color(from: &Rgb<T>) -> Self {
        let zero = num::cast(0.0).unwrap();
        let sum = from.red() + from.green() + from.blue();

        if sum != zero {
            let r = from.red() / sum;
            let g = from.green() / sum;

            let i = num::cast::<_, T>(1.0 / 3.0).unwrap() * sum;

            Rgi::from_channels(r, g, i)
        } else {
            Rgi::from_channels(zero, zero, zero)
        }
    }
}

impl<T> FromColor<Rgi<T>> for Rgb<T>
    where T: BoundedChannelScalarTraits + Float
{
    fn from_color(from: &Rgi<T>) -> Self {
        let sum = from.intensity() * num::cast(3.0).unwrap();
        let red = from.red() * sum;
        let green = from.green() * sum;
        let blue = from.blue() * sum;

        Rgb::from_channels(red, green, blue)
    }
}

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

    #[test]
    fn test_construct() {
        let c1 = Rgi::from_channels(0.5, 0.2, 1.0);
        assert_relative_eq!(c1.red(), 0.5);
        assert_relative_eq!(c1.green(), 0.2);
        assert_relative_eq!(c1.blue(), 0.3);
        assert_relative_eq!(c1.intensity(), 1.0);
        assert_eq!(c1.to_tuple(), (0.5, 0.2, 1.0));
        assert_relative_eq!(Rgi::from_tuple(c1.to_tuple()), c1);

        let c2 = Rgi::from_channels(0.0, 0.0, 0.5);
        assert_relative_eq!(c2.red(), 0.0);
        assert_relative_eq!(c2.green(), 0.0);
        assert_relative_eq!(c2.blue(), 1.0);
        assert_relative_eq!(c2.intensity(), 0.5);
        assert_eq!(c2.to_tuple(), (0.0, 0.0, 0.5));

        let c3 = Rgi::from_channels(0.7, 0.3, 0.0);
        assert_relative_eq!(c3.red(), 0.7);
        assert_relative_eq!(c3.green(), 0.3);
        assert_relative_eq!(c3.blue(), 0.0);
        assert_relative_eq!(c3.intensity(), 0.0);
        assert_eq!(c3.to_tuple(), (0.7, 0.3, 0.0));
        assert_relative_eq!(Rgi::from_tuple(c3.to_tuple()), c3);
    }

    #[test]
    fn test_set_channels() {
        let mut c1 = Rgi::from_channels(0.3, 0.2, 0.5);
        c1.set_red(0.6);
        assert_relative_eq!(c1.red(), 0.6);
        assert_relative_eq!(c1.green(), 0.1142857, epsilon=1e-6);
        assert_relative_eq!(c1.blue(), 0.2857143, epsilon=1e-6);
        assert_relative_eq!(c1.intensity(), 0.5);

        let mut c2 = Rgi::from_channels(0.333333, 0.333333, 0.9);
        c2.set_green(0.5);
        assert_relative_eq!(c2.red(), 0.25, epsilon=1e-6);
        assert_relative_eq!(c2.green(), 0.5, epsilon=1e-6);
        assert_relative_eq!(c2.blue(), 0.25, epsilon=1e-6);
        assert_relative_eq!(c2.intensity(), 0.9, epsilon=1e-6);
        c2.set_green(1.0);
        assert_relative_eq!(c2.red(), 0.0, epsilon=1e-6);
        assert_relative_eq!(c2.green(), 1.0, epsilon=1e-6);
        assert_relative_eq!(c2.blue(), 0.0, epsilon=1e-6);

        let mut c3 = Rgi::from_channels(0.6, 0.3, 0.83);
        c3.set_blue(0.7);
        assert_relative_eq!(c3.red(), 0.2, epsilon=1e-6);
        assert_relative_eq!(c3.green(), 0.1, epsilon=1e-6);
        assert_relative_eq!(c3.blue(), 0.7, epsilon=1e-6);
        assert_relative_eq!(c3.intensity(), 0.83, epsilon=1e-6);

        let mut c4 = Rgi::from_channels(1.0, 0.0, 0.6);
        c4.set_red(0.5);
        assert_relative_eq!(c4.red(), 0.5);
        assert_relative_eq!(c4.green(), 0.25);
        assert_relative_eq!(c4.blue(), 0.25);
    }

    #[test]
    fn test_flatten() {
        let c1 = Rgi::from_channels(0.2, 0.5, 0.6);
        assert_eq!(c1.as_slice(), &[0.2, 0.5, 0.6]);
        assert_relative_eq!(Rgi::from_slice(c1.as_slice()), c1);
    }

    #[test]
    fn test_normalize() {
        let c1 = Rgi::from_channels(0.5, 0.2, 0.8);
        assert_relative_eq!(c1.normalize(), c1);
        assert!(c1.is_normalized());
        let c2 = Rgi::from_channels(0.0, 0.0, 1.2);
        assert_relative_eq!(c2.normalize(), Rgi::from_channels(0.0, 0.0, 1.0));
        assert!(!c2.is_normalized());
    }

    #[test]
    #[should_panic]
    fn test_constructor_oob_panic() {
        let mut c1 = Rgi::from_channels(0.7, 0.4, 0.9);
        c1.set_blue(0.0);
    }

    #[test]
    #[should_panic]
    fn test_red_setter_oob_panic() {
        let mut c1 = Rgi::from_channels(0.2, 0.3, 0.8);
        c1.set_red(1.2);
    }
    #[test]
    #[should_panic]
    fn test_green_setter_oob_panic() {
        let mut c1 = Rgi::from_channels(0.2, 0.3, 0.8);
        c1.set_green(1.00000000001);
    }

    #[test]
    fn test_lerp() {
        let c1 = Rgi::from_channels(0.3, 0.6, 0.5);
        let c2 = Rgi::from_channels(0.1, 0.4, 1.0);
        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), Rgi::from_channels(0.2, 0.5, 0.75));
        assert_relative_eq!(c1.lerp(&c2, 0.75), Rgi::from_channels(0.15, 0.45, 0.875),
            epsilon=1e-5);
    }

    #[test]
    fn test_from_to_rgb() {
        let test_data = test::build_hwb_test_data();
        for item in test_data.iter() {
            let rgi = Rgi::from_color(&item.rgb);
            let rgb = Rgb::from_color(&rgi);
            assert_relative_eq!(rgb, item.rgb, epsilon=1e-6);
        }

        let rgb1 = Rgb::from_channels(0.50, 0.50, 1.0);
        let rgi1 = Rgi::from_color(&rgb1);
        assert_relative_eq!(rgi1, Rgi::from_channels(0.25, 0.25, 0.6666666666),
                            epsilon=1e-6);
        assert_relative_eq!(Rgb::from_color(&rgi1), rgb1);

        let rgb2 = Rgb::from_channels(0.00, 0.00, 0.00);
        let rgi2 = Rgi::from_color(&rgb2);
        assert_relative_eq!(rgi2, Rgi::from_channels(0.0, 0.0, 0.0));
        assert_relative_eq!(Rgb::from_color(&rgi2), rgb2);

        let rgb3 = Rgb::from_channels(1.0, 1.0, 1.0);
        let rgi3 = Rgi::from_color(&rgb3);
        assert_relative_eq!(rgi3, Rgi::from_channels(0.333333, 0.333333, 1.0),
                            epsilon=1e-5);
        assert_relative_eq!(Rgb::from_color(&rgi3), rgb3);
    }

    #[test]
    fn color_cast() {
        let c1 = Rgi::from_channels(0.6f32, 0.2, 0.9);
        assert_relative_eq!(c1.color_cast(), c1);
        assert_relative_eq!(c1.color_cast::<f64>().color_cast(), c1);
        assert_relative_eq!(c1.color_cast(), Rgi::from_channels(0.6, 0.2, 0.9),
            epsilon=1e-6);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::net::SocketAddr;
use std::str::FromStr;
use std::time::Duration;

use std::io::{Read, Write};  // Used for TcpStream.read,  TcpStream.write
use mio::{Poll, Token, Events, Event, Ready, PollOpt};
use mio::tcp::{TcpListener, TcpStream};

use slab;
use interface::{ServerFactory, Protocol, Reason};
use transport::Transport;

const CONNS_MAX: usize = 65_536;
const BUF_SIZE: usize = 4096;

type Slab<T> = slab::Slab<T, Token>;

#[derive(Clone)]
enum ConnectionType {
    Server,
    Client,
}

struct ServerConnection {
    server: Box<ServerFactory>,
    socket: TcpListener,
}

struct ClientConnection {
    protocol: Box<Protocol>,
    socket: TcpStream,
    interest: Ready,
    transport: Transport,
}

impl ClientConnection {
    fn new(protocol: Box<Protocol>, socket: TcpStream) -> ClientConnection {
        ClientConnection {
            protocol: protocol,
            socket: socket,
            interest: Ready::hup() | Ready::readable(),
            transport: Transport::new(),
        }
    }

    fn peer_addr(&self) -> io::Result<SocketAddr> {
        self.socket.peer_addr()
    }

    fn is_finished(&self) -> bool {
        self.interest == Ready::none()
    }

    fn handle_hup(&mut self) {
        self.interest = Ready::none();
    }

    fn handle_read(&mut self) -> io::Result<()> {
        let mut read_bytes: Vec<u8> = Vec::new();
        loop {
            let (buf, read_len) = {
                let mut buf = [0; BUF_SIZE];
                let read_len = try!(self.socket.read(&mut buf[..]));
                // let s_data = str::from_utf8(&buf).unwrap();
                // info!("<<< {}", s_data);
                (buf, read_len)
            };
            if read_len > 0 {
                read_bytes.extend(buf[0..read_len].iter());
                if read_len < BUF_SIZE {
                    debug!("Nothing more to read");
                    break;
                } else {
                    debug!("More data to read");
                }
            }
        }
        self.protocol.data_received(&read_bytes[..], &mut self.transport);
        Ok(())
    }

    fn handle_write(&mut self) {

        {
            // a block where transport muting

            debug!("handle write");
            let buf = &mut self.transport.buf();
            let to_write_len = buf.len();
            if to_write_len > 0 {
                // let s_data = str::from_utf8(&buf[..]).unwrap();
                // info!(">>> {}", s_data);

                let result = self.socket.write(&buf[..]);
                match result {
                    Ok(written_len) => {
                        debug!("Write {} bytes", written_len);
                        if to_write_len != written_len {
                            error!("{} bytes to write but {} written, hanging up",
                                   to_write_len,
                                   written_len);
                            self.interest = Ready::hup();
                        }
                    }
                    Err(err) => {
                        error!("Error {} while writing to the socket, disconnecting", err);
                        self.interest = Ready::hup();
                    }
                };
            }
        };

        self.transport.clear();

        if self.transport.hup() {
            info!("Peer is disconnecting, will unregister connection");
            self.interest = Ready::none();
        }
    }
}

struct Connection {
    connection_type: ConnectionType,
    server: Option<ServerConnection>,
    client: Option<ClientConnection>,
    peer_addr: SocketAddr,
}

#[allow(dead_code)]
impl Connection {
    fn new_server(server: Box<ServerFactory>,
                  peer_addr: SocketAddr,
                  socket: TcpListener)
                  -> Connection {
        Connection {
            connection_type: ConnectionType::Server,
            server: Some(ServerConnection {
                server: server,
                socket: socket,
            }),
            client: None,
            peer_addr: peer_addr,
        }
    }

    fn new_client(protocol: Box<Protocol>, peer_addr: SocketAddr, socket: TcpStream) -> Connection {
        Connection {
            connection_type: ConnectionType::Client,
            client: Some(ClientConnection::new(protocol, socket)),
            server: None,
            peer_addr: peer_addr,
        }
    }

    fn peer_addr(&self) -> SocketAddr {
        self.peer_addr
    }

    fn server_ref(&self) -> &ServerConnection {
        self.server.as_ref().unwrap()
    }

    fn client_ref(&self) -> &ClientConnection {
        self.client.as_ref().unwrap()
    }

    fn client_mut(&mut self) -> &mut ClientConnection {
        self.client.as_mut().unwrap()
    }

    fn alive(&self) -> bool {
        return match self.connection_type {
            ConnectionType::Server => true,
            ConnectionType::Client => {
                match self.client_ref().peer_addr() {
                    Ok(_) => true,
                    Err(_) => false,
                }
            }
        };
    }
}

/// The I/O Loop
pub struct Rio {
    poll: Poll,
    connections: Slab<Connection>,
    running: bool
}

impl Rio {
    /// Instanciate the IOLoop, should be called once.
    pub fn new() -> Rio {
        let poll: Poll = Poll::new().unwrap();
        let connections = Slab::with_capacity(CONNS_MAX);
        Rio {
            running: false,
            poll: poll,
            connections: connections,
        }
    }

    /// Will listen on the given address when the loop will start.
    /// The ServerFactory.build_protocol method will be called on every
    /// new client connection.
    pub fn listen(&mut self, addr: &str, server: Box<ServerFactory>) -> Result<Token, io::Error> {
        info!("Rio is listenning on {}", addr);
        let sock_addr: SocketAddr = FromStr::from_str(addr).unwrap();
        debug!("Bind the server socket {}", addr);
        let sock = TcpListener::bind(&sock_addr).unwrap();
        let result = self.connections.insert(Connection::new_server(server, sock_addr, sock));
        match result {
            Ok(token) => {
                let _ = self.poll.register(&self.connections[token].server_ref().socket,
                                           token,
                                           Ready::readable() | Ready::writable(),
                                           PollOpt::edge());
                return Ok(token);
            }
            Err(_) => {
                error!("Cannot register server {:?}", addr);
                return Err(io::Error::new(io::ErrorKind::Other, format!("Cannot register server {:?}", addr)));
            }
        }
    }

    /// Will listen on the given address when the loop will start.
    /// The ServerFactory.build_protocol method will be called on every
    /// new client connection.
    pub fn connect(&mut self, addr: &str, client: Box<Protocol>) -> Result<Token, io::Error> {
        info!("Connecting to socket {}", addr);
        let sock_addr: SocketAddr = FromStr::from_str(addr).unwrap();

        let sock = TcpStream::connect(&sock_addr).unwrap();
        let result = self.connections.insert(Connection::new_client(client, sock_addr, sock));
        match result {
            Ok(token) => {
                let client = self.connections[token].client_mut();
                client.protocol.connection_made(&mut client.transport);
                let _ = self.poll.register(&client.socket,
                                           token,
                                           Ready::all(),
                                           PollOpt::all());
                debug!(" socket {} registered in the poller", addr);
                return Ok(token);
            }
            Err(_) => {
                error!("Cannot register client {:?}", addr);
                return Err(io::Error::new(io::ErrorKind::Other, format!("Cannot register client {:?}", addr)));
            }
        }
    }

    /// Start the io loop
    pub fn run_forever(&mut self) {
        self.run_until(&|_: &Rio| -> bool { true });
    }

    pub fn run_until(&mut self, is_done: &Fn(&Rio) -> bool) {

        info!("Start polling");

        let timeout = Duration::new(1, 0);
        let mut events = Events::with_capacity(1024);

        self.running = true;
        while self.running {
            debug!("Polling...");
            self.poll.poll(&mut events, Some(timeout)).unwrap();

            for event in events.iter() {
                let token = event.token();
                debug!("Got event for {:?}", token);
                let _ = match self.connections[token].connection_type {
                    ConnectionType::Server => self.handle_server(token),
                    ConnectionType::Client => self.handle_client(token, event),
                };
            }
            self.running = is_done(self)
        }
    }

    pub fn contains(&self, token: Token) -> bool {
        return self.connections.contains(token)
    }

    fn handle_server(&mut self, token: Token) -> io::Result<()> {
        while self.running {
            let (sock, addr) = try!(self.connections[token].server_ref().socket.accept());

            info!("Accepting connection from {:?}", addr);

            debug!("Building procotol");
            let protocol = {
                let server = self.connections[token].server.as_ref();
                server.unwrap().server.build_protocol()
            };

            debug!("Take a token for the connection");
            let result = self.connections.insert(Connection::new_client(protocol, addr, sock));
            match result {
                Ok(client_token) => {
                    debug!("Registering procotol");
                    let mut client = self.connections[client_token].client_mut();
                    client.protocol.connection_made(&mut client.transport);
                    try!(self.poll.register(&client.socket,
                                            client_token,
                                            Ready::readable() | Ready::writable(),
                                            PollOpt::edge() | PollOpt::oneshot()));
                }
                Err(_) => error!("Cannot register client"),

            }
        }
        Ok(())
    }

    fn handle_client(&mut self, token: Token, event: Event) -> io::Result<()> {
        debug!("handle client, {:?}", event);

        if !&self.connections.contains(token) {
            error!("Ignoring unkown token to handle");
            return Ok(());
        }

        let kind = event.kind();

        if !&self.connections[token].alive() || kind.is_error() {
            error!("Connection failed {:?}", &self.connections[token].peer_addr);
            info!("Removing connection {:?}",
                  &self.connections[token].peer_addr);

            {
                let client = &mut self.connections[token].client_mut();
                client.protocol.connection_lost(Reason::ConnectionError);
            }
            self.connections.remove(token);
            return Ok(());
        }

        let mut finished = false;
        let client_addr = &self.connections[token].client_ref().peer_addr().unwrap().clone();
        {
            let mut client = &mut self.connections[token].client_mut();

            debug!("handle client {:?} {:?}", token, client_addr);

            if kind.is_hup() {
                debug!("handle hup {:?} {:?}", token, client_addr);
                client.handle_hup();
                finished = true;
            } else {
                if kind.is_readable() {
                    debug!("handle readable {:?} {:?}", token, client_addr);
                    info!("++++++++++++++++++++++++++++++");
                    try!(client.handle_read());
                    info!("******************************");
                }

                if kind.is_writable() || client.transport.should_write() {
                    debug!("handle writable {:?} {:?}", token, client_addr);
                    client.handle_write();
                }
            }

            if client.is_finished() {
                info!("Closing connection with {:?} {:?}", token, client_addr);
                match client.peer_addr() {
                    Ok(addr) => info!("Connection closed {:?}", addr),
                    Err(_) => error!("Connection closed (Peer already disconnected)"),
                }
                if client.transport.hup() {
                    info!("Peer hang up {:?} {:?}", token, client_addr);
                    client.protocol.connection_lost(Reason::HangUp);
                } else {
                    info!("Connection lost {:?} {:?}", token, client_addr);
                    client.protocol.connection_lost(Reason::ConnectionLost);
                }
                try!(self.poll.deregister(&client.socket));
                finished = true;
            } else {
                info!("Reregister token {:?} {:?}", token, client_addr);
                try!(self.poll.reregister(&client.socket, token, client.interest, PollOpt::edge()));
            }
        }

        if finished {
            info!("Removing connection {:?} {:?}", token, client_addr);
            self.connections.remove(token);
        }

        debug!("end handle client {:?} {:?}", token, client_addr);
        Ok(())
    }
}
<commit_msg>Fix stucking in read data that not comes<commit_after>use std::io;
use std::net::SocketAddr;
use std::str::FromStr;
use std::time::Duration;

use std::io::{Read, Write};  // Used for TcpStream.read,  TcpStream.write
use mio::{Poll, Token, Events, Event, Ready, PollOpt};
use mio::tcp::{TcpListener, TcpStream};

use slab;
use interface::{ServerFactory, Protocol, Reason};
use transport::Transport;

const CONNS_MAX: usize = 65_536;
const BUF_SIZE: usize = 4096;

type Slab<T> = slab::Slab<T, Token>;

#[derive(Clone)]
enum ConnectionType {
    Server,
    Client,
}

struct ServerConnection {
    server: Box<ServerFactory>,
    socket: TcpListener,
}

struct ClientConnection {
    protocol: Box<Protocol>,
    socket: TcpStream,
    interest: Ready,
    transport: Transport,
}

impl ClientConnection {
    fn new(protocol: Box<Protocol>, socket: TcpStream) -> ClientConnection {
        ClientConnection {
            protocol: protocol,
            socket: socket,
            interest: Ready::hup() | Ready::readable(),
            transport: Transport::new(),
        }
    }

    fn peer_addr(&self) -> io::Result<SocketAddr> {
        self.socket.peer_addr()
    }

    fn is_finished(&self) -> bool {
        self.interest == Ready::none()
    }

    fn handle_hup(&mut self) {
        self.interest = Ready::none();
    }

    fn handle_read(&mut self) -> io::Result<()> {
        let mut read_bytes: Vec<u8> = Vec::new();
        loop {
            let (buf, read_len) = {
                let mut buf = [0; BUF_SIZE];
                let read_len = try!(self.socket.read(&mut buf[..]));
                // let s_data = str::from_utf8(&buf).unwrap();
                // info!("<<< {}", s_data);
                (buf, read_len)
            };
            if read_len > 0 {
                read_bytes.extend(buf[0..read_len].iter());
                if read_len < BUF_SIZE {
                    debug!("Nothing more to read");
                    break;
                } else {
                    debug!("More data to read");
                }
            } else {
                debug!("Nothing to read");
                break;
            }
        }
        if read_bytes.len() > 0 {
            self.protocol.data_received(&read_bytes[..], &mut self.transport);
        }
        Ok(())
    }

    fn handle_write(&mut self) {

        {
            // a block where transport muting

            debug!("handle write");
            let buf = &mut self.transport.buf();
            let to_write_len = buf.len();
            if to_write_len > 0 {
                // let s_data = str::from_utf8(&buf[..]).unwrap();
                // info!(">>> {}", s_data);

                let result = self.socket.write(&buf[..]);
                match result {
                    Ok(written_len) => {
                        debug!("Write {} bytes", written_len);
                        if to_write_len != written_len {
                            error!("{} bytes to write but {} written, hanging up",
                                   to_write_len,
                                   written_len);
                            self.interest = Ready::hup();
                        }
                    }
                    Err(err) => {
                        error!("Error {} while writing to the socket, disconnecting", err);
                        self.interest = Ready::hup();
                    }
                };
            }
        };

        self.transport.clear();

        if self.transport.hup() {
            info!("Peer is disconnecting, will unregister connection");
            self.interest = Ready::none();
        }
    }
}

struct Connection {
    connection_type: ConnectionType,
    server: Option<ServerConnection>,
    client: Option<ClientConnection>,
    peer_addr: SocketAddr,
}

#[allow(dead_code)]
impl Connection {
    fn new_server(server: Box<ServerFactory>,
                  peer_addr: SocketAddr,
                  socket: TcpListener)
                  -> Connection {
        Connection {
            connection_type: ConnectionType::Server,
            server: Some(ServerConnection {
                server: server,
                socket: socket,
            }),
            client: None,
            peer_addr: peer_addr,
        }
    }

    fn new_client(protocol: Box<Protocol>, peer_addr: SocketAddr, socket: TcpStream) -> Connection {
        Connection {
            connection_type: ConnectionType::Client,
            client: Some(ClientConnection::new(protocol, socket)),
            server: None,
            peer_addr: peer_addr,
        }
    }

    fn peer_addr(&self) -> SocketAddr {
        self.peer_addr
    }

    fn server_ref(&self) -> &ServerConnection {
        self.server.as_ref().unwrap()
    }

    fn client_ref(&self) -> &ClientConnection {
        self.client.as_ref().unwrap()
    }

    fn client_mut(&mut self) -> &mut ClientConnection {
        self.client.as_mut().unwrap()
    }

    fn alive(&self) -> bool {
        return match self.connection_type {
            ConnectionType::Server => true,
            ConnectionType::Client => {
                match self.client_ref().peer_addr() {
                    Ok(_) => true,
                    Err(_) => false,
                }
            }
        };
    }
}

/// The I/O Loop
pub struct Rio {
    poll: Poll,
    connections: Slab<Connection>,
    running: bool
}

impl Rio {
    /// Instanciate the IOLoop, should be called once.
    pub fn new() -> Rio {
        let poll: Poll = Poll::new().unwrap();
        let connections = Slab::with_capacity(CONNS_MAX);
        Rio {
            running: false,
            poll: poll,
            connections: connections,
        }
    }

    /// Will listen on the given address when the loop will start.
    /// The ServerFactory.build_protocol method will be called on every
    /// new client connection.
    pub fn listen(&mut self, addr: &str, server: Box<ServerFactory>) -> Result<Token, io::Error> {
        info!("Rio is listenning on {}", addr);
        let sock_addr: SocketAddr = FromStr::from_str(addr).unwrap();
        debug!("Bind the server socket {}", addr);
        let sock = TcpListener::bind(&sock_addr).unwrap();
        let result = self.connections.insert(Connection::new_server(server, sock_addr, sock));
        match result {
            Ok(token) => {
                let _ = self.poll.register(&self.connections[token].server_ref().socket,
                                           token,
                                           Ready::readable() | Ready::writable(),
                                           PollOpt::edge());
                return Ok(token);
            }
            Err(_) => {
                error!("Cannot register server {:?}", addr);
                return Err(io::Error::new(io::ErrorKind::Other, format!("Cannot register server {:?}", addr)));
            }
        }
    }

    /// Will listen on the given address when the loop will start.
    /// The ServerFactory.build_protocol method will be called on every
    /// new client connection.
    pub fn connect(&mut self, addr: &str, client: Box<Protocol>) -> Result<Token, io::Error> {
        info!("Connecting to socket {}", addr);
        let sock_addr: SocketAddr = FromStr::from_str(addr).unwrap();

        let sock = TcpStream::connect(&sock_addr).unwrap();
        let result = self.connections.insert(Connection::new_client(client, sock_addr, sock));
        match result {
            Ok(token) => {
                let client = self.connections[token].client_mut();
                client.protocol.connection_made(&mut client.transport);
                let _ = self.poll.register(&client.socket,
                                           token,
                                           Ready::all(),
                                           PollOpt::all());
                debug!(" socket {} registered in the poller", addr);
                return Ok(token);
            }
            Err(_) => {
                error!("Cannot register client {:?}", addr);
                return Err(io::Error::new(io::ErrorKind::Other, format!("Cannot register client {:?}", addr)));
            }
        }
    }

    /// Start the io loop
    pub fn run_forever(&mut self) {
        self.run_until(&|_: &Rio| -> bool { true });
    }

    pub fn run_until(&mut self, is_done: &Fn(&Rio) -> bool) {

        info!("Start polling");

        let timeout = Duration::from_millis(500);
        let mut events = Events::with_capacity(1024);

        self.running = true;
        while self.running {
            // debug!("Polling...");
            self.poll.poll(&mut events, Some(timeout)).unwrap();

            for event in events.iter() {
                let token = event.token();
                debug!("Got event for {:?}", token);
                let _ = match self.connections[token].connection_type {
                    ConnectionType::Server => self.handle_server(token),
                    ConnectionType::Client => self.handle_client(token, event),
                };
            }
            self.running = is_done(self)
        }
    }

    pub fn contains(&self, token: Token) -> bool {
        return self.connections.contains(token)
    }

    fn handle_server(&mut self, token: Token) -> io::Result<()> {
        while self.running {
            let (sock, addr) = try!(self.connections[token].server_ref().socket.accept());

            info!("Accepting connection from {:?}", addr);

            debug!("Building procotol");
            let protocol = {
                let server = self.connections[token].server.as_ref();
                server.unwrap().server.build_protocol()
            };

            debug!("Take a token for the connection");
            let result = self.connections.insert(Connection::new_client(protocol, addr, sock));
            match result {
                Ok(client_token) => {
                    debug!("Registering procotol");
                    let mut client = self.connections[client_token].client_mut();
                    client.protocol.connection_made(&mut client.transport);
                    try!(self.poll.register(&client.socket,
                                            client_token,
                                            Ready::readable() | Ready::writable(),
                                            PollOpt::edge() | PollOpt::oneshot()));
                }
                Err(_) => error!("Cannot register client"),

            }
        }
        Ok(())
    }

    fn handle_client(&mut self, token: Token, event: Event) -> io::Result<()> {
        debug!("handle client, {:?}", event);

        if !&self.connections.contains(token) {
            error!("Ignoring unkown token to handle");
            return Ok(());
        }

        let kind = event.kind();

        if !&self.connections[token].alive() || kind.is_error() {
            error!("Connection failed {:?}", &self.connections[token].peer_addr);
            info!("Removing connection {:?}",
                  &self.connections[token].peer_addr);

            {
                let client = &mut self.connections[token].client_mut();
                client.protocol.connection_lost(Reason::ConnectionError);
            }
            self.connections.remove(token);
            return Ok(());
        }

        let mut finished = false;
        let client_addr = &self.connections[token].client_ref().peer_addr().unwrap().clone();
        {
            let mut client = &mut self.connections[token].client_mut();

            debug!("handle client {:?} {:?}", token, client_addr);

            if kind.is_hup() {
                debug!("handle hup {:?} {:?}", token, client_addr);
                client.handle_hup();
                finished = true;
            } else {
                if kind.is_readable() {
                    debug!("handle readable {:?} {:?}", token, client_addr);
                    try!(client.handle_read());
                }

                if kind.is_writable() || client.transport.should_write() {
                    debug!("handle writable {:?} {:?}", token, client_addr);
                    client.handle_write();
                }
            }

            if client.is_finished() {
                info!("Closing connection with {:?} {:?}", token, client_addr);
                match client.peer_addr() {
                    Ok(addr) => info!("Connection closed {:?}", addr),
                    Err(_) => error!("Connection closed (Peer already disconnected)"),
                }
                if client.transport.hup() {
                    info!("Peer hang up {:?} {:?}", token, client_addr);
                    client.protocol.connection_lost(Reason::HangUp);
                } else {
                    info!("Connection lost {:?} {:?}", token, client_addr);
                    client.protocol.connection_lost(Reason::ConnectionLost);
                }
                try!(self.poll.deregister(&client.socket));
                finished = true;
            } else {
                info!("Reregister token {:?} {:?}", token, client_addr);
                try!(self.poll.reregister(&client.socket, token, client.interest, PollOpt::edge()));
            }
        }

        if finished {
            info!("Removing connection {:?} {:?}", token, client_addr);
            self.connections.remove(token);
        }

        debug!("end handle client {:?} {:?}", token, client_addr);
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
#![feature(type_ascription)]
#![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

use std::intrinsics;

#[allow(dead_code)]
mod byteorder;
#[allow(dead_code, unused_imports, unused_variables, unused_mut)]
mod elf;

mod backtrace_hack;
mod llvm_stackmaps;

const DEMO_ID: i64 = 0;
const SUBCALL_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

fn subcall(data: *mut u8) {
    println!("Enter `subcall`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL_ID, 0, subcall_2, data);
    }
    println!("Finis `subcall`");
}

fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

impl StackMap {
    pub fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        println!("");
        println!("addr: {:?}", addr);

	if let Some(base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                println!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

static mut MAIN_LOCAL: usize = 0;
pub fn main_height() -> usize { unsafe { MAIN_LOCAL } }

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;
use std::sync::RwLock;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use std::path::Path;
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL_ID as usize] = subcall as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    let file = elf::File::open_path(&path)?;

    let stackmap_section = {
        let name = ".llvm_stackmaps".to_string();
        file.get_section(name.clone())
            .ok_or_else(|| DemoError::MissingSection(name))?
    };

    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<commit_msg>dont mangle function names that I am likely to want to disassemble from the debugger.<commit_after>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
#![feature(type_ascription)]
#![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

use std::intrinsics;

#[allow(dead_code)]
mod byteorder;
#[allow(dead_code, unused_imports, unused_variables, unused_mut)]
mod elf;

mod backtrace_hack;
mod llvm_stackmaps;

const DEMO_ID: i64 = 0;
const SUBCALL_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

#[no_mangle]
fn subcall(data: *mut u8) {
    println!("Enter `subcall`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL_ID, 0, subcall_2, data);
        // intrinsics::patchpoint_call(SUBCALL_ID, 13, subcall_2, data);
    }
    println!("Finis `subcall`");
}

#[no_mangle]
fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
        // intrinsics::patchpoint_call(SUBCALL2_ID, 13, subcall_3, data);

    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

impl StackMap {
    pub fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        println!("");
        println!("addr: {:?}", addr);

	if let Some(base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                println!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

static mut MAIN_LOCAL: usize = 0;
pub fn main_height() -> usize { unsafe { MAIN_LOCAL } }

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;
use std::sync::RwLock;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use std::path::Path;
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL_ID as usize] = subcall as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    let file = elf::File::open_path(&path)?;

    let stackmap_section = {
        let name = ".llvm_stackmaps".to_string();
        file.get_section(name.clone())
            .ok_or_else(|| DemoError::MissingSection(name))?
    };

    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall, data.as_mut_ptr());
        // intrinsics::patchpoint_call(DEMO_ID, 13, subcall, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<|endoftext|>


<commit_before>//! System primitives.

use core::ptr::Unique;

use fail;

/// Out of memory.
///
/// In release mode, this will simply abort the process (standard behavior). In debug mode, it will
/// panic, causing debugging to be easier.
pub fn oom() -> ! {
    fail::oom();
}

/// A system call error.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Error {
    /// Sir, we're running outta memory!
    OutOfMemory,
    /// Arithmetic overflow.
    ArithOverflow,
    /// An unknown error occurred.
    Unknown,
}

impl Error {
    /// Handle this error with the appropriate method.
    pub fn handle(self) -> ! {
        match self {
            Error::OutOfMemory | Error::ArithOverflow => oom(),
            Error::Unknown => panic!("Unknown OS error.")
        }
    }
}

/// Cooperatively gives up a timeslice to the OS scheduler.
pub fn yield_now() {
    unsafe {
        #[cfg(unix)]
        syscall!(SCHED_YIELD);

        #[cfg(redox)]
        ::system::syscall::unix::sys_yield();
    }
}

/// Retrieve the end of the current data segment.
///
/// This will not change the state of the process in any way, and is thus safe.
pub fn segment_end() -> Result<*const u8, Error> {
    unsafe {
        sys_brk(0)
    }.map(|x| x as *const _)
}

/// Increment data segment of this process by some, _n_, return a pointer to the new data segment
/// start.
///
/// This uses the system call BRK as backend.
///
/// This is unsafe for multiple reasons. Most importantly, it can create an inconsistent state,
/// because it is not atomic. Thus, it can be used to create Undefined Behavior.
pub unsafe fn inc_brk(n: usize) -> Result<Unique<u8>, Error> {
    let orig_seg_end = try!(segment_end()) as usize;
    if n == 0 { return Ok(Unique::new(orig_seg_end as *mut u8)) }

    let expected_end = try!(orig_seg_end.checked_add(n).ok_or(Error::ArithOverflow));
    let new_seg_end = try!(sys_brk(expected_end));

    if new_seg_end != expected_end {
        // Reset the break.
        try!(sys_brk(orig_seg_end));

        Err(Error::OutOfMemory)
    } else {
        Ok(Unique::new(orig_seg_end as *mut u8))
    }
}

/// Redox syscall, BRK.
#[cfg(target_os = "redox")]
unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
    use system::syscall;

    if let Ok(ret) = syscall::sys_brk(n) {
        Ok(ret)
    } else {
        Err(Error::Unknown)
    }
}

/// Unix syscall, BRK.
#[cfg(not(target_os = "redox"))]
unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
    let ret = syscall!(BRK, n);

    if ret == !0 {
        Err(Error::Unknown)
    } else {
        Ok(ret)
    }
}

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

    #[test]
    fn test_oom() {
        unsafe {
            assert_eq!(inc_brk(9999999999999).err(), Some(Error::OutOfMemory));
        }
    }

    #[test]
    fn test_read() {
        unsafe {
            let mem = *inc_brk(8).unwrap() as *mut u64;
            assert_eq!(*mem, 0);
        }
    }

    #[test]
    fn test_overflow() {
        unsafe {
            assert_eq!(inc_brk(!0).err(), Some(Error::ArithOverflow));
            assert_eq!(inc_brk(!0 - 2000).err(), Some(Error::ArithOverflow));
        }
    }

    #[test]
    fn test_segment_end() {
        assert_eq!(segment_end().unwrap(), segment_end().unwrap());
        assert_eq!(segment_end().unwrap(), segment_end().unwrap());
        assert_eq!(segment_end().unwrap(), segment_end().unwrap());
    }
}
<commit_msg>Fix cfg flags for Redox<commit_after>//! System primitives.

use core::ptr::Unique;

use fail;

/// Out of memory.
///
/// In release mode, this will simply abort the process (standard behavior). In debug mode, it will
/// panic, causing debugging to be easier.
pub fn oom() -> ! {
    fail::oom();
}

/// A system call error.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Error {
    /// Sir, we're running outta memory!
    OutOfMemory,
    /// Arithmetic overflow.
    ArithOverflow,
    /// An unknown error occurred.
    Unknown,
}

impl Error {
    /// Handle this error with the appropriate method.
    pub fn handle(self) -> ! {
        match self {
            Error::OutOfMemory | Error::ArithOverflow => oom(),
            Error::Unknown => panic!("Unknown OS error.")
        }
    }
}

/// Cooperatively gives up a timeslice to the OS scheduler.
pub fn yield_now() {
    unsafe {
        #[cfg(not(target_os = "redox"))]
        syscall!(SCHED_YIELD);

        #[cfg(target_os = "redox")]
        ::system::syscall::unix::sys_yield();
    }
}

/// Retrieve the end of the current data segment.
///
/// This will not change the state of the process in any way, and is thus safe.
pub fn segment_end() -> Result<*const u8, Error> {
    unsafe {
        sys_brk(0)
    }.map(|x| x as *const _)
}

/// Increment data segment of this process by some, _n_, return a pointer to the new data segment
/// start.
///
/// This uses the system call BRK as backend.
///
/// This is unsafe for multiple reasons. Most importantly, it can create an inconsistent state,
/// because it is not atomic. Thus, it can be used to create Undefined Behavior.
pub unsafe fn inc_brk(n: usize) -> Result<Unique<u8>, Error> {
    let orig_seg_end = try!(segment_end()) as usize;
    if n == 0 { return Ok(Unique::new(orig_seg_end as *mut u8)) }

    let expected_end = try!(orig_seg_end.checked_add(n).ok_or(Error::ArithOverflow));
    let new_seg_end = try!(sys_brk(expected_end));

    if new_seg_end != expected_end {
        // Reset the break.
        try!(sys_brk(orig_seg_end));

        Err(Error::OutOfMemory)
    } else {
        Ok(Unique::new(orig_seg_end as *mut u8))
    }
}

/// Redox syscall, BRK.
#[cfg(target_os = "redox")]
unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
    use system::syscall;

    if let Ok(ret) = syscall::sys_brk(n) {
        Ok(ret)
    } else {
        Err(Error::Unknown)
    }
}

/// Unix syscall, BRK.
#[cfg(not(target_os = "redox"))]
unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
    let ret = syscall!(BRK, n);

    if ret == !0 {
        Err(Error::Unknown)
    } else {
        Ok(ret)
    }
}

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

    #[test]
    fn test_oom() {
        unsafe {
            assert_eq!(inc_brk(9999999999999).err(), Some(Error::OutOfMemory));
        }
    }

    #[test]
    fn test_read() {
        unsafe {
            let mem = *inc_brk(8).unwrap() as *mut u64;
            assert_eq!(*mem, 0);
        }
    }

    #[test]
    fn test_overflow() {
        unsafe {
            assert_eq!(inc_brk(!0).err(), Some(Error::ArithOverflow));
            assert_eq!(inc_brk(!0 - 2000).err(), Some(Error::ArithOverflow));
        }
    }

    #[test]
    fn test_segment_end() {
        assert_eq!(segment_end().unwrap(), segment_end().unwrap());
        assert_eq!(segment_end().unwrap(), segment_end().unwrap());
        assert_eq!(segment_end().unwrap(), segment_end().unwrap());
    }
}
<|endoftext|>


<commit_before>//! email handles parsing of GPX-spec emails.

extern crate xml;

use errors::*;
use std::io::Read;
use std::iter::Peekable;
use xml::reader::Events;
use xml::reader::XmlEvent;

/// consume consumes a GPX email from the `reader` until it ends.
/// When it returns, the reader will be at the element after the end GPX email
/// tag.
pub fn consume<R: Read>(reader: &mut Peekable<Events<R>>) -> Result<String> {
    let mut email: Option<String> = None;

    while let Some(event) = reader.next() {
        match event.chain_err(|| "error while parsing XML")? {
            XmlEvent::StartElement { name, attributes, .. } => {
                match name.local_name.as_ref() {
                    "email" => {
                        // get required id and domain attributes
                        let id = attributes
                            .iter()
                            .filter(|attr| attr.name.local_name == "id")
                            .nth(0)
                            .ok_or(Error::from(ErrorKind::InvalidElementLacksAttribute("id")))?;

                        let id = id.clone().value;

                        let domain = attributes
                            .iter()
                            .filter(|attr| attr.name.local_name == "domain")
                            .nth(0)
                            .ok_or(Error::from(ErrorKind::InvalidElementLacksAttribute("domain")))?;

                        let domain = domain.clone().value;

                        email = Some(format!("{id}@{domain}", id = id, domain = domain));
                    }
                    _ => Err(Error::from(ErrorKind::InvalidChildElement("email")))?,
                }
            }

            XmlEvent::EndElement { .. } => {
                return Ok(email.unwrap());
            }

            _ => {}
        }
    }

    unreachable!("should return by now");
}

#[cfg(test)]
mod tests {
    use std::io::BufReader;
    use xml::reader::EventReader;

    use super::consume;

    #[test]
    fn consume_simple_email() {
        let email = consume!("<email id=\"me\" domain=\"example.com\" />");

        assert!(email.is_ok());

        let email = email.unwrap();

        assert_eq!(email, "me@example.com");
    }

    #[test]
    fn consume_attrs_reversed() {
        let email = consume!("<email domain=\"example.com\" id=\"me\" />");

        assert!(email.is_ok());

        let email = email.unwrap();

        assert_eq!(email, "me@example.com");
    }

    #[test]
    fn consume_err_no_id() {
        let err = consume!("<email domain='example.com'/>").unwrap_err();

        assert_eq!(err.description(), "invalid element, lacks required attribute");
        assert_eq!(err.to_string(), "invalid element, lacks required attribute id");
    }

    #[test]
    fn consume_err_no_domain() {
        let err = consume!("<email id=\"gpx\" />").unwrap_err();

        assert_eq!(err.description(), "invalid element, lacks required attribute");
        assert_eq!(err.to_string(), "invalid element, lacks required attribute domain");
    }

    #[test]
    fn consume_err_invalid_child_element() {
        let err = consume!("<email id=\"id\" domain=\"domain\"><child /></email>").unwrap_err();

        assert_eq!(err.description(), "invalid child element");
        assert_eq!(err.to_string(), "invalid child element in email");
    }

    #[test]
    fn consume_err_no_ending_tag() {
        let err = consume!("<email id=\"id\" domain=\"domain\">").unwrap_err();

        assert_eq!(err.description(), "error while parsing XML");
    }
}
<commit_msg>rust fmt<commit_after>//! email handles parsing of GPX-spec emails.

extern crate xml;

use errors::*;
use std::io::Read;
use std::iter::Peekable;
use xml::reader::Events;
use xml::reader::XmlEvent;

/// consume consumes a GPX email from the `reader` until it ends.
/// When it returns, the reader will be at the element after the end GPX email
/// tag.
pub fn consume<R: Read>(reader: &mut Peekable<Events<R>>) -> Result<String> {
    let mut email: Option<String> = None;

    while let Some(event) = reader.next() {
        match event.chain_err(|| "error while parsing XML")? {
            XmlEvent::StartElement { name, attributes, .. } => {
                match name.local_name.as_ref() {
                    "email" => {
                        // get required id and domain attributes
                        let id =
                            attributes
                                .iter()
                                .filter(|attr| attr.name.local_name == "id")
                                .nth(0)
                                .ok_or(Error::from(ErrorKind::InvalidElementLacksAttribute("id")))?;

                        let id = id.clone().value;

                        let domain = attributes
                            .iter()
                            .filter(|attr| attr.name.local_name == "domain")
                            .nth(0)
                            .ok_or(Error::from(
                                ErrorKind::InvalidElementLacksAttribute("domain"),
                            ))?;

                        let domain = domain.clone().value;

                        email = Some(format!("{id}@{domain}", id = id, domain = domain));
                    }
                    _ => Err(Error::from(ErrorKind::InvalidChildElement("email")))?,
                }
            }

            XmlEvent::EndElement { .. } => {
                return Ok(email.unwrap());
            }

            _ => {}
        }
    }

    unreachable!("should return by now");
}

#[cfg(test)]
mod tests {
    use std::io::BufReader;
    use xml::reader::EventReader;

    use super::consume;

    #[test]
    fn consume_simple_email() {
        let email = consume!("<email id=\"me\" domain=\"example.com\" />");

        assert!(email.is_ok());

        let email = email.unwrap();

        assert_eq!(email, "me@example.com");
    }

    #[test]
    fn consume_attrs_reversed() {
        let email = consume!("<email domain=\"example.com\" id=\"me\" />");

        assert!(email.is_ok());

        let email = email.unwrap();

        assert_eq!(email, "me@example.com");
    }

    #[test]
    fn consume_err_no_id() {
        let err = consume!("<email domain='example.com'/>").unwrap_err();

        assert_eq!(
            err.description(),
            "invalid element, lacks required attribute"
        );
        assert_eq!(
            err.to_string(),
            "invalid element, lacks required attribute id"
        );
    }

    #[test]
    fn consume_err_no_domain() {
        let err = consume!("<email id=\"gpx\" />").unwrap_err();

        assert_eq!(
            err.description(),
            "invalid element, lacks required attribute"
        );
        assert_eq!(
            err.to_string(),
            "invalid element, lacks required attribute domain"
        );
    }

    #[test]
    fn consume_err_invalid_child_element() {
        let err = consume!("<email id=\"id\" domain=\"domain\"><child /></email>").unwrap_err();

        assert_eq!(err.description(), "invalid child element");
        assert_eq!(err.to_string(), "invalid child element in email");
    }

    #[test]
    fn consume_err_no_ending_tag() {
        let err = consume!("<email id=\"id\" domain=\"domain\">").unwrap_err();

        assert_eq!(err.description(), "error while parsing XML");
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    use model::{Model, TemplateParameter};

    use std::fs::File;
    use std::io::Write;
    use clang::{Clang, Index};
    use tempdir::TempDir;

    use serde_json;

    const INTERFACE: &'static str = r#"
namespace foo { namespace sample {

struct Interface {
    virtual ~Interface() = default;
    virtual void method(int foo) = 0;
    virtual int foo(double bar) = 0;
    virtual bool baz() {return true};
};

}}
"#;

    const TEMPLATE_INTERFACE: &'static str = r#"
namespace foo { namespace bar {

template <typename T, typename U, class V>
class Baz {
    virtual ~Baz() = default;
    Baz(const Baz&) = delete;
    virtual bool boo() = 0;
};

}}
"#;

    fn create_model(input: &str) -> Model {
        let tmp_dir = TempDir::new("cpp-codegen").expect("create temp dir");
        let file_path = tmp_dir.path().join("interface.h");
        let mut tmp_file = File::create(&file_path).expect("create temp file");
        tmp_file.write(input.as_bytes()).expect("write file");
        let clang = Clang::new().expect("instantiate clang");
        let index = Index::new(&clang, false, false);
        let tu = index.parser(&file_path)
            .arguments(&[&"-x", &"c++", &"-std=c++14"])
            .parse()
            .expect("parse interface");
        Model::new(&tu)
    }

    #[test]
    fn should_parse() {
        create_model(INTERFACE);
    }

    #[test]
    fn should_not_include_destructors() {
        let model = create_model(INTERFACE);
        assert!(!model.interfaces[0]
            .clone()
            .methods
            .into_iter()
            .any(|x| x.name == "~Interface"));
    }

    #[test]
    fn should_parse_template_class() {
        create_model(TEMPLATE_INTERFACE);
    }

    #[test]
    fn should_list_template_parameters() {
        let model = create_model(TEMPLATE_INTERFACE);
        assert!(model.interfaces.len() > 0);
        assert_eq!(model.interfaces[0]
                       .clone()
                       .template_parameters
                       .unwrap(),
                   vec![TemplateParameter { type_name: "T".to_string() },
                        TemplateParameter { type_name: "U".to_string() },
                        TemplateParameter { type_name: "V".to_string() }]);
    }

    #[test]
    fn should_generate_random_names_for_anonymous_method_arguments() {

        const INTERFACE_WITH_NAMELESS_ARGUMENT_METHODS: &'static str = r#"
            struct Foo {
                virtual void noArgumentName(double) = 0;
            };
            "#;

        let model = create_model(INTERFACE_WITH_NAMELESS_ARGUMENT_METHODS);
        assert!(serde_json::ser::to_string(&model.interfaces[0].methods[0].arguments[0].name)
            .unwrap()
            .len() > 0)
    }

    #[test]
    fn should_parse_template_methods() {

        const INTERFACE_WITH_TEMPLATE_METHODS: &'static str = r#"
            struct Foo {
                template <typename T> void foo(T bar);
            };
            "#;

        let model = create_model(INTERFACE_WITH_TEMPLATE_METHODS);
        assert_eq!(model.interfaces[0]
                           .clone()
                           .methods[0]
                       .clone()
                       .template_arguments
                       .unwrap(),
                   vec![TemplateParameter { type_name: "T".to_string() }])
    }
}
<commit_msg>Add unit test for namespace parsing<commit_after>#[cfg(test)]
mod tests {
    use model::{Model, TemplateParameter};

    use std::fs::File;
    use std::io::Write;
    use clang::{Clang, Index};
    use tempdir::TempDir;

    use serde_json;

    const INTERFACE: &'static str = r#"
namespace foo { namespace sample {

struct Interface {
    virtual ~Interface() = default;
    virtual void method(int foo) = 0;
    virtual int foo(double bar) = 0;
    virtual bool baz() {return true};
};

}}
"#;

    const TEMPLATE_INTERFACE: &'static str = r#"
namespace foo { namespace bar {

template <typename T, typename U, class V>
class Baz {
    virtual ~Baz() = default;
    Baz(const Baz&) = delete;
    virtual bool boo() = 0;
};

}}
"#;

    fn create_model(input: &str) -> Model {
        let tmp_dir = TempDir::new("cpp-codegen").expect("create temp dir");
        let file_path = tmp_dir.path().join("interface.h");
        let mut tmp_file = File::create(&file_path).expect("create temp file");
        tmp_file.write(input.as_bytes()).expect("write file");
        let clang = Clang::new().expect("instantiate clang");
        let index = Index::new(&clang, false, false);
        let tu = index.parser(&file_path)
            .arguments(&[&"-x", &"c++", &"-std=c++14"])
            .parse()
            .expect("parse interface");
        Model::new(&tu)
    }

    #[test]
    fn should_parse() {
        create_model(INTERFACE);
    }

    #[test]
    fn should_list_namespaces() {
        let model = create_model(INTERFACE);
        assert!(model.interfaces[0].namespaces == vec!["foo".to_string(), "sample".to_string()]);
    }

    #[test]
    fn should_not_include_destructors() {
        let model = create_model(INTERFACE);
        assert!(!model.interfaces[0]
            .clone()
            .methods
            .into_iter()
            .any(|x| x.name == "~Interface"));
    }

    #[test]
    fn should_parse_template_class() {
        create_model(TEMPLATE_INTERFACE);
    }

    #[test]
    fn should_list_template_parameters() {
        let model = create_model(TEMPLATE_INTERFACE);
        assert!(model.interfaces.len() > 0);
        assert_eq!(model.interfaces[0]
                       .clone()
                       .template_parameters
                       .unwrap(),
                   vec![TemplateParameter { type_name: "T".to_string() },
                        TemplateParameter { type_name: "U".to_string() },
                        TemplateParameter { type_name: "V".to_string() }]);
    }

    #[test]
    fn should_generate_random_names_for_anonymous_method_arguments() {

        const INTERFACE_WITH_NAMELESS_ARGUMENT_METHODS: &'static str = r#"
            struct Foo {
                virtual void noArgumentName(double) = 0;
            };
            "#;

        let model = create_model(INTERFACE_WITH_NAMELESS_ARGUMENT_METHODS);
        assert!(serde_json::ser::to_string(&model.interfaces[0].methods[0].arguments[0].name)
            .unwrap()
            .len() > 0)
    }

    #[test]
    fn should_parse_template_methods() {

        const INTERFACE_WITH_TEMPLATE_METHODS: &'static str = r#"
            struct Foo {
                template <typename T> void foo(T bar);
            };
            "#;

        let model = create_model(INTERFACE_WITH_TEMPLATE_METHODS);
        assert_eq!(model.interfaces[0]
                           .clone()
                           .methods[0]
                       .clone()
                       .template_arguments
                       .unwrap(),
                   vec![TemplateParameter { type_name: "T".to_string() }])
    }
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*/

#![link(name="xcb",
       vers="0.3",
       uuid="ef466d26-0620-4f5f-a1d2-1bb9c628e101",
       url= "https://github.com/Aatch/rust-xcb")]

#![license = "MIT"]
#![crate_type="lib"]
#![feature(globs)]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]
extern crate libc;

pub mod ffi {
    pub mod xproto;
    pub mod base;

    pub mod bigreq;
    pub mod composite;
    pub mod damage;
    pub mod dpms;
    pub mod dri2;

    //pub mod ge; not sure about this one...

    pub mod glx;
    pub mod randr;
    pub mod record;
    pub mod render;
    pub mod screensaver;
    pub mod shape;
    pub mod shm;
    pub mod sync;
    pub mod xc_misc;
    pub mod xevie;
    pub mod xf86dri;
    //pub mod xf86vidmode; Same with this one...
    pub mod xfixes;
    pub mod xinerama;
    pub mod xinput;
    //pub mod xkb;
    pub mod xprint;

    #[cfg(enable_xselinux)]
    pub mod xselinux;
    pub mod xtest;
    pub mod xv;
    pub mod xvmc;
}

pub mod base;
pub mod macro;

pub mod xproto;

pub mod xinerama;

pub mod bigreq;
pub mod composite;
pub mod xfixes;
pub mod render;
pub mod shape;
/*
pub mod damage;
pub mod dpms;
pub mod dri2;
//pub mod ge; not sure about this one...

pub mod glx;
pub mod randr;
pub mod record;
pub mod screensaver;
pub mod shm;
pub mod sync;
pub mod xc_misc;
pub mod xevie;
pub mod xf86dri;
//pub mod xf86vidmode; Same with this one...
pub mod xinput;
//pub mod xkb;
pub mod xprint;

#[cfg(enable_xselinux)]
pub mod xselinux;
pub mod xtest;
pub mod xv;
pub mod xvmc;
*/
<commit_msg>Shut the compiler up about warnings<commit_after>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*/

#![link(name="xcb",
       vers="0.3",
       uuid="ef466d26-0620-4f5f-a1d2-1bb9c628e101",
       url= "https://github.com/Aatch/rust-xcb")]

#![license = "MIT"]
#![crate_type="lib"]
#![feature(globs)]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]

#![allow(dead_code)]
#![allow(ctypes)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]

extern crate libc;

pub mod ffi {
    pub mod xproto;
    pub mod base;

    pub mod bigreq;
    pub mod composite;
    pub mod damage;
    pub mod dpms;
    pub mod dri2;

    //pub mod ge; not sure about this one...

    pub mod glx;
    pub mod randr;
    pub mod record;
    pub mod render;
    pub mod screensaver;
    pub mod shape;
    pub mod shm;
    pub mod sync;
    pub mod xc_misc;
    pub mod xevie;
    pub mod xf86dri;
    //pub mod xf86vidmode; Same with this one...
    pub mod xfixes;
    pub mod xinerama;
    pub mod xinput;
    //pub mod xkb;
    pub mod xprint;

    #[cfg(enable_xselinux)]
    pub mod xselinux;
    pub mod xtest;
    pub mod xv;
    pub mod xvmc;
}

pub mod base;
pub mod macro;

pub mod xproto;

pub mod xinerama;

pub mod bigreq;
pub mod composite;
pub mod xfixes;
pub mod render;
pub mod shape;
/*
pub mod damage;
pub mod dpms;
pub mod dri2;
//pub mod ge; not sure about this one...

pub mod glx;
pub mod randr;
pub mod record;
pub mod screensaver;
pub mod shm;
pub mod sync;
pub mod xc_misc;
pub mod xevie;
pub mod xf86dri;
//pub mod xf86vidmode; Same with this one...
pub mod xinput;
//pub mod xkb;
pub mod xprint;

#[cfg(enable_xselinux)]
pub mod xselinux;
pub mod xtest;
pub mod xv;
pub mod xvmc;
*/
<|endoftext|>