<commit_before>use std::cmp;
use image::Pixel;

pub struct HSL {
    pub h: f64, // 0-360 Degree
    pub s: f64, // 0-1 (Percent)
    pub l: f64, // 0-1 (Percent)
}

impl HSL {
    /// Convert Pixel value to HSL
    ///
    /// Algorithm from [go-color] by Brandon Thomson <bt@brandonthomson.com>.
    ///
    /// [go-color]: https://github.com/bthomson/go-color
    pub fn from_pixel<P>(pixel: &P) -> HSL
        where P: Pixel<Subpixel = u8>
    {
        let mut h: f64;
        let s: f64;
        let l: f64;

        let pixel = pixel.clone();
        let rgb = pixel.to_rgb();
        let rgb = rgb.channels();
        let (r, g, b) = (rgb[0], rgb[1], rgb[2]);

        let max = cmp::max(cmp::max(r, g), b);
        let min = cmp::min(cmp::min(r, g), b);

        // Normalized RGB: Divide everything by 255 to get percentages of colors.
        let (r, g, b) = (r as f64 / 255_f64, g as f64 / 255_f64, b as f64 / 255_f64);
        let (min, max) = (min as f64 / 255_f64, max as f64 / 255_f64);

        // Luminosity is the average of the max and min rgb color intensities.
        l = (max + min) / 2_f64;

        // Saturation
        let delta: f64 = max - min;
        if delta == 0_f64 {
    		// it's gray
            return HSL { h: 0_f64, s: 0_f64, l: l};
        }

        // it's not gray
        if l < 0.5_f64 {
            s = delta / (max + min);
        } else {
            s = delta / (2_f64 - max - min);
        }

        // Hue
        let r2 = (((max - r) / 6_f64) + (delta / 2_f64)) / delta;
        let g2 = (((max - g) / 6_f64) + (delta / 2_f64)) / delta;
        let b2 = (((max - b) / 6_f64) + (delta / 2_f64)) / delta;

        h = match max {
            x if x == r => b2 - g2,
            x if x == g => (1_f64 / 3_f64) + r2 - b2,
            _ => (2_f64 / 3_f64) + g2 - r2,
        };

        // Fix wraparounds
        if h < 0 as f64 {
            h += 1_f64;
        } else if h > 1 as f64 {
            h -= 1_f64;
        }

        HSL { h: h * 360_f64, s: s, l: l }
    }
}

#[cfg(test)]
mod test {
    macro_rules! test_rgb_to_hsl {
        (($r:expr, $g:expr, $b:expr) <=> ($h:expr, $s:expr, $l:expr)) => {
            {
                // Round gracefully to half a percent
                const EPSILON: f64 = 0.05;
                // Round gracefully to half a degree
                const EPSILON_DEGREE: f64 = 0.5;

                let rgb = Rgb::from_channels($r as u8, $g as u8, $b as u8, 0_u8);
                let hsl = HSL::from_pixel(&rgb);

                assert!(
                    $h - hsl.h <= EPSILON_DEGREE,
                    "Converting {:?} to HSL: H differs too much. Expected {}, got {}.",
                        rgb, $h, hsl.h
                );
                assert!(
                    $s - hsl.s <= EPSILON,
                    "Converting {:?} to HSL: S differs too much. Expected {}, got {}.",
                        rgb, $s, hsl.s
                );
                assert!(
                    $l - hsl.l <= EPSILON,
                    "Converting {:?} to HSL: L differs too much. Expected {}, got {}.",
                        rgb, $l, hsl.l
                );
            }
        };
    }

    use image::{Rgb, Pixel};
    use super::HSL;

    #[test]
    fn rgb_to_hsl() {
        // black
        test_rgb_to_hsl!( (0, 0, 0) <=> (0_f64, 0_f64, 0_f64) );

        // white
        test_rgb_to_hsl!( (255, 255, 255) <=> (0_f64, 0_f64, 1_f64) );

        // http://rgb.to/rgb/18,35,67
        test_rgb_to_hsl!( (18, 35, 67) <=> (219_f64, 0.58_f64, 0.17_f64) );

        // http://rgb.to/hex/93c6cd
        test_rgb_to_hsl!( (147, 198, 205) <=> (187_f64, 0.37_f64, 0.69_f64) );

        // http://rgb.to/hex/bada55
        test_rgb_to_hsl!( (186, 218, 85) <=> (74_f64, 0.64_f64, 0.59_f64) );

        // http://rgb.to/hex/ff0
        test_rgb_to_hsl!( (255, 255, 0) <=> (60_f64, 1_f64, 0.5_f64) );

        // http://rgb.to/rgb/198,250,172
        test_rgb_to_hsl!( (198, 250, 172) <=> (100_f64, 0.89_f64, 0.83_f64) );

        // http://rgb.to/hex/faadc7
        test_rgb_to_hsl!( (250, 173, 199) <=> (340_f64, 0.89_f64, 0.83_f64) );
    }
}
<commit_msg>HSL to RGB<commit_after>use std::cmp;
use image::{Pixel, Rgb};

#[derive(Debug, PartialEq, PartialOrd, Default)]
pub struct HSL {
    pub h: f64, // 0-360 Degree
    pub s: f64, // 0-1 (Percent)
    pub l: f64, // 0-1 (Percent)
}

impl HSL {
    /// Convert pixel value to HSL
    ///
    /// Algorithm from [go-color] by Brandon Thomson <bt@brandonthomson.com>. (Iternally converts
    /// the pixel to RGB before converting it to HSL.)
    ///
    /// [go-color]: https://github.com/bthomson/go-color
    pub fn from_pixel<P>(pixel: &P) -> HSL
        where P: Pixel<Subpixel = u8>
    {
        HSL::from_rgb(pixel.to_rgb().channels())
    }

    /// Convert RGB pixel (as array of three bytes) to HSL.
    fn from_rgb(rgb: &[u8]) -> HSL {
        let mut h: f64;
        let s: f64;
        let l: f64;

        let (r, g, b) = (rgb[0], rgb[1], rgb[2]);

        let max = cmp::max(cmp::max(r, g), b);
        let min = cmp::min(cmp::min(r, g), b);

        // Normalized RGB: Divide everything by 255 to get percentages of colors.
        let (r, g, b) = (r as f64 / 255_f64, g as f64 / 255_f64, b as f64 / 255_f64);
        let (min, max) = (min as f64 / 255_f64, max as f64 / 255_f64);

        // Luminosity is the average of the max and min rgb color intensities.
        l = (max + min) / 2_f64;

        // Saturation
        let delta: f64 = max - min;
        if delta == 0_f64 {
    		// it's gray
            return HSL { h: 0_f64, s: 0_f64, l: l};
        }

        // it's not gray
        if l < 0.5_f64 {
            s = delta / (max + min);
        } else {
            s = delta / (2_f64 - max - min);
        }

        // Hue
        let r2 = (((max - r) / 6_f64) + (delta / 2_f64)) / delta;
        let g2 = (((max - g) / 6_f64) + (delta / 2_f64)) / delta;
        let b2 = (((max - b) / 6_f64) + (delta / 2_f64)) / delta;

        h = match max {
            x if x == r => b2 - g2,
            x if x == g => (1_f64 / 3_f64) + r2 - b2,
            _ => (2_f64 / 3_f64) + g2 - r2,
        };

        // Fix wraparounds
        if h < 0 as f64 {
            h += 1_f64;
        } else if h > 1 as f64 {
            h -= 1_f64;
        }

        HSL { h: h * 360_f64, s: s, l: l }
    }

    pub fn to_rgb(&self) -> Rgb<u8> {
        if self.s == 0.0 {
            // Achromatic, i.e., grey.
            let l = percent_to_byte(self.l);
            return Rgb::from_channels(l, l, l, 255);
        }

        let h = self.h / 360.0; // treat this as 0..1 instead of degrees
        let s = self.s;
        let l = self.l;

        let q = if l < 0.5 {
            l * (1.0 + s)
        } else {
            l + s - (l * s)
        };
        let p = 2.0 * l - q;

        Rgb::from_channels(percent_to_byte(hue_to_rgb(p, q, h + 1.0 / 3.0)),
                           percent_to_byte(hue_to_rgb(p, q, h)),
                           percent_to_byte(hue_to_rgb(p, q, h - 1.0 / 3.0)),
                           255)
    }
}

fn percent_to_byte(percent: f64) -> u8 {
    (percent * 255.0).round() as u8
}

fn hue_to_rgb(p: f64, q: f64, t: f64) -> f64 {
    let t = if t < 0.0 {
        t + 1.0
    } else if t > 1.0 {
        t - 1.0
    } else {
        t
    };

    let res = if t < 1.0 / 6.0 {
        p + (q - p) * 6.0 * t
    } else if t < 1.0 / 2.0 {
        q
    } else if t < 2.0 / 3.0 {
        p + (q - p) * (2.0 / 3.0 - t) * 6.0
    } else {
        p
    };

    res
}

#[cfg(test)]
mod test {
    macro_rules! test_rgb_to_hsl {
        (($r:expr, $g:expr, $b:expr) <=> ($h:expr, $s:expr, $l:expr)) => {
            {
                // Round gracefully to half a percent
                const EPSILON: f64 = 0.05;
                // Round gracefully to half a degree
                const EPSILON_DEGREE: f64 = 0.5;

                let rgb = Rgb::from_channels($r as u8, $g as u8, $b as u8, 0_u8);
                let hsl = HSL::from_pixel(&rgb);

                assert!(
                    $h - hsl.h <= EPSILON_DEGREE,
                    "Converting {:?} to HSL: H differs too much. Expected {}, got {}.",
                        rgb, $h, hsl.h
                );
                assert!(
                    $s - hsl.s <= EPSILON,
                    "Converting {:?} to HSL: S differs too much. Expected {}, got {}.",
                        rgb, $s, hsl.s
                );
                assert!(
                    $l - hsl.l <= EPSILON,
                    "Converting {:?} to HSL: L differs too much. Expected {}, got {}.",
                        rgb, $l, hsl.l
                );
            }
        };
    }

    use image::{Rgb, Pixel};
    use super::HSL;

    #[test]
    fn rgb_to_hsl() {
        // black
        test_rgb_to_hsl!( (0, 0, 0) <=> (0_f64, 0_f64, 0_f64) );

        // white
        test_rgb_to_hsl!( (255, 255, 255) <=> (0_f64, 0_f64, 1_f64) );

        // http://rgb.to/rgb/18,35,67
        test_rgb_to_hsl!( (18, 35, 67) <=> (219_f64, 0.58_f64, 0.17_f64) );

        // http://rgb.to/hex/93c6cd
        test_rgb_to_hsl!( (147, 198, 205) <=> (187_f64, 0.37_f64, 0.69_f64) );

        // http://rgb.to/hex/bada55
        test_rgb_to_hsl!( (186, 218, 85) <=> (74_f64, 0.64_f64, 0.59_f64) );

        // http://rgb.to/hex/ff0
        test_rgb_to_hsl!( (255, 255, 0) <=> (60_f64, 1_f64, 0.5_f64) );

        // http://rgb.to/rgb/198,250,172
        test_rgb_to_hsl!( (198, 250, 172) <=> (100_f64, 0.89_f64, 0.83_f64) );

        // http://rgb.to/hex/faadc7
        test_rgb_to_hsl!( (250, 173, 199) <=> (340_f64, 0.89_f64, 0.83_f64) );
    }
}
<|endoftext|>


<commit_before>use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};

use bounds::Bounded;
use ops::checked::*;
use ops::saturating::Saturating;
use {Num, NumCast};

pub trait PrimInt:
    Sized
    + Copy
    + Num
    + NumCast
    + Bounded
    + PartialOrd
    + Ord
    + Eq
    + Not<Output = Self>
    + BitAnd<Output = Self>
    + BitOr<Output = Self>
    + BitXor<Output = Self>
    + Shl<usize, Output = Self>
    + Shr<usize, Output = Self>
    + CheckedAdd<Output = Self>
    + CheckedSub<Output = Self>
    + CheckedMul<Output = Self>
    + CheckedDiv<Output = Self>
    + Saturating
{
    /// Returns the number of ones in the binary representation of `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0b01001100u8;
    ///
    /// assert_eq!(n.count_ones(), 3);
    /// ```
    fn count_ones(self) -> u32;

    /// Returns the number of zeros in the binary representation of `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0b01001100u8;
    ///
    /// assert_eq!(n.count_zeros(), 5);
    /// ```
    fn count_zeros(self) -> u32;

    /// Returns the number of leading zeros in the binary representation
    /// of `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0b0101000u16;
    ///
    /// assert_eq!(n.leading_zeros(), 10);
    /// ```
    fn leading_zeros(self) -> u32;

    /// Returns the number of trailing zeros in the binary representation
    /// of `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0b0101000u16;
    ///
    /// assert_eq!(n.trailing_zeros(), 3);
    /// ```
    fn trailing_zeros(self) -> u32;

    /// Shifts the bits to the left by a specified amount amount, `n`, wrapping
    /// the truncated bits to the end of the resulting integer.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    /// let m = 0x3456789ABCDEF012u64;
    ///
    /// assert_eq!(n.rotate_left(12), m);
    /// ```
    fn rotate_left(self, n: u32) -> Self;

    /// Shifts the bits to the right by a specified amount amount, `n`, wrapping
    /// the truncated bits to the beginning of the resulting integer.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    /// let m = 0xDEF0123456789ABCu64;
    ///
    /// assert_eq!(n.rotate_right(12), m);
    /// ```
    fn rotate_right(self, n: u32) -> Self;

    /// Shifts the bits to the left by a specified amount amount, `n`, filling
    /// zeros in the least significant bits.
    ///
    /// This is bitwise equivalent to signed `Shl`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    /// let m = 0x3456789ABCDEF000u64;
    ///
    /// assert_eq!(n.signed_shl(12), m);
    /// ```
    fn signed_shl(self, n: u32) -> Self;

    /// Shifts the bits to the right by a specified amount amount, `n`, copying
    /// the "sign bit" in the most significant bits even for unsigned types.
    ///
    /// This is bitwise equivalent to signed `Shr`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0xFEDCBA9876543210u64;
    /// let m = 0xFFFFEDCBA9876543u64;
    ///
    /// assert_eq!(n.signed_shr(12), m);
    /// ```
    fn signed_shr(self, n: u32) -> Self;

    /// Shifts the bits to the left by a specified amount amount, `n`, filling
    /// zeros in the least significant bits.
    ///
    /// This is bitwise equivalent to unsigned `Shl`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFi64;
    /// let m = 0x3456789ABCDEF000i64;
    ///
    /// assert_eq!(n.unsigned_shl(12), m);
    /// ```
    fn unsigned_shl(self, n: u32) -> Self;

    /// Shifts the bits to the right by a specified amount amount, `n`, filling
    /// zeros in the most significant bits.
    ///
    /// This is bitwise equivalent to unsigned `Shr`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0xFEDCBA9876543210i64;
    /// let m = 0x000FEDCBA9876543i64;
    ///
    /// assert_eq!(n.unsigned_shr(12), m);
    /// ```
    fn unsigned_shr(self, n: u32) -> Self;

    /// Reverses the byte order of the integer.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    /// let m = 0xEFCDAB8967452301u64;
    ///
    /// assert_eq!(n.swap_bytes(), m);
    /// ```
    fn swap_bytes(self) -> Self;

    /// Convert an integer from big endian to the target's endianness.
    ///
    /// On big endian this is a no-op. On little endian the bytes are swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    ///
    /// if cfg!(target_endian = "big") {
    ///     assert_eq!(u64::from_be(n), n)
    /// } else {
    ///     assert_eq!(u64::from_be(n), n.swap_bytes())
    /// }
    /// ```
    fn from_be(x: Self) -> Self;

    /// Convert an integer from little endian to the target's endianness.
    ///
    /// On little endian this is a no-op. On big endian the bytes are swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    ///
    /// if cfg!(target_endian = "little") {
    ///     assert_eq!(u64::from_le(n), n)
    /// } else {
    ///     assert_eq!(u64::from_le(n), n.swap_bytes())
    /// }
    /// ```
    fn from_le(x: Self) -> Self;

    /// Convert `self` to big endian from the target's endianness.
    ///
    /// On big endian this is a no-op. On little endian the bytes are swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    ///
    /// if cfg!(target_endian = "big") {
    ///     assert_eq!(n.to_be(), n)
    /// } else {
    ///     assert_eq!(n.to_be(), n.swap_bytes())
    /// }
    /// ```
    fn to_be(self) -> Self;

    /// Convert `self` to little endian from the target's endianness.
    ///
    /// On little endian this is a no-op. On big endian the bytes are swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    ///
    /// if cfg!(target_endian = "little") {
    ///     assert_eq!(n.to_le(), n)
    /// } else {
    ///     assert_eq!(n.to_le(), n.swap_bytes())
    /// }
    /// ```
    fn to_le(self) -> Self;

    /// Raises self to the power of `exp`, using exponentiation by squaring.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// assert_eq!(2i32.pow(4), 16);
    /// ```
    fn pow(self, exp: u32) -> Self;
}

macro_rules! prim_int_impl {
    ($T:ty, $S:ty, $U:ty) => {
        impl PrimInt for $T {
            #[inline]
            fn count_ones(self) -> u32 {
                <$T>::count_ones(self)
            }

            #[inline]
            fn count_zeros(self) -> u32 {
                <$T>::count_zeros(self)
            }

            #[inline]
            fn leading_zeros(self) -> u32 {
                <$T>::leading_zeros(self)
            }

            #[inline]
            fn trailing_zeros(self) -> u32 {
                <$T>::trailing_zeros(self)
            }

            #[inline]
            fn rotate_left(self, n: u32) -> Self {
                <$T>::rotate_left(self, n)
            }

            #[inline]
            fn rotate_right(self, n: u32) -> Self {
                <$T>::rotate_right(self, n)
            }

            #[inline]
            fn signed_shl(self, n: u32) -> Self {
                ((self as $S) << n) as $T
            }

            #[inline]
            fn signed_shr(self, n: u32) -> Self {
                ((self as $S) >> n) as $T
            }

            #[inline]
            fn unsigned_shl(self, n: u32) -> Self {
                ((self as $U) << n) as $T
            }

            #[inline]
            fn unsigned_shr(self, n: u32) -> Self {
                ((self as $U) >> n) as $T
            }

            #[inline]
            fn swap_bytes(self) -> Self {
                <$T>::swap_bytes(self)
            }

            #[inline]
            fn from_be(x: Self) -> Self {
                <$T>::from_be(x)
            }

            #[inline]
            fn from_le(x: Self) -> Self {
                <$T>::from_le(x)
            }

            #[inline]
            fn to_be(self) -> Self {
                <$T>::to_be(self)
            }

            #[inline]
            fn to_le(self) -> Self {
                <$T>::to_le(self)
            }

            #[inline]
            fn pow(self, exp: u32) -> Self {
                <$T>::pow(self, exp)
            }
        }
    };
}

// prim_int_impl!(type, signed, unsigned);
prim_int_impl!(u8, i8, u8);
prim_int_impl!(u16, i16, u16);
prim_int_impl!(u32, i32, u32);
prim_int_impl!(u64, i64, u64);
#[cfg(has_i128)]
prim_int_impl!(u128, i128, u128);
prim_int_impl!(usize, isize, usize);
prim_int_impl!(i8, i8, u8);
prim_int_impl!(i16, i16, u16);
prim_int_impl!(i32, i32, u32);
prim_int_impl!(i64, i64, u64);
#[cfg(has_i128)]
prim_int_impl!(i128, i128, u128);
prim_int_impl!(isize, isize, usize);
<commit_msg>fix unsigned_shr docs<commit_after>use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};

use bounds::Bounded;
use ops::checked::*;
use ops::saturating::Saturating;
use {Num, NumCast};

pub trait PrimInt:
    Sized
    + Copy
    + Num
    + NumCast
    + Bounded
    + PartialOrd
    + Ord
    + Eq
    + Not<Output = Self>
    + BitAnd<Output = Self>
    + BitOr<Output = Self>
    + BitXor<Output = Self>
    + Shl<usize, Output = Self>
    + Shr<usize, Output = Self>
    + CheckedAdd<Output = Self>
    + CheckedSub<Output = Self>
    + CheckedMul<Output = Self>
    + CheckedDiv<Output = Self>
    + Saturating
{
    /// Returns the number of ones in the binary representation of `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0b01001100u8;
    ///
    /// assert_eq!(n.count_ones(), 3);
    /// ```
    fn count_ones(self) -> u32;

    /// Returns the number of zeros in the binary representation of `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0b01001100u8;
    ///
    /// assert_eq!(n.count_zeros(), 5);
    /// ```
    fn count_zeros(self) -> u32;

    /// Returns the number of leading zeros in the binary representation
    /// of `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0b0101000u16;
    ///
    /// assert_eq!(n.leading_zeros(), 10);
    /// ```
    fn leading_zeros(self) -> u32;

    /// Returns the number of trailing zeros in the binary representation
    /// of `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0b0101000u16;
    ///
    /// assert_eq!(n.trailing_zeros(), 3);
    /// ```
    fn trailing_zeros(self) -> u32;

    /// Shifts the bits to the left by a specified amount amount, `n`, wrapping
    /// the truncated bits to the end of the resulting integer.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    /// let m = 0x3456789ABCDEF012u64;
    ///
    /// assert_eq!(n.rotate_left(12), m);
    /// ```
    fn rotate_left(self, n: u32) -> Self;

    /// Shifts the bits to the right by a specified amount amount, `n`, wrapping
    /// the truncated bits to the beginning of the resulting integer.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    /// let m = 0xDEF0123456789ABCu64;
    ///
    /// assert_eq!(n.rotate_right(12), m);
    /// ```
    fn rotate_right(self, n: u32) -> Self;

    /// Shifts the bits to the left by a specified amount amount, `n`, filling
    /// zeros in the least significant bits.
    ///
    /// This is bitwise equivalent to signed `Shl`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    /// let m = 0x3456789ABCDEF000u64;
    ///
    /// assert_eq!(n.signed_shl(12), m);
    /// ```
    fn signed_shl(self, n: u32) -> Self;

    /// Shifts the bits to the right by a specified amount amount, `n`, copying
    /// the "sign bit" in the most significant bits even for unsigned types.
    ///
    /// This is bitwise equivalent to signed `Shr`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0xFEDCBA9876543210u64;
    /// let m = 0xFFFFEDCBA9876543u64;
    ///
    /// assert_eq!(n.signed_shr(12), m);
    /// ```
    fn signed_shr(self, n: u32) -> Self;

    /// Shifts the bits to the left by a specified amount amount, `n`, filling
    /// zeros in the least significant bits.
    ///
    /// This is bitwise equivalent to unsigned `Shl`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFi64;
    /// let m = 0x3456789ABCDEF000i64;
    ///
    /// assert_eq!(n.unsigned_shl(12), m);
    /// ```
    fn unsigned_shl(self, n: u32) -> Self;

    /// Shifts the bits to the right by a specified amount amount, `n`, filling
    /// zeros in the most significant bits.
    ///
    /// This is bitwise equivalent to unsigned `Shr`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFi64;
    /// let m = 0x0000123456789ABCi64;
    ///
    /// assert_eq!(n.unsigned_shr(12), m);
    /// ```
    fn unsigned_shr(self, n: u32) -> Self;

    /// Reverses the byte order of the integer.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    /// let m = 0xEFCDAB8967452301u64;
    ///
    /// assert_eq!(n.swap_bytes(), m);
    /// ```
    fn swap_bytes(self) -> Self;

    /// Convert an integer from big endian to the target's endianness.
    ///
    /// On big endian this is a no-op. On little endian the bytes are swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    ///
    /// if cfg!(target_endian = "big") {
    ///     assert_eq!(u64::from_be(n), n)
    /// } else {
    ///     assert_eq!(u64::from_be(n), n.swap_bytes())
    /// }
    /// ```
    fn from_be(x: Self) -> Self;

    /// Convert an integer from little endian to the target's endianness.
    ///
    /// On little endian this is a no-op. On big endian the bytes are swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    ///
    /// if cfg!(target_endian = "little") {
    ///     assert_eq!(u64::from_le(n), n)
    /// } else {
    ///     assert_eq!(u64::from_le(n), n.swap_bytes())
    /// }
    /// ```
    fn from_le(x: Self) -> Self;

    /// Convert `self` to big endian from the target's endianness.
    ///
    /// On big endian this is a no-op. On little endian the bytes are swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    ///
    /// if cfg!(target_endian = "big") {
    ///     assert_eq!(n.to_be(), n)
    /// } else {
    ///     assert_eq!(n.to_be(), n.swap_bytes())
    /// }
    /// ```
    fn to_be(self) -> Self;

    /// Convert `self` to little endian from the target's endianness.
    ///
    /// On little endian this is a no-op. On big endian the bytes are swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// let n = 0x0123456789ABCDEFu64;
    ///
    /// if cfg!(target_endian = "little") {
    ///     assert_eq!(n.to_le(), n)
    /// } else {
    ///     assert_eq!(n.to_le(), n.swap_bytes())
    /// }
    /// ```
    fn to_le(self) -> Self;

    /// Raises self to the power of `exp`, using exponentiation by squaring.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::PrimInt;
    ///
    /// assert_eq!(2i32.pow(4), 16);
    /// ```
    fn pow(self, exp: u32) -> Self;
}

macro_rules! prim_int_impl {
    ($T:ty, $S:ty, $U:ty) => {
        impl PrimInt for $T {
            #[inline]
            fn count_ones(self) -> u32 {
                <$T>::count_ones(self)
            }

            #[inline]
            fn count_zeros(self) -> u32 {
                <$T>::count_zeros(self)
            }

            #[inline]
            fn leading_zeros(self) -> u32 {
                <$T>::leading_zeros(self)
            }

            #[inline]
            fn trailing_zeros(self) -> u32 {
                <$T>::trailing_zeros(self)
            }

            #[inline]
            fn rotate_left(self, n: u32) -> Self {
                <$T>::rotate_left(self, n)
            }

            #[inline]
            fn rotate_right(self, n: u32) -> Self {
                <$T>::rotate_right(self, n)
            }

            #[inline]
            fn signed_shl(self, n: u32) -> Self {
                ((self as $S) << n) as $T
            }

            #[inline]
            fn signed_shr(self, n: u32) -> Self {
                ((self as $S) >> n) as $T
            }

            #[inline]
            fn unsigned_shl(self, n: u32) -> Self {
                ((self as $U) << n) as $T
            }

            #[inline]
            fn unsigned_shr(self, n: u32) -> Self {
                ((self as $U) >> n) as $T
            }

            #[inline]
            fn swap_bytes(self) -> Self {
                <$T>::swap_bytes(self)
            }

            #[inline]
            fn from_be(x: Self) -> Self {
                <$T>::from_be(x)
            }

            #[inline]
            fn from_le(x: Self) -> Self {
                <$T>::from_le(x)
            }

            #[inline]
            fn to_be(self) -> Self {
                <$T>::to_be(self)
            }

            #[inline]
            fn to_le(self) -> Self {
                <$T>::to_le(self)
            }

            #[inline]
            fn pow(self, exp: u32) -> Self {
                <$T>::pow(self, exp)
            }
        }
    };
}

// prim_int_impl!(type, signed, unsigned);
prim_int_impl!(u8, i8, u8);
prim_int_impl!(u16, i16, u16);
prim_int_impl!(u32, i32, u32);
prim_int_impl!(u64, i64, u64);
#[cfg(has_i128)]
prim_int_impl!(u128, i128, u128);
prim_int_impl!(usize, isize, usize);
prim_int_impl!(i8, i8, u8);
prim_int_impl!(i16, i16, u16);
prim_int_impl!(i32, i32, u32);
prim_int_impl!(i64, i64, u64);
#[cfg(has_i128)]
prim_int_impl!(i128, i128, u128);
prim_int_impl!(isize, isize, usize);
<|endoftext|>


<commit_before>use std::path::Path;
use semver::Version;
use std::env;
use git2::{self, Repository, Commit, Signature, PushOptions, RemoteCallbacks, Cred};

use commit_analyzer::{self, CommitType};
use error::Error;
use config::Config;

pub fn get_signature(repo: &Repository) -> Result<Signature, Error> {
    let author = {
        let mut author = env::var("GIT_COMMITTER_NAME").map_err(Error::from);

        if author.is_err() {
            let config = try!(repo.config());
            author = config.get_string("user.name").map_err(Error::from);
        }
        try!(author)
    };

    let email = {
        let mut email = env::var("GIT_COMMITTER_EMAIL").map_err(Error::from);

        if email.is_err() {
            let config = try!(repo.config());
            email = config.get_string("user.email").map_err(Error::from);
        }
        try!(email)
    };

    Signature::now(&author, &email).map_err(From::from)
}

fn range_to_head(commit: &str) -> String {
    format!("{}..HEAD", commit)
}

fn format_commit(commit: Commit) -> String {
    format!("{}\n{}", commit.id(), commit.message().unwrap_or(""))
}

fn add<P: AsRef<Path>>(repo: &Repository, files: &[P]) -> Result<(), git2::Error> {
    let mut index = try!(repo.index());

    for path in files {
        try!(index.add_path(path.as_ref()));
    }

    index.write()
}

fn commit(config: &Config, message: &str) -> Result<(), git2::Error> {
    let update_ref = format!("refs/heads/{}", config.branch);
    let repo = &config.repository;

    let oid = try!(repo.refname_to_id("HEAD"));
    let parent_commit = try!(repo.find_commit(oid));
    let parents = vec![&parent_commit];

    let mut index = try!(repo.index());
    let tree_oid = try!(index.write_tree());
    let tree = try!(repo.find_tree(tree_oid));

    repo
        .commit(Some(&update_ref), &config.signature, &config.signature, message, &tree, &parents)
        .map(|_| ())
}

fn create_tag(config: &Config, tag_name: &str, message: &str) -> Result<(), git2::Error> {
    let repo = &config.repository;

    let rev = format!("refs/heads/{}", config.branch);
    let obj = try!(repo.revparse_single(&rev));

    repo.tag(tag_name, &obj, &config.signature, message, false)
        .map(|_| ())
}

pub fn latest_tag(repo: &Repository) -> Option<Version> {
    let tags = match repo.tag_names(None) {
        Ok(tags) => tags,
        Err(_) => return None
    };

    tags.iter()
        .map(|tag| tag.unwrap())
        .filter_map(|tag| Version::parse(&tag[1..]).ok())
        .max()
}

pub fn version_bump_since_latest(repo: &Repository) -> CommitType {
    match latest_tag(repo) {
        Some(t) => {
            let tag = format!("v{}", t.to_string());
            version_bump_since_tag(repo, &tag)
        },
        None => CommitType::Major
    }
}

pub fn version_bump_since_tag(repo: &Repository, tag: &str) -> CommitType {
    let tag = range_to_head(tag);

    let mut walker = repo.revwalk().expect("Creating a revwalk failed");
    walker.push_range(&tag).expect("Adding a range failed");

    let tag = walker.map(|c| repo.find_commit(c.expect("Not a valid commit")).expect("No commit found"))
        .map(format_commit)
        .map(|c| commit_analyzer::analyze_single(&c).expect("Analyzing commit failed"))
        .max().unwrap_or(CommitType::Unknown);

    tag
}

pub fn generate_commit_message(new_version: &str) -> String {
    format!("Bump version to {}", new_version).into()
}

pub fn commit_files(config: &Config, new_version: &str) -> Result<(), Error> {
    let repo = &config.repository;
    let files = ["Cargo.toml", "Cargo.lock", "Changelog.md"];
    let files = files.iter().filter(|filename| {
        let path = Path::new(filename);
        !repo.status_should_ignore(path).expect("Determining ignore status of file failed")
    }).collect::<Vec<_>>();

    try!(add(&config.repository, &files[..]));

    commit(config, &generate_commit_message(new_version)).map_err(Error::from)
}

pub fn tag(config: &Config, tag_name: &str, tag_message: &str) -> Result<(), Error> {
    create_tag(config, &tag_name, &tag_message)
        .map_err(Error::from)
}

pub fn push(config: &Config, tag_name: &str) -> Result<(), Error> {
    let repo      = &config.repository;
    let token     = config.gh_token.as_ref().unwrap();

    let user      = &config.user;
    let repo_name = &config.repository_name;
    let branch    = &config.branch;

    // We need to push both the branch we just committed as well as the tag we created.
    let branch_ref = format!("refs/heads/{}", branch);
    let tag_ref    = format!("refs/tags/{}", tag_name);
    let refs = [&branch_ref[..], &tag_ref[..]];

    // TODO: Get user and repo
    let url = format!("https://github.com/{}/{}.git", user, repo_name);

    let mut remote = try!(repo.remote_anonymous(&url));

    let mut cbs = RemoteCallbacks::new();
    cbs.credentials(|_url, _username, _allowed| {
        Cred::userpass_plaintext(&token, "")
    });
    let mut opts = PushOptions::new();
    opts.remote_callbacks(cbs);

    remote
        .push(&refs, Some(&mut opts))
        .map(|_| ())
        .map_err(Error::from)
}
<commit_msg>style: Remove TODO<commit_after>use std::path::Path;
use semver::Version;
use std::env;
use git2::{self, Repository, Commit, Signature, PushOptions, RemoteCallbacks, Cred};

use commit_analyzer::{self, CommitType};
use error::Error;
use config::Config;

pub fn get_signature(repo: &Repository) -> Result<Signature, Error> {
    let author = {
        let mut author = env::var("GIT_COMMITTER_NAME").map_err(Error::from);

        if author.is_err() {
            let config = try!(repo.config());
            author = config.get_string("user.name").map_err(Error::from);
        }
        try!(author)
    };

    let email = {
        let mut email = env::var("GIT_COMMITTER_EMAIL").map_err(Error::from);

        if email.is_err() {
            let config = try!(repo.config());
            email = config.get_string("user.email").map_err(Error::from);
        }
        try!(email)
    };

    Signature::now(&author, &email).map_err(From::from)
}

fn range_to_head(commit: &str) -> String {
    format!("{}..HEAD", commit)
}

fn format_commit(commit: Commit) -> String {
    format!("{}\n{}", commit.id(), commit.message().unwrap_or(""))
}

fn add<P: AsRef<Path>>(repo: &Repository, files: &[P]) -> Result<(), git2::Error> {
    let mut index = try!(repo.index());

    for path in files {
        try!(index.add_path(path.as_ref()));
    }

    index.write()
}

fn commit(config: &Config, message: &str) -> Result<(), git2::Error> {
    let update_ref = format!("refs/heads/{}", config.branch);
    let repo = &config.repository;

    let oid = try!(repo.refname_to_id("HEAD"));
    let parent_commit = try!(repo.find_commit(oid));
    let parents = vec![&parent_commit];

    let mut index = try!(repo.index());
    let tree_oid = try!(index.write_tree());
    let tree = try!(repo.find_tree(tree_oid));

    repo
        .commit(Some(&update_ref), &config.signature, &config.signature, message, &tree, &parents)
        .map(|_| ())
}

fn create_tag(config: &Config, tag_name: &str, message: &str) -> Result<(), git2::Error> {
    let repo = &config.repository;

    let rev = format!("refs/heads/{}", config.branch);
    let obj = try!(repo.revparse_single(&rev));

    repo.tag(tag_name, &obj, &config.signature, message, false)
        .map(|_| ())
}

pub fn latest_tag(repo: &Repository) -> Option<Version> {
    let tags = match repo.tag_names(None) {
        Ok(tags) => tags,
        Err(_) => return None
    };

    tags.iter()
        .map(|tag| tag.unwrap())
        .filter_map(|tag| Version::parse(&tag[1..]).ok())
        .max()
}

pub fn version_bump_since_latest(repo: &Repository) -> CommitType {
    match latest_tag(repo) {
        Some(t) => {
            let tag = format!("v{}", t.to_string());
            version_bump_since_tag(repo, &tag)
        },
        None => CommitType::Major
    }
}

pub fn version_bump_since_tag(repo: &Repository, tag: &str) -> CommitType {
    let tag = range_to_head(tag);

    let mut walker = repo.revwalk().expect("Creating a revwalk failed");
    walker.push_range(&tag).expect("Adding a range failed");

    let tag = walker.map(|c| repo.find_commit(c.expect("Not a valid commit")).expect("No commit found"))
        .map(format_commit)
        .map(|c| commit_analyzer::analyze_single(&c).expect("Analyzing commit failed"))
        .max().unwrap_or(CommitType::Unknown);

    tag
}

pub fn generate_commit_message(new_version: &str) -> String {
    format!("Bump version to {}", new_version).into()
}

pub fn commit_files(config: &Config, new_version: &str) -> Result<(), Error> {
    let repo = &config.repository;
    let files = ["Cargo.toml", "Cargo.lock", "Changelog.md"];
    let files = files.iter().filter(|filename| {
        let path = Path::new(filename);
        !repo.status_should_ignore(path).expect("Determining ignore status of file failed")
    }).collect::<Vec<_>>();

    try!(add(&config.repository, &files[..]));

    commit(config, &generate_commit_message(new_version)).map_err(Error::from)
}

pub fn tag(config: &Config, tag_name: &str, tag_message: &str) -> Result<(), Error> {
    create_tag(config, &tag_name, &tag_message)
        .map_err(Error::from)
}

pub fn push(config: &Config, tag_name: &str) -> Result<(), Error> {
    let repo      = &config.repository;
    let token     = config.gh_token.as_ref().unwrap();

    let user      = &config.user;
    let repo_name = &config.repository_name;
    let branch    = &config.branch;

    // We need to push both the branch we just committed as well as the tag we created.
    let branch_ref = format!("refs/heads/{}", branch);
    let tag_ref    = format!("refs/tags/{}", tag_name);
    let refs = [&branch_ref[..], &tag_ref[..]];

    let url = format!("https://github.com/{}/{}.git", user, repo_name);

    let mut remote = try!(repo.remote_anonymous(&url));

    let mut cbs = RemoteCallbacks::new();
    cbs.credentials(|_url, _username, _allowed| {
        Cred::userpass_plaintext(&token, "")
    });
    let mut opts = PushOptions::new();
    opts.remote_callbacks(cbs);

    remote
        .push(&refs, Some(&mut opts))
        .map(|_| ())
        .map_err(Error::from)
}
<|endoftext|>


<commit_before>extern crate image;

use image::Rgb;

pub struct HSL {
    hue: f32,
    sat: f32,
    lum: f32,
}

impl HSL {
    pub fn new(hue: f32, sat: f32, lum: f32) -> HSL {
        HSL {
            hue: hue,
            sat: sat,
            lum: lum,
        }
    }

    // http://www.w3.org/TR/css3-color/#hsl-color
    pub fn rgb(&self) -> Rgb<u8> {
        let hue = self.hue / 360.0;
        let sat = self.sat / 100.0;
        let lum = self.lum / 100.0;

        let b = if lum <= 0.5 {
            lum * (sat + 1.0)
        } else {
            lum + sat - lum * sat
        };
        let a = lum * 2.0 - b;

        let r = HSL::hue_to_rgb(a, b, hue + 1.0 / 3.0);
        let g = HSL::hue_to_rgb(a, b, hue);
        let b = HSL::hue_to_rgb(a, b, hue - 1.0 / 3.0);

        Rgb([(r * 255.0).round() as u8, (g * 255.0).round() as u8, (b * 255.0).round() as u8])
    }

    fn hue_to_rgb(a: f32, b: f32, hue: f32) -> f32 {
        let h = if hue < 0.0 {
            hue + 1.0
        } else if hue > 1.0 {
            hue - 1.0
        } else {
            hue
        };

        if h < 1.0 / 6.0 {
            return a + (b - a) * 6.0 * h;
        }

        if h < 1.0 / 2.0 {
            return b;
        }

        if h < 2.0 / 3.0 {
            return a + (b - a) * (2.0 / 3.0 - h) * 6.0;
        }

        a
    }
}

#[cfg(test)]
mod tests {
    use super::HSL;
    use image::Rgb;

    #[test]
    fn it_converts_black() {
        let black = Rgb([0, 0, 0]);
        let rgb = HSL::new(0.0, 0.0, 0.0).rgb();
        assert_eq!(black, rgb);
    }

    #[test]
    fn it_converts_white() {
        let white = Rgb([255, 255, 255]);
        let rgb = HSL::new(0.0, 0.0, 100.0).rgb();
        assert_eq!(white, rgb);
    }

    #[test]
    fn it_converts_red() {
        let red = Rgb([255, 0, 0]);
        let rgb = HSL::new(0.0, 100.0, 50.0).rgb();
        assert_eq!(red, rgb);
    }

    #[test]
    fn it_converts_green() {
        let green = Rgb([0, 255, 0]);
        let rgb = HSL::new(120.0, 100.0, 50.0).rgb();
        assert_eq!(green, rgb);
    }

    #[test]
    fn it_converts_blue() {
        let blue = Rgb([0, 0, 255]);
        let rgb = HSL::new(240.0, 100.0, 50.0).rgb();
        assert_eq!(blue, rgb);
    }
}
<commit_msg>Apply rustfmt rules<commit_after>extern crate image;

use image::Rgb;

pub struct HSL {
    hue: f32,
    sat: f32,
    lum: f32,
}

impl HSL {
    pub fn new(hue: f32, sat: f32, lum: f32) -> HSL {
        HSL {
            hue: hue,
            sat: sat,
            lum: lum,
        }
    }

    // http://www.w3.org/TR/css3-color/#hsl-color
    pub fn rgb(&self) -> Rgb<u8> {
        let hue = self.hue / 360.0;
        let sat = self.sat / 100.0;
        let lum = self.lum / 100.0;

        let b = if lum <= 0.5 {
            lum * (sat + 1.0)
        } else {
            lum + sat - lum * sat
        };
        let a = lum * 2.0 - b;

        let r = HSL::hue_to_rgb(a, b, hue + 1.0 / 3.0);
        let g = HSL::hue_to_rgb(a, b, hue);
        let b = HSL::hue_to_rgb(a, b, hue - 1.0 / 3.0);

        Rgb([(r * 255.0).round() as u8,
             (g * 255.0).round() as u8,
             (b * 255.0).round() as u8])
    }

    fn hue_to_rgb(a: f32, b: f32, hue: f32) -> f32 {
        let h = if hue < 0.0 {
            hue + 1.0
        } else if hue > 1.0 {
            hue - 1.0
        } else {
            hue
        };

        if h < 1.0 / 6.0 {
            return a + (b - a) * 6.0 * h;
        }

        if h < 1.0 / 2.0 {
            return b;
        }

        if h < 2.0 / 3.0 {
            return a + (b - a) * (2.0 / 3.0 - h) * 6.0;
        }

        a
    }
}

#[cfg(test)]
mod tests {
    use super::HSL;
    use image::Rgb;

    #[test]
    fn it_converts_black() {
        let black = Rgb([0, 0, 0]);
        let rgb = HSL::new(0.0, 0.0, 0.0).rgb();
        assert_eq!(black, rgb);
    }

    #[test]
    fn it_converts_white() {
        let white = Rgb([255, 255, 255]);
        let rgb = HSL::new(0.0, 0.0, 100.0).rgb();
        assert_eq!(white, rgb);
    }

    #[test]
    fn it_converts_red() {
        let red = Rgb([255, 0, 0]);
        let rgb = HSL::new(0.0, 100.0, 50.0).rgb();
        assert_eq!(red, rgb);
    }

    #[test]
    fn it_converts_green() {
        let green = Rgb([0, 255, 0]);
        let rgb = HSL::new(120.0, 100.0, 50.0).rgb();
        assert_eq!(green, rgb);
    }

    #[test]
    fn it_converts_blue() {
        let blue = Rgb([0, 0, 255]);
        let rgb = HSL::new(240.0, 100.0, 50.0).rgb();
        assert_eq!(blue, rgb);
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

// use cgmath::{Vector2};
use core_types::{ZInt/*, MapPos*/};

pub enum Dir {
  NorthEast,
  East,
  SouthEast,
  SouthWest,
  West,
  NorthWest,
}

/*
const DIR_TO_POS_DIFF: [[Vector2<ZInt>; 6]; 2] = [
    [
        Vector2{x: 1, y: -1},
        Vector2{x: 1, y: 0},
        Vector2{x: 1, y: 1},
        Vector2{x: 0, y: 1},
        Vector2{x: -1, y: 0},
        Vector2{x: 0, y: -1},
    ],
    [
        Vector2{x: 0, y: -1},
        Vector2{x: 1, y: 0},
        Vector2{x: 0, y: 1},
        Vector2{x: -1, y: 1},
        Vector2{x: -1, y: 0},
        Vector2{x: -1, y: -1},
    ]
];
*/

impl Dir {
    pub fn from_int(n: ZInt) -> Dir {
        assert!(n >= 0 && n < 6);
        let dirs = [
            Dir::NorthEast,
            Dir::East,
            Dir::SouthEast,
            Dir::SouthWest,
            Dir::West,
            Dir::NorthWest,
        ];
        dirs[n as uint]
    }

    pub fn to_int(&self) -> ZInt {
        match *self {
            Dir::NorthEast => 0,
            Dir::East => 1,
            Dir::SouthEast => 2,
            Dir::SouthWest => 3,
            Dir::West => 4,
            Dir::NorthWest => 5,
        }
    }

    /*
    pub fn get_dir_from_to(from: MapPos, to: MapPos) -> Dir {
        // assert!(from.distance(to) == 1);
        let diff = to.v - from.v;
        for i in range(0u, 6) {
            if diff == DIR_TO_POS_DIFF[(from.v.y % 2) as uint][i] {
                return Dir::from_int(i as ZInt);
            }
        }
        panic!("impossible positions: {}, {}", from, to);
    }

    pub fn get_neighbour_pos(pos: MapPos, dir: Dir) -> MapPos {
        let is_odd_row = pos.v.y % 2 == 1;
        let subtable_index = if is_odd_row { 1 } else { 0 };
        let direction_index = dir.to_int();
        assert!(direction_index >= 0 && direction_index < 6);
        let difference = DIR_TO_POS_DIFF[subtable_index][direction_index as uint];
        MapPos{v: pos.v + difference}
    }
    */
}

pub struct DirIter {
    index: ZInt,
}

impl DirIter {
    pub fn new() -> Self {
        DirIter{index: 0}
    }
}

impl Iterator for DirIter {
    type Item = Dir;

    fn next(&mut self) -> Option<Dir> {
        self.index += 1;
        if self.index == 6 {
            None
        } else {
            Some(Dir::from_int(self.index))
        }
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/dir.rs: Fixed iterator<commit_after>// See LICENSE file for copyright and license details.

// use cgmath::{Vector2};
use core_types::{ZInt/*, MapPos*/};

pub enum Dir {
  NorthEast,
  East,
  SouthEast,
  SouthWest,
  West,
  NorthWest,
}

/*
const DIR_TO_POS_DIFF: [[Vector2<ZInt>; 6]; 2] = [
    [
        Vector2{x: 1, y: -1},
        Vector2{x: 1, y: 0},
        Vector2{x: 1, y: 1},
        Vector2{x: 0, y: 1},
        Vector2{x: -1, y: 0},
        Vector2{x: 0, y: -1},
    ],
    [
        Vector2{x: 0, y: -1},
        Vector2{x: 1, y: 0},
        Vector2{x: 0, y: 1},
        Vector2{x: -1, y: 1},
        Vector2{x: -1, y: 0},
        Vector2{x: -1, y: -1},
    ]
];
*/

impl Dir {
    pub fn from_int(n: ZInt) -> Dir {
        assert!(n >= 0 && n < 6);
        let dirs = [
            Dir::NorthEast,
            Dir::East,
            Dir::SouthEast,
            Dir::SouthWest,
            Dir::West,
            Dir::NorthWest,
        ];
        dirs[n as uint]
    }

    pub fn to_int(&self) -> ZInt {
        match *self {
            Dir::NorthEast => 0,
            Dir::East => 1,
            Dir::SouthEast => 2,
            Dir::SouthWest => 3,
            Dir::West => 4,
            Dir::NorthWest => 5,
        }
    }

    /*
    pub fn get_dir_from_to(from: MapPos, to: MapPos) -> Dir {
        // assert!(from.distance(to) == 1);
        let diff = to.v - from.v;
        for i in range(0u, 6) {
            if diff == DIR_TO_POS_DIFF[(from.v.y % 2) as uint][i] {
                return Dir::from_int(i as ZInt);
            }
        }
        panic!("impossible positions: {}, {}", from, to);
    }

    pub fn get_neighbour_pos(pos: MapPos, dir: Dir) -> MapPos {
        let is_odd_row = pos.v.y % 2 == 1;
        let subtable_index = if is_odd_row { 1 } else { 0 };
        let direction_index = dir.to_int();
        assert!(direction_index >= 0 && direction_index < 6);
        let difference = DIR_TO_POS_DIFF[subtable_index][direction_index as uint];
        MapPos{v: pos.v + difference}
    }
    */
}

pub struct DirIter {
    index: ZInt,
}

impl DirIter {
    pub fn new() -> Self {
        DirIter{index: 0}
    }
}

impl Iterator for DirIter {
    type Item = Dir;

    fn next(&mut self) -> Option<Dir> {
        let next_dir = if self.index == 6 {
            None
        } else {
            Some(Dir::from_int(self.index))
        };
        self.index += 1;
        next_dir
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>//! Read and write Elasto Mania level files.

use std::io::{ Read };
use std::fs::File;
use byteorder::{ ByteOrder, ReadBytesExt, LittleEndian };
use super::{ Position, trim_string };

// Magic arbitrary number; signifies end-of-data. Followed by Top10 list(s).
const EOD: i32 = 0x0067103A;
// Magic arbitrary number; signifies end-of-file.
const EOF: i32 = 0x00845D52;

/// Game version.
#[derive(Debug, PartialEq)]
pub enum Version {
    Across,
    Elma
}

impl Default for Version {
    fn default() -> Version { Version::Elma }
}

/// Type of object.
#[derive(Debug, PartialEq)]
pub enum ObjectType {
    Apple,
    Exit,
    Killer,
    Player
}

impl Default for ObjectType {
    fn default() -> ObjectType { ObjectType::Apple }
}

/// Object struct. Every level requires one `ObjectType::Player` Object and at least one `ObjectType::Exit` Object.
#[derive(Debug, Default, PartialEq)]
pub struct Object {
    /// Position. See `Position` struct.
    pub position: Position<f64>,
    /// Type of Object, see `ObjectType`.
    pub object_type: ObjectType,
    /// Applies to `ObjectType::Apple` only.
    ///
    /// 0 = normal
    /// 1 = gravity up
    /// 2 = gravity down
    /// 3 = gravity left
    /// 4 = gravity right
    // TODO: enum with gravity
    pub gravity: i32,
    /// Applies to `ObjectType::Apple` only. Valid values are 1 to 9.
    pub animation: i32
}

/// Polygon struct.
#[derive(Debug, Default, PartialEq)]
pub struct Polygon {
    /// Grass polygon.
    pub grass: bool,
    /// Vector with all vertices, see Position struct.
    pub vertices: Vec<Position<f64>>
}

impl Polygon {
    pub fn new () -> Self {
        Polygon {
            grass: false,
            vertices: vec![]
        }
    }
}

/// Picture struct.
#[derive(Debug, Default, PartialEq)]
pub struct Picture {
    /// Picture name.
    pub name: String,
    /// Texture name.
    pub texture: String,
    /// Mask name.
    pub mask: String,
    /// Position. See Position struct.
    pub position: Position<f64>,
    /// Z-distance
    pub distance: i32,
    /// Clipping.
    ///
    /// 0 = unclipped
    /// 1 = ground
    /// 2 = sky
    // TODO: make enum
    pub clip: i32
}

/// Top10 list entry struct.
#[derive(Debug, Default, PartialEq)]
pub struct ListEntry {
    /// Player 1 name.
    pub name_1: String,
    /// Player 2 name.
    pub name_2: String,
    /// Time.
    pub time: i32
}

/// Level struct that contains all level information.
#[derive(Debug, PartialEq)]
pub struct Level {
    /// Raw binary data of a loaded or finalized constructed level.
    raw: Vec<u8>,
    /// Elma or Across level.
    pub version: Version,
    /// Random number that links level file to replay files.
    pub link: i32,
    /// Contains four integrity checks (See calculate_integrity_sums()).
    pub integrity: [f64; 4],
    /// Level name.
    pub name: String,
    /// LGR file name.
    pub lgr: String,
    /// Ground texture name.
    pub ground: String,
    /// Sky texture name.
    pub sky: String,
    /// Vector with all polygons (See Polygon).
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See Object).
    pub objects: Vec<Object>,
    /// Vector with all pictures (See Picture).
    pub pictures: Vec<Picture>,
    /// Vector of Top10 single-player names and times.
    pub top10_single: Vec<ListEntry>,
    /// Vector of Top10 multi-player names and times.
    pub top10_multi: Vec<ListEntry>
}

impl Default for Level {
    fn default() -> Level { Level::new() }
}

impl Level {
    /// Returns a new Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::new();
    /// ```
    pub fn new () -> Self {
        Level {
            raw: vec![],
            version: Version::Elma,
            link: 0,
            integrity: [0f64; 4],
            name: String::new(),
            lgr: String::from("default"),
            ground: String::from("ground"),
            sky: String::from("sky"),
            polygons: vec![],
            objects: vec![],
            pictures: vec![],
            top10_single: vec![],
            top10_multi: vec![]
        }
    }

    /// Loads a level file and returns a Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::load_level("tests/test.lev");
    /// ```
    pub fn load_level (filename: &str) -> Self {
        let mut level = Level::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        level.raw = buffer;
        level.parse_level();
        level
    }

    /// Parses the raw binary data into Level struct fields.
    fn parse_level (&mut self) {
        let remaining = self.raw.as_slice();

        // POT06 = Across, POT14 = Elma.
        let (version, remaining) = remaining.split_at(5);
        self.version = match version {
            [80, 79, 84, 49, 52] => Version::Elma,
            [80, 79, 84, 48, 54] => Version::Across,
            _ => panic!("Not a valid level file.")
        };

        // Link.
        let (_, mut remaining) = remaining.split_at(2); // Never used
        self.link = remaining.read_i32::<LittleEndian>().unwrap();

        // Integrity checksums.
        for i in 0..4 {
            self.integrity[i] = remaining.read_f64::<LittleEndian>().unwrap();
        }

        // Level name.
        let (name, remaining) = remaining.split_at(51);
        self.name = trim_string(name).unwrap();
        // LGR name.
        let (lgr, remaining) = remaining.split_at(16);
        self.lgr = trim_string(lgr).unwrap();
        // Ground texture name.
        let (ground, remaining) = remaining.split_at(10);
        self.ground = trim_string(ground).unwrap();
        // Sky texture name.
        let (sky, mut remaining) = remaining.split_at(10);
        self.sky = trim_string(sky).unwrap();

        // Polygons.
        let poly_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..poly_count {
            let grass = remaining.read_i32::<LittleEndian>().unwrap() > 0;
            let vertex_count = remaining.read_i32::<LittleEndian>().unwrap();
            let mut vertices: Vec<Position<f64>> = vec![];
            for _ in 0..vertex_count {
                let x = remaining.read_f64::<LittleEndian>().unwrap();
                let y = remaining.read_f64::<LittleEndian>().unwrap();
                vertices.push(Position {
                    x: x,
                    y: y
                });
            }
            self.polygons.push(Polygon {
                grass: grass,
                vertices: vertices
            });
        }

        // Objects.
        let object_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..object_count {
            let x = remaining.read_f64::<LittleEndian>().unwrap();
            let y = remaining.read_f64::<LittleEndian>().unwrap();
            let position = Position { x: x, y: y };
            let object_type = match remaining.read_i32::<LittleEndian>().unwrap() {
                1 => ObjectType::Exit,
                2 => ObjectType::Apple,
                3 => ObjectType::Killer,
                4 => ObjectType::Player,
                _ => panic!("Not a valid object type")
            };
            let gravity = remaining.read_i32::<LittleEndian>().unwrap();
            let animation = remaining.read_i32::<LittleEndian>().unwrap() + 1;

            self.objects.push(Object {
                position: position,
                object_type: object_type,
                gravity: gravity,
                animation: animation
            });
        }

        // Pictures.
        let picture_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.2345672).round() as usize;
        for _ in 0..picture_count {
            let (name, temp_remaining) = remaining.split_at(10);
            let name = trim_string(name).unwrap();
            let (texture, temp_remaining) = temp_remaining.split_at(10);
            let texture = trim_string(texture).unwrap();
            let (mask, temp_remaining) = temp_remaining.split_at(10);
            let mask = trim_string(mask).unwrap();
            remaining = temp_remaining;
            let x = remaining.read_f64::<LittleEndian>().unwrap();
            let y = remaining.read_f64::<LittleEndian>().unwrap();
            let distance = remaining.read_i32::<LittleEndian>().unwrap();
            let clip = remaining.read_i32::<LittleEndian>().unwrap();

            self.pictures.push(Picture {
                name: name,
                texture: texture,
                mask: mask,
                position: Position { x: x, y: y },
                distance: distance,
                clip: clip
            });
        }

        // EOD marker expected at this point.
        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOD { panic!("EOD marker mismatch: x0{:x} != x0{:x}", expected, EOD); }

        // First decrypt the top10 blocks.
        let (top10, mut remaining) = remaining.split_at(688);
        let decrypted_top10_data = crypt_top10(top10);

        // Single-player list.
        let single = &decrypted_top10_data[0..344];
        self.top10_single = parse_top10(single);

        // Multi-player list.
        let multi = &decrypted_top10_data[344..688];
        self.top10_multi = parse_top10(multi);

        // EOF marker expected at this point.
        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOF { panic!("EOF marker mismatch: x0{:x} != x0{:x}", expected, EOF); }
    }

    /// Combines the Level struct fields to generate the raw binary data,
    /// and calculate integrity sums.
    fn update (&self) {
        // TODO: convert
        self.calculate_integrity_sums();
    }

    fn calculate_integrity_sums (&self) {
        // TODO: do that
    }

    /// Converts all struct fields into raw binary form and returns it.
    pub fn get_raw (self) -> Vec<u8> {
        self.update();
        self.raw
    }

    /// Saves level as a file.
    pub fn save_lev (&self, _filename: &str) {
        self.update();
        // let file = File::create(&filename).unwrap();
        // TODO: write stuff.
    }
}

/// Decrypt and encrypt top10 list data. Same algorithm for both.
pub fn crypt_top10 (top10_data: &[u8]) -> Vec<u8> {
    let mut top10: Vec<u8> = Vec::with_capacity(688);
    top10.extend_from_slice(top10_data);

    // Some variables to match the original c/asm code?
    let mut ebp8: i16 = 0x15;
    let mut ebp10: i16 = 0x2637;

    for mut t in top10.iter_mut().take(688) {
        *t ^= (ebp8 & 0xFF) as u8;
        ebp10 = ebp10.wrapping_add((ebp8.wrapping_rem(0xD3D)).wrapping_mul(0xD3D));
        ebp8 = ebp10.wrapping_mul(0x1F).wrapping_add(0xD3D);
    }

    top10
}

/// Parse top10 lists and return a vector of `ListEntry`s
pub fn parse_top10 (top10: &[u8]) -> Vec<ListEntry> {
    let mut list: Vec<ListEntry> = vec![];
    let times = LittleEndian::read_i32(&top10[0..4]);
    for n in 0..times {
        let time_offset = (4 + n * 4) as usize;
        let time_end = time_offset + 4;
        let name_1_offset = (44 + n * 15) as usize;
        let name_1_end = name_1_offset + 15;
        let name_2_offset = (194 + n * 15) as usize;
        let name_2_end = name_2_offset + 15;
        // All of this pains me even though I don't understand it...
        let name_1 = &top10[name_1_offset..name_1_end];
        let name_2 = &top10[name_2_offset..name_2_end];
        list.push(ListEntry {
            time: LittleEndian::read_i32(&top10[time_offset..time_end]),
            name_1: trim_string(name_1).unwrap(),
            name_2: trim_string(name_2).unwrap()
        });
    }
    list
}
<commit_msg>Enums for gravity and clipping<commit_after>//! Read and write Elasto Mania level files.

use std::io::{ Read };
use std::fs::File;
use byteorder::{ ByteOrder, ReadBytesExt, LittleEndian };
use super::{ Position, trim_string };

// Magic arbitrary number; signifies end-of-data. Followed by Top10 list(s).
const EOD: i32 = 0x0067103A;
// Magic arbitrary number; signifies end-of-file.
const EOF: i32 = 0x00845D52;

/// Game version.
#[derive(Debug, PartialEq)]
pub enum Version {
    Across,
    Elma
}

impl Default for Version {
    fn default() -> Version { Version::Elma }
}

/// Type of object.
#[derive(Debug, PartialEq)]
pub enum ObjectType {
    Apple { gravity: Direction, animation: u8 },
    Exit,
    Killer,
    Player
}

impl Default for ObjectType {
    fn default() -> ObjectType { ObjectType::Apple { gravity: Direction::default(), animation: 1 } }
}

/// Apple direction object.
#[derive(Debug, PartialEq)]
pub enum Direction {
    Normal,
    Up,
    Down,
    Left,
    Right
}

impl Default for Direction {
    fn default() -> Direction { Direction::Normal }
}

/// Object struct. Every level requires one `ObjectType::Player` Object and at least one `ObjectType::Exit` Object.
#[derive(Debug, Default, PartialEq)]
pub struct Object {
    /// Position. See `Position` struct.
    pub position: Position<f64>,
    /// Type of Object, see `ObjectType`.
    pub object_type: ObjectType
}

/// Polygon struct.
#[derive(Debug, Default, PartialEq)]
pub struct Polygon {
    /// Grass polygon.
    pub grass: bool,
    /// Vector with all vertices, see Position struct.
    pub vertices: Vec<Position<f64>>
}

impl Polygon {
    pub fn new () -> Self {
        Polygon {
            grass: false,
            vertices: vec![]
        }
    }
}

/// Picture clipping.
#[derive(Debug, PartialEq)]
pub enum Clip {
    Unclipped,
    Ground,
    Sky
}

impl Default for Clip {
    fn default() -> Clip { Clip::Ground }
}

/// Picture struct.
#[derive(Debug, Default, PartialEq)]
pub struct Picture {
    /// Picture name.
    pub name: String,
    /// Texture name.
    pub texture: String,
    /// Mask name.
    pub mask: String,
    /// Position. See Position struct.
    pub position: Position<f64>,
    /// Z-distance
    pub distance: i32,
    /// Clipping.
    pub clip: Clip
}

/// Top10 list entry struct.
#[derive(Debug, Default, PartialEq)]
pub struct ListEntry {
    /// Player 1 name.
    pub name_1: String,
    /// Player 2 name.
    pub name_2: String,
    /// Time.
    pub time: i32
}

/// Level struct that contains all level information.
#[derive(Debug, PartialEq)]
pub struct Level {
    /// Raw binary data of a loaded or finalized constructed level.
    raw: Vec<u8>,
    /// Elma or Across level.
    pub version: Version,
    /// Random number that links level file to replay files.
    pub link: i32,
    /// Contains four integrity checks (See calculate_integrity_sums()).
    pub integrity: [f64; 4],
    /// Level name.
    pub name: String,
    /// LGR file name.
    pub lgr: String,
    /// Ground texture name.
    pub ground: String,
    /// Sky texture name.
    pub sky: String,
    /// Vector with all polygons (See Polygon).
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See Object).
    pub objects: Vec<Object>,
    /// Vector with all pictures (See Picture).
    pub pictures: Vec<Picture>,
    /// Vector of Top10 single-player names and times.
    pub top10_single: Vec<ListEntry>,
    /// Vector of Top10 multi-player names and times.
    pub top10_multi: Vec<ListEntry>
}

impl Default for Level {
    fn default() -> Level { Level::new() }
}

impl Level {
    /// Returns a new Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::new();
    /// ```
    pub fn new () -> Self {
        Level {
            raw: vec![],
            version: Version::Elma,
            link: 0,
            integrity: [0f64; 4],
            name: String::new(),
            lgr: String::from("default"),
            ground: String::from("ground"),
            sky: String::from("sky"),
            polygons: vec![],
            objects: vec![],
            pictures: vec![],
            top10_single: vec![],
            top10_multi: vec![]
        }
    }

    /// Loads a level file and returns a Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::load_level("tests/test_1.lev");
    /// ```
    pub fn load_level (filename: &str) -> Self {
        let mut level = Level::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        level.raw = buffer;
        level.parse_level();
        level
    }

    /// Parses the raw binary data into Level struct fields.
    fn parse_level (&mut self) {
        let remaining = self.raw.as_slice();

        // POT06 = Across, POT14 = Elma.
        let (version, remaining) = remaining.split_at(5);
        self.version = match version {
            [80, 79, 84, 49, 52] => Version::Elma,
            [80, 79, 84, 48, 54] => Version::Across,
            _ => panic!("Not a valid level file.")
        };

        // Link.
        let (_, mut remaining) = remaining.split_at(2); // Never used
        self.link = remaining.read_i32::<LittleEndian>().unwrap();

        // Integrity checksums.
        for i in 0..4 {
            self.integrity[i] = remaining.read_f64::<LittleEndian>().unwrap();
        }

        // Level name.
        let (name, remaining) = remaining.split_at(51);
        self.name = trim_string(name).unwrap();
        // LGR name.
        let (lgr, remaining) = remaining.split_at(16);
        self.lgr = trim_string(lgr).unwrap();
        // Ground texture name.
        let (ground, remaining) = remaining.split_at(10);
        self.ground = trim_string(ground).unwrap();
        // Sky texture name.
        let (sky, mut remaining) = remaining.split_at(10);
        self.sky = trim_string(sky).unwrap();

        // Polygons.
        let poly_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..poly_count {
            let grass = remaining.read_i32::<LittleEndian>().unwrap() > 0;
            let vertex_count = remaining.read_i32::<LittleEndian>().unwrap();
            let mut vertices: Vec<Position<f64>> = vec![];
            for _ in 0..vertex_count {
                let x = remaining.read_f64::<LittleEndian>().unwrap();
                let y = remaining.read_f64::<LittleEndian>().unwrap();
                vertices.push(Position {
                    x: x,
                    y: y
                });
            }
            self.polygons.push(Polygon {
                grass: grass,
                vertices: vertices
            });
        }

        // Objects.
        let object_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..object_count {
            let x = remaining.read_f64::<LittleEndian>().unwrap();
            let y = remaining.read_f64::<LittleEndian>().unwrap();
            let position = Position { x: x, y: y };
            let object_type = remaining.read_i32::<LittleEndian>().unwrap();
            let gravity = remaining.read_i32::<LittleEndian>().unwrap();
            let gravity_direction = match gravity {
                0 => Direction::Normal,
                1 => Direction::Up,
                2 => Direction::Down,
                3 => Direction::Left,
                4 => Direction::Right,
                _ => panic!("Not a valid gravity direction: {:?}", gravity)
            };
            let animation = (remaining.read_i32::<LittleEndian>().unwrap() + 1) as u8;
            let object = match object_type {
                1 => ObjectType::Exit,
                2 => ObjectType::Apple { gravity: gravity_direction, animation: animation },
                3 => ObjectType::Killer,
                4 => ObjectType::Player,
                _ => panic!("Not a valid object type: {:?}", object_type)
            };

            self.objects.push(Object {
                position: position,
                object_type: object
            });
        }

        // Pictures.
        let picture_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.2345672).round() as usize;
        for _ in 0..picture_count {
            let (name, temp_remaining) = remaining.split_at(10);
            let name = trim_string(name).unwrap();
            let (texture, temp_remaining) = temp_remaining.split_at(10);
            let texture = trim_string(texture).unwrap();
            let (mask, temp_remaining) = temp_remaining.split_at(10);
            let mask = trim_string(mask).unwrap();
            remaining = temp_remaining;
            let x = remaining.read_f64::<LittleEndian>().unwrap();
            let y = remaining.read_f64::<LittleEndian>().unwrap();
            let distance = remaining.read_i32::<LittleEndian>().unwrap();
            let clipping = remaining.read_i32::<LittleEndian>().unwrap();
            let clip = match clipping {
                0 => Clip::Unclipped,
                1 => Clip::Ground,
                2 => Clip::Sky,
                _ => panic!("Not valid clipping data: {:?}", clipping)
            };

            self.pictures.push(Picture {
                name: name,
                texture: texture,
                mask: mask,
                position: Position { x: x, y: y },
                distance: distance,
                clip: clip
            });
        }

        // EOD marker expected at this point.
        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOD { panic!("EOD marker mismatch: x0{:x} != x0{:x}", expected, EOD); }

        // First decrypt the top10 blocks.
        let (top10, mut remaining) = remaining.split_at(688);
        let decrypted_top10_data = crypt_top10(top10);

        // Single-player list.
        let single = &decrypted_top10_data[0..344];
        self.top10_single = parse_top10(single);

        // Multi-player list.
        let multi = &decrypted_top10_data[344..688];
        self.top10_multi = parse_top10(multi);

        // EOF marker expected at this point.
        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOF { panic!("EOF marker mismatch: x0{:x} != x0{:x}", expected, EOF); }
    }

    /// Combines the Level struct fields to generate the raw binary data,
    /// and calculate integrity sums.
    fn update (&self) {
        // TODO: convert
        self.calculate_integrity_sums();
    }

    fn calculate_integrity_sums (&self) {
        // TODO: do that
    }

    /// Converts all struct fields into raw binary form and returns it.
    pub fn get_raw (self) -> Vec<u8> {
        self.update();
        self.raw
    }

    /// Saves level as a file.
    pub fn save_lev (&self, _filename: &str) {
        self.update();
        // let file = File::create(&filename).unwrap();
        // TODO: write stuff.
    }
}

/// Decrypt and encrypt top10 list data. Same algorithm for both.
pub fn crypt_top10 (top10_data: &[u8]) -> Vec<u8> {
    let mut top10: Vec<u8> = Vec::with_capacity(688);
    top10.extend_from_slice(top10_data);

    // Some variables to match the original c/asm code?
    let mut ebp8: i16 = 0x15;
    let mut ebp10: i16 = 0x2637;

    for mut t in top10.iter_mut().take(688) {
        *t ^= (ebp8 & 0xFF) as u8;
        ebp10 = ebp10.wrapping_add((ebp8.wrapping_rem(0xD3D)).wrapping_mul(0xD3D));
        ebp8 = ebp10.wrapping_mul(0x1F).wrapping_add(0xD3D);
    }

    top10
}

/// Parse top10 lists and return a vector of `ListEntry`s
pub fn parse_top10 (top10: &[u8]) -> Vec<ListEntry> {
    let mut list: Vec<ListEntry> = vec![];
    let times = LittleEndian::read_i32(&top10[0..4]);
    for n in 0..times {
        let time_offset = (4 + n * 4) as usize;
        let time_end = time_offset + 4;
        let name_1_offset = (44 + n * 15) as usize;
        let name_1_end = name_1_offset + 15;
        let name_2_offset = (194 + n * 15) as usize;
        let name_2_end = name_2_offset + 15;
        // All of this pains me even though I don't understand it...
        let name_1 = &top10[name_1_offset..name_1_end];
        let name_2 = &top10[name_2_offset..name_2_end];
        list.push(ListEntry {
            time: LittleEndian::read_i32(&top10[time_offset..time_end]),
            name_1: trim_string(name_1).unwrap(),
            name_2: trim_string(name_2).unwrap()
        });
    }
    list
}
<|endoftext|>


<commit_before>//! nom, eating data byte by byte
//!
//! nom is a parser combinator library with a focus on safe parsing,
//! streaming patterns, and as much as possible zero copy.
//!
//! The code is available on [Github](https://github.com/Geal/nom)
//!
//! # Example
//!
//! ```
//! #[macro_use]
//! extern crate nom;
//!
//! use nom::{IResult,digit};
//! use nom::IResult::*;
//!
//! // Parser definition
//!
//! use std::str;
//! use std::str::FromStr;
//!
//! named!(parens<i64>, delimited!(
//!     char!('('),
//!     expr,
//!     char!(')')
//!   )
//! );
//!
//! named!(i64_digit<i64>,
//!   map_res!(
//!     map_res!(
//!       digit,
//!       str::from_utf8
//!     ),
//!     FromStr::from_str
//!   )
//! );
//!
//! // We transform an integer string into a i64
//! // we look for a digit suite, and try to convert it.
//! // if either str::from_utf8 or FromStr::from_str fail,
//! // the parser will fail
//! named!(factor<i64>,
//!   alt!(
//!     i64_digit
//!   | parens
//!   )
//! );
//!
//! // we define acc as mutable to update its value whenever a new term is found
//! named!(term <i64>,
//!   chain!(
//!     mut acc: factor  ~
//!              many0!(
//!                alt!(
//!                  tap!(mul: preceded!(tag!("*"), factor) => acc = acc * mul) |
//!                  tap!(div: preceded!(tag!("/"), factor) => acc = acc / div)
//!                )
//!              ),
//!     || { return acc }
//!   )
//! );
//!
//! named!(expr <i64>,
//!   chain!(
//!     mut acc: term  ~
//!              many0!(
//!                alt!(
//!                  tap!(add: preceded!(tag!("+"), term) => acc = acc + add) |
//!                  tap!(sub: preceded!(tag!("-"), term) => acc = acc - sub)
//!                )
//!              ),
//!     || { return acc }
//!   )
//! );
//!
//! fn main() {
//!   assert_eq!(expr(b"1+2"),         IResult::Done(&b""[..], 3));
//!   assert_eq!(expr(b"12+6-4+3"),    IResult::Done(&b""[..], 17));
//!   assert_eq!(expr(b"1+2*3+4"),     IResult::Done(&b""[..], 11));
//!
//!   assert_eq!(expr(b"(2)"),         IResult::Done(&b""[..], 2));
//!   assert_eq!(expr(b"2*(3+4)"),     IResult::Done(&b""[..], 14));
//!   assert_eq!(expr(b"2*2/(5-1)+3"), IResult::Done(&b""[..], 4));
//! }
//! ```
#![cfg_attr(feature = "core", feature(no_std))]
#![cfg_attr(feature = "core", feature(collections))]
#![cfg_attr(feature = "core", no_std)]
#![cfg_attr(feature = "nightly", feature(test))]

#[cfg(feature = "core")]
extern crate collections;
#[cfg(feature = "regexp")]
extern crate regex;
#[cfg(feature = "regexp_macros")]
#[macro_use] extern crate lazy_static;
#[cfg(feature = "nightly")]
extern crate test;

#[cfg(feature = "core")]
mod std {
#[macro_use]
  pub use core::{fmt, iter, option, ops, slice, mem};
  pub use collections::{boxed, vec, string};
  pub mod prelude {
    pub use core::prelude as v1;
  }
}

pub use self::util::*;
pub use self::internal::*;
pub use self::macros::*;
pub use self::methods::*;
pub use self::bytes::*;
pub use self::bits::*;

pub use self::nom::*;
pub use self::character::*;

#[cfg(feature = "regexp")]
pub use self::regexp::*;

#[cfg(not(feature = "core"))]
#[cfg(feature = "stream")]
pub use self::stream::*;

#[cfg(not(feature = "core"))]
pub use self::str::*;

#[macro_use] mod util;
mod internal;
#[macro_use] mod macros;
#[macro_use] mod methods;
#[macro_use] mod bytes;
#[macro_use] mod bits;

#[macro_use] mod nom;
#[macro_use] mod character;

#[cfg(feature = "regexp")]
#[macro_use] mod regexp;

#[macro_use]
#[cfg(not(feature = "core"))]
#[cfg(feature = "stream")]
mod stream;

#[cfg(not(feature = "core"))]
mod str;
<commit_msg>enable const_fn on nightly builds<commit_after>//! nom, eating data byte by byte
//!
//! nom is a parser combinator library with a focus on safe parsing,
//! streaming patterns, and as much as possible zero copy.
//!
//! The code is available on [Github](https://github.com/Geal/nom)
//!
//! # Example
//!
//! ```
//! #[macro_use]
//! extern crate nom;
//!
//! use nom::{IResult,digit};
//! use nom::IResult::*;
//!
//! // Parser definition
//!
//! use std::str;
//! use std::str::FromStr;
//!
//! named!(parens<i64>, delimited!(
//!     char!('('),
//!     expr,
//!     char!(')')
//!   )
//! );
//!
//! named!(i64_digit<i64>,
//!   map_res!(
//!     map_res!(
//!       digit,
//!       str::from_utf8
//!     ),
//!     FromStr::from_str
//!   )
//! );
//!
//! // We transform an integer string into a i64
//! // we look for a digit suite, and try to convert it.
//! // if either str::from_utf8 or FromStr::from_str fail,
//! // the parser will fail
//! named!(factor<i64>,
//!   alt!(
//!     i64_digit
//!   | parens
//!   )
//! );
//!
//! // we define acc as mutable to update its value whenever a new term is found
//! named!(term <i64>,
//!   chain!(
//!     mut acc: factor  ~
//!              many0!(
//!                alt!(
//!                  tap!(mul: preceded!(tag!("*"), factor) => acc = acc * mul) |
//!                  tap!(div: preceded!(tag!("/"), factor) => acc = acc / div)
//!                )
//!              ),
//!     || { return acc }
//!   )
//! );
//!
//! named!(expr <i64>,
//!   chain!(
//!     mut acc: term  ~
//!              many0!(
//!                alt!(
//!                  tap!(add: preceded!(tag!("+"), term) => acc = acc + add) |
//!                  tap!(sub: preceded!(tag!("-"), term) => acc = acc - sub)
//!                )
//!              ),
//!     || { return acc }
//!   )
//! );
//!
//! fn main() {
//!   assert_eq!(expr(b"1+2"),         IResult::Done(&b""[..], 3));
//!   assert_eq!(expr(b"12+6-4+3"),    IResult::Done(&b""[..], 17));
//!   assert_eq!(expr(b"1+2*3+4"),     IResult::Done(&b""[..], 11));
//!
//!   assert_eq!(expr(b"(2)"),         IResult::Done(&b""[..], 2));
//!   assert_eq!(expr(b"2*(3+4)"),     IResult::Done(&b""[..], 14));
//!   assert_eq!(expr(b"2*2/(5-1)+3"), IResult::Done(&b""[..], 4));
//! }
//! ```
#![cfg_attr(feature = "core", feature(no_std))]
#![cfg_attr(feature = "core", feature(collections))]
#![cfg_attr(feature = "core", no_std)]
#![cfg_attr(feature = "nightly", feature(test))]
#![cfg_attr(feature = "nightly", feature(const_fn))]

#[cfg(feature = "core")]
extern crate collections;
#[cfg(feature = "regexp")]
extern crate regex;
#[cfg(feature = "regexp_macros")]
#[macro_use] extern crate lazy_static;
#[cfg(feature = "nightly")]
extern crate test;

#[cfg(feature = "core")]
mod std {
#[macro_use]
  pub use core::{fmt, iter, option, ops, slice, mem};
  pub use collections::{boxed, vec, string};
  pub mod prelude {
    pub use core::prelude as v1;
  }
}

pub use self::util::*;
pub use self::internal::*;
pub use self::macros::*;
pub use self::methods::*;
pub use self::bytes::*;
pub use self::bits::*;

pub use self::nom::*;
pub use self::character::*;

#[cfg(feature = "regexp")]
pub use self::regexp::*;

#[cfg(not(feature = "core"))]
#[cfg(feature = "stream")]
pub use self::stream::*;

#[cfg(not(feature = "core"))]
pub use self::str::*;

#[macro_use] mod util;
mod internal;
#[macro_use] mod macros;
#[macro_use] mod methods;
#[macro_use] mod bytes;
#[macro_use] mod bits;

#[macro_use] mod nom;
#[macro_use] mod character;

#[cfg(feature = "regexp")]
#[macro_use] mod regexp;

#[macro_use]
#[cfg(not(feature = "core"))]
#[cfg(feature = "stream")]
mod stream;

#[cfg(not(feature = "core"))]
mod str;
<|endoftext|>