<commit_before>extern crate num;

#[cfg(test)] extern crate hamcrest;
#[cfg(test)] extern crate quickcheck;

use num::{Float, Num, NumCast, Signed, Zero, cast};
use std::f64::consts::PI;
use std::fmt::{Display, Formatter, Error};
use std::ops::{Add, Div, Mul, Neg, Sub};

/// An angle.
///
/// Might be a value in degrees or in radians.
#[derive(Copy, Clone, Debug)]
pub enum Angle<T=f64> {
    Radians(T),
    Degrees(T)
}

impl<T: NumCast> Angle<T> {
    /// Yield the value encoded in radians.
    pub fn in_radians(self) -> T {
        match self {
            Radians(v) => v,
            Degrees(v) => cast(cast::<T, f64>(v).unwrap() / 180.0 * PI).unwrap()
        }
    }

    /// Yield the value encoded in degrees.
    pub fn in_degrees(self) -> T {
        match self {
            Radians(v) => cast(cast::<T, f64>(v).unwrap() / PI * 180.0).unwrap(),
            Degrees(v) => v
        }
    }

    /// An angle of 45°.
    pub fn eighth() -> Angle<T> {
        Degrees(cast(45).unwrap())
    }

    /// An angle of 90° (right angle).
    pub fn quarter() -> Angle<T> {
        Degrees(cast(90).unwrap())
    }

    /// An angle of 180° (straight).
    pub fn half() -> Angle<T> {
        Degrees(cast(180).unwrap())
    }

    /// An angle of 360° (perigon).
    pub fn full() -> Angle<T> {
        Degrees(cast(360).unwrap())
    }
}

impl<T: Copy + Num + NumCast + PartialOrd> Angle<T> {
    /// Create a new angle by normalizing the value into the range of
    /// [0, 2π) rad.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use angular::*;
    /// # use std::f64::consts::PI;
    /// let alpha = Degrees(-90.0f64).normalized();
    /// assert!((alpha.in_degrees() - 270.0).abs() < 1.0e-10);
    ///
    /// let beta = Radians(2.0 * PI).normalized();
    /// assert!((beta.in_radians() - 0.0).abs() < 1.0e-10);
    /// ```
    pub fn normalized(self) -> Self {
        let (v, upper) = match self {
            Radians(v) => (v, cast(2.0 * PI).unwrap()),
            Degrees(v) => (v, cast(360.0).unwrap())
        };

        let normalized = if v < upper && v >= Zero::zero() {
            v
        } else {
            let v = v % upper;

            if v >= Zero::zero() {
                v
            } else {
                v + upper
            }
        };

        match self {
            Radians(_) => Radians(normalized),
            Degrees(_) => Degrees(normalized)
        }
    }
}

impl<T: Float> Angle<T> {
    /// Computes the minimal unsigned distance between two normalized angles. Returns an
    /// angle in the range of [0, π] rad.
    ///
    /// ```rust
    /// # use angular::*;
    /// let distance = Degrees(345.0).min_dist(Degrees(15.0));
    /// assert!((distance.in_degrees() - 30.0) < 1.0e-10);
    /// ```
    pub fn min_dist(self, other: Angle<T>) -> Angle<T> {
        let pi = cast(PI).unwrap();
        let two_pi = cast(2.0 * PI).unwrap();

        let a = self.in_radians();
        let b = other.in_radians();

        let d = (a - b).abs();

        // short-circout if both angles are normalized
        Radians(if a >= T::zero() && a < two_pi && b >= T::zero() && b < two_pi {
            d.min(two_pi - d)
        } else {
            pi - ((d % two_pi) - pi).abs()
        })
    }
}

impl<T: Signed> Angle<T> {
    /// Compute the absolute angle.
    pub fn abs(self) -> Self {
        match self {
            Radians(v) => Radians(v.abs()),
            Degrees(v) => Degrees(v.abs())
        }
    }
}

impl<T: Float + NumCast> Angle<T> {
    /// Compute the sine of the angle.
    pub fn sin(self) -> T {
        self.in_radians().sin()
    }

    /// Compute the cosine of the angle.
    pub fn cos(self) -> T {
        self.in_radians().cos()
    }

    /// Compute the tangent of the angle.
    pub fn tan(self) -> T {
        self.in_radians().tan()
    }

    /// Simultaneously compute the sine and cosine of the number, `x`.
    /// Return `(sin(x), cos(x))`.
    pub fn sin_cos(self) -> (T, T) {
        self.in_radians().sin_cos()
    }
}

impl<T: Zero + Copy + NumCast> Zero for Angle<T> {
    fn zero() -> Self {
        Radians(T::zero())
    }

    fn is_zero(&self) -> bool {
        match self {
            &Radians(ref v) => v.is_zero(),
            &Degrees(ref v) => v.is_zero()
        }
    }
}

impl<T: PartialEq + Copy + NumCast> PartialEq for Angle<T> {
    fn eq(&self, other: &Angle<T>) -> bool {
        if let (Degrees(a), Degrees(b)) = (*self, *other) {
            a == b
        } else {
            self.in_radians() == other.in_radians()
        }
    }
}

macro_rules! math_additive(
    ($bound:ident, $func:ident) => (
        impl<T: $bound + Copy + NumCast> $bound for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: Angle<T>) -> Self::Output {
                if let (Degrees(a), Degrees(b)) = (self, rhs) {
                    Degrees(a.$func(b))
                } else {
                    Radians(self.in_radians().$func(rhs.in_radians()))
                }
            }
        }
    );
);

math_additive!(Add, add);
math_additive!(Sub, sub);

macro_rules! math_multiplicative(
    ($bound:ident, $func:ident, $($t:ident),*) => (
        impl<T: $bound> $bound<T> for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: T) -> Self::Output {
                match self {
                    Radians(v) => Radians(v.$func(rhs)),
                    Degrees(v) => Degrees(v.$func(rhs))
                }
            }
        }

        $(
            impl $bound<Angle<$t>> for $t {
                type Output = Angle<$t>;
                fn $func(self, rhs: Angle<$t>) -> Self::Output {
                    match rhs {
                        Radians(v) => Radians(self.$func(v)),
                        Degrees(v) => Degrees(self.$func(v))
                    }
                }
            }
        )*
    );
);

math_multiplicative!(Mul, mul, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);
math_multiplicative!(Div, div, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);

impl<T: Neg> Neg for Angle<T> {
    type Output = Angle<T::Output>;
    fn neg(self) -> Self::Output {
        match self {
            Radians(v) => Radians(-v),
            Degrees(v) => Degrees(-v)
        }
    }
}

impl<T: Display> Display for Angle<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Radians(ref v) => write!(f, "{}rad", v),
            Degrees(ref v) => write!(f, "{}°", v)
        }
    }
}

unsafe impl<T: Send> Send for Angle<T> {  }

/// Compute the arcsine of a number. Return value is in the range of
/// [-π/2, π/2] rad or `None` if the number is outside the range [-1, 1].
pub fn asin<T: Float>(value: T) -> Option<Angle<T>> {
    let value = value.asin();
    if value.is_nan() {
        None
    } else {
        Some(Radians(value))
    }
}

/// Compute the arccosine of a number. Return value is in the range of
/// [0, π] rad or `None` if the number is outside the range [-1, 1].
pub fn acos<T: Float>(value: T) -> Option<Angle<T>> {
    let value = value.acos();
    if value.is_nan() {
        None
    } else {
        Some(Radians(value))
    }
}

/// Compute the arctangent of a number. Return value is in the range of
/// [-π/2, π/2] rad.
pub fn atan<T: Float>(value: T) -> Angle<T> {
    Radians(value.atan())
}

/// Compute the four quadrant arctangent of `y` and `x`.
pub fn atan2<T: Float>(y: T, x: T) -> Angle<T> {
    Radians(y.atan2(x))
}

/// Compute the approximate mean of a list of angles by averaging the
/// Cartesian coordinates of the angles on the unit circle. Return the
/// normalized angle.
pub fn mean_angle<T: Float>(angles: &[Angle<T>]) -> Angle<T>
{
    let mut x = T::zero();
    let mut y = T::zero();

    for angle in angles {
        let (sin, cos) = angle.sin_cos();

        x = x + cos;
        y = y + sin;
    }

    let n = cast(angles.len()).unwrap();
    let a = (y/n).atan2(x/n);

    Radians(a).normalized()
}

// re-exports
pub use Angle::{Radians, Degrees};

#[cfg(test)]
mod tests {
    use hamcrest::{assert_that, is, close_to};
    use num::{Float, cast};
    use quickcheck::{Arbitrary, Gen, quickcheck};
    use std::f64::consts::PI;

    use super::*;

    #[test]
    fn test_angle_conversions() {
        fn prop(angle: Angle) -> bool {
            are_close(angle.in_radians(), Degrees(angle.in_degrees()).in_radians())
        }
        quickcheck(prop as fn(Angle) -> bool);
    }

    #[test]
    fn test_angle_math_multiplicative() {
        fn prop(a: Angle, x: f64) -> bool {
            match a {
                Radians(v) => (a * x).in_radians() == v * x &&
                              (a / x).in_radians() == v / x,
                Degrees(v) => (a * x).in_degrees() == v * x &&
                              (a / x).in_degrees() == v / x
            }
        }
        quickcheck(prop as fn(Angle, f64) -> bool);
    }

    #[test]
    fn test_angle_math_additive() {
        fn prop(a: Angle, b: Angle) -> bool {
            if let (Radians(x), Radians(y)) = (a, b) {
                (a + b).in_radians() == x + y &&
                (a - b).in_radians() == x - y
            } else if let (Degrees(x), Degrees(y)) = (a, b) {
                (a + b).in_degrees() == x + y &&
                (a - b).in_degrees() == x - y
            } else {
                (a + b).in_radians() == a.in_radians() + b.in_radians()
            }
        }
        quickcheck(prop as fn(Angle, Angle) -> bool);
    }

    #[test]
    fn test_angle_normalization() {
        fn prop(angle: Angle) -> bool {
            let v = angle.normalized();
            let rad = v.in_radians();
            let deg = v.in_degrees();

            0.0 <= rad && rad < 2.0 * PI &&
            0.0 <= deg && deg < 360.0 &&
            are_close(rad.cos(), angle.cos())
        }
        quickcheck(prop as fn(Angle) -> bool);
    }

    #[test]
    fn test_angle_minimal_distance() {
        fn prop(a: Angle, b: Angle) -> bool {
            let d = a.min_dist(b);
            0.0 <= d.in_radians() && d.in_radians() <= PI
        }
        quickcheck(prop as fn(Angle, Angle) -> bool);

        assert_that(Degrees(180.0).min_dist(Degrees(0.0)).in_degrees(), is(close_to(180.0, 0.000001)));
        assert_that(Degrees(0.1).min_dist(Degrees(359.9)).in_degrees(), is(close_to(0.2, 0.000001)));
        assert_that(Degrees(1.0).min_dist(Degrees(2.0)).in_degrees(), is(close_to(1.0, 0.000001)));
    }

    #[test]
    pub fn test_mean_angle() {
        assert_that(mean_angle(&[Degrees(90.0)]).in_degrees(), is(close_to(90.0, 0.000001)));
        assert_that(mean_angle(&[Degrees(90.0), Degrees(90.0)]).in_degrees(), is(close_to(90.0, 0.000001)));
        assert_that(mean_angle(&[Degrees(90.0), Degrees(180.0), Degrees(270.0)]).in_degrees(), is(close_to(180.0, 0.000001)));
        assert_that(mean_angle(&[Degrees(20.0), Degrees(350.0)]).in_degrees(), is(close_to(5.0, 0.000001)));
    }

    fn are_close<T: Float>(a: T, b: T) -> bool {
        (a - b).abs() < cast(1.0e-10).unwrap()
    }

    impl<T: Arbitrary> Arbitrary for Angle<T> {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            let v = Arbitrary::arbitrary(g);
            if bool::arbitrary(g) {
                Radians(v)
            } else {
                Degrees(v)
            }
        }
    }
}
<commit_msg>Improve `mean_angle` function<commit_after>extern crate num;

#[cfg(test)] extern crate hamcrest;
#[cfg(test)] extern crate quickcheck;

use num::{Float, Num, NumCast, Signed, Zero, cast};
use std::f64::consts::PI;
use std::fmt::{Display, Formatter, Error};
use std::ops::{Add, Div, Mul, Neg, Sub};

/// An angle.
///
/// Might be a value in degrees or in radians.
#[derive(Copy, Clone, Debug)]
pub enum Angle<T=f64> {
    Radians(T),
    Degrees(T)
}

impl<T: NumCast> Angle<T> {
    /// Yield the value encoded in radians.
    pub fn in_radians(self) -> T {
        match self {
            Radians(v) => v,
            Degrees(v) => cast(cast::<T, f64>(v).unwrap() / 180.0 * PI).unwrap()
        }
    }

    /// Yield the value encoded in degrees.
    pub fn in_degrees(self) -> T {
        match self {
            Radians(v) => cast(cast::<T, f64>(v).unwrap() / PI * 180.0).unwrap(),
            Degrees(v) => v
        }
    }

    /// An angle of 45°.
    pub fn eighth() -> Angle<T> {
        Degrees(cast(45).unwrap())
    }

    /// An angle of 90° (right angle).
    pub fn quarter() -> Angle<T> {
        Degrees(cast(90).unwrap())
    }

    /// An angle of 180° (straight).
    pub fn half() -> Angle<T> {
        Degrees(cast(180).unwrap())
    }

    /// An angle of 360° (perigon).
    pub fn full() -> Angle<T> {
        Degrees(cast(360).unwrap())
    }
}

impl<T: Copy + Num + NumCast + PartialOrd> Angle<T> {
    /// Create a new angle by normalizing the value into the range of
    /// [0, 2π) rad.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use angular::*;
    /// # use std::f64::consts::PI;
    /// let alpha = Degrees(-90.0f64).normalized();
    /// assert!((alpha.in_degrees() - 270.0).abs() < 1.0e-10);
    ///
    /// let beta = Radians(2.0 * PI).normalized();
    /// assert!((beta.in_radians() - 0.0).abs() < 1.0e-10);
    /// ```
    pub fn normalized(self) -> Self {
        let (v, upper) = match self {
            Radians(v) => (v, cast(2.0 * PI).unwrap()),
            Degrees(v) => (v, cast(360.0).unwrap())
        };

        let normalized = if v < upper && v >= Zero::zero() {
            v
        } else {
            let v = v % upper;

            if v >= Zero::zero() {
                v
            } else {
                v + upper
            }
        };

        match self {
            Radians(_) => Radians(normalized),
            Degrees(_) => Degrees(normalized)
        }
    }
}

impl<T: Float> Angle<T> {
    /// Computes the minimal unsigned distance between two normalized angles. Returns an
    /// angle in the range of [0, π] rad.
    ///
    /// ```rust
    /// # use angular::*;
    /// let distance = Degrees(345.0).min_dist(Degrees(15.0));
    /// assert!((distance.in_degrees() - 30.0) < 1.0e-10);
    /// ```
    pub fn min_dist(self, other: Angle<T>) -> Angle<T> {
        let pi = cast(PI).unwrap();
        let two_pi = cast(2.0 * PI).unwrap();

        let a = self.in_radians();
        let b = other.in_radians();

        let d = (a - b).abs();

        // short-circout if both angles are normalized
        Radians(if a >= T::zero() && a < two_pi && b >= T::zero() && b < two_pi {
            d.min(two_pi - d)
        } else {
            pi - ((d % two_pi) - pi).abs()
        })
    }
}

impl<T: Signed> Angle<T> {
    /// Compute the absolute angle.
    pub fn abs(self) -> Self {
        match self {
            Radians(v) => Radians(v.abs()),
            Degrees(v) => Degrees(v.abs())
        }
    }
}

impl<T: Float + NumCast> Angle<T> {
    /// Compute the sine of the angle.
    pub fn sin(self) -> T {
        self.in_radians().sin()
    }

    /// Compute the cosine of the angle.
    pub fn cos(self) -> T {
        self.in_radians().cos()
    }

    /// Compute the tangent of the angle.
    pub fn tan(self) -> T {
        self.in_radians().tan()
    }

    /// Simultaneously compute the sine and cosine of the number, `x`.
    /// Return `(sin(x), cos(x))`.
    pub fn sin_cos(self) -> (T, T) {
        self.in_radians().sin_cos()
    }
}

impl<T: Zero + Copy + NumCast> Zero for Angle<T> {
    fn zero() -> Self {
        Radians(T::zero())
    }

    fn is_zero(&self) -> bool {
        match self {
            &Radians(ref v) => v.is_zero(),
            &Degrees(ref v) => v.is_zero()
        }
    }
}

impl<T: PartialEq + Copy + NumCast> PartialEq for Angle<T> {
    fn eq(&self, other: &Angle<T>) -> bool {
        if let (Degrees(a), Degrees(b)) = (*self, *other) {
            a == b
        } else {
            self.in_radians() == other.in_radians()
        }
    }
}

macro_rules! math_additive(
    ($bound:ident, $func:ident) => (
        impl<T: $bound + Copy + NumCast> $bound for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: Angle<T>) -> Self::Output {
                if let (Degrees(a), Degrees(b)) = (self, rhs) {
                    Degrees(a.$func(b))
                } else {
                    Radians(self.in_radians().$func(rhs.in_radians()))
                }
            }
        }
    );
);

math_additive!(Add, add);
math_additive!(Sub, sub);

macro_rules! math_multiplicative(
    ($bound:ident, $func:ident, $($t:ident),*) => (
        impl<T: $bound> $bound<T> for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: T) -> Self::Output {
                match self {
                    Radians(v) => Radians(v.$func(rhs)),
                    Degrees(v) => Degrees(v.$func(rhs))
                }
            }
        }

        $(
            impl $bound<Angle<$t>> for $t {
                type Output = Angle<$t>;
                fn $func(self, rhs: Angle<$t>) -> Self::Output {
                    match rhs {
                        Radians(v) => Radians(self.$func(v)),
                        Degrees(v) => Degrees(self.$func(v))
                    }
                }
            }
        )*
    );
);

math_multiplicative!(Mul, mul, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);
math_multiplicative!(Div, div, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);

impl<T: Neg> Neg for Angle<T> {
    type Output = Angle<T::Output>;
    fn neg(self) -> Self::Output {
        match self {
            Radians(v) => Radians(-v),
            Degrees(v) => Degrees(-v)
        }
    }
}

impl<T: Display> Display for Angle<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Radians(ref v) => write!(f, "{}rad", v),
            Degrees(ref v) => write!(f, "{}°", v)
        }
    }
}

unsafe impl<T: Send> Send for Angle<T> {  }

/// Compute the arcsine of a number. Return value is in the range of
/// [-π/2, π/2] rad or `None` if the number is outside the range [-1, 1].
pub fn asin<T: Float>(value: T) -> Option<Angle<T>> {
    let value = value.asin();
    if value.is_nan() {
        None
    } else {
        Some(Radians(value))
    }
}

/// Compute the arccosine of a number. Return value is in the range of
/// [0, π] rad or `None` if the number is outside the range [-1, 1].
pub fn acos<T: Float>(value: T) -> Option<Angle<T>> {
    let value = value.acos();
    if value.is_nan() {
        None
    } else {
        Some(Radians(value))
    }
}

/// Compute the arctangent of a number. Return value is in the range of
/// [-π/2, π/2] rad.
pub fn atan<T: Float>(value: T) -> Angle<T> {
    Radians(value.atan())
}

/// Compute the four quadrant arctangent of `y` and `x`.
pub fn atan2<T: Float>(y: T, x: T) -> Angle<T> {
    Radians(y.atan2(x))
}

/// Compute the approximate mean of a list of angles by averaging the
/// Cartesian coordinates of the angles on the unit circle. Return the
/// normalized angle.
///
/// # Examples
///
/// ```rust
/// # use angular::*;
/// let angles = [Degrees(270.0f64), Degrees(360.0), Degrees(90.0)];
///
/// let mu = mean_angle(&angles);
/// assert!(mu.min_dist(Radians(0.0)).in_radians() < 1.0e-10);
/// ```
pub fn mean_angle<'a, T, I>(angles: I) -> Angle<T>
    where T: 'a + Float, I: IntoIterator<Item=&'a Angle<T>>
{
    let mut x = T::zero();
    let mut y = T::zero();
    let mut n = 0;

    for angle in angles {
        let (sin, cos) = angle.sin_cos();

        x = x + cos;
        y = y + sin;
        n += 1;
    }

    let n = cast(n).unwrap();
    let a = (y / n).atan2(x / n);

    Radians(a).normalized()
}

// re-exports
pub use Angle::{Radians, Degrees};

#[cfg(test)]
mod tests {
    use hamcrest::{assert_that, is, close_to};
    use num::{Float, cast};
    use quickcheck::{Arbitrary, Gen, quickcheck};
    use std::f64::consts::PI;

    use super::*;

    #[test]
    fn test_angle_conversions() {
        fn prop(angle: Angle) -> bool {
            are_close(angle.in_radians(), Degrees(angle.in_degrees()).in_radians())
        }
        quickcheck(prop as fn(Angle) -> bool);
    }

    #[test]
    fn test_angle_math_multiplicative() {
        fn prop(a: Angle, x: f64) -> bool {
            match a {
                Radians(v) => (a * x).in_radians() == v * x &&
                              (a / x).in_radians() == v / x,
                Degrees(v) => (a * x).in_degrees() == v * x &&
                              (a / x).in_degrees() == v / x
            }
        }
        quickcheck(prop as fn(Angle, f64) -> bool);
    }

    #[test]
    fn test_angle_math_additive() {
        fn prop(a: Angle, b: Angle) -> bool {
            if let (Radians(x), Radians(y)) = (a, b) {
                (a + b).in_radians() == x + y &&
                (a - b).in_radians() == x - y
            } else if let (Degrees(x), Degrees(y)) = (a, b) {
                (a + b).in_degrees() == x + y &&
                (a - b).in_degrees() == x - y
            } else {
                (a + b).in_radians() == a.in_radians() + b.in_radians()
            }
        }
        quickcheck(prop as fn(Angle, Angle) -> bool);
    }

    #[test]
    fn test_angle_normalization() {
        fn prop(angle: Angle) -> bool {
            let v = angle.normalized();
            let rad = v.in_radians();
            let deg = v.in_degrees();

            0.0 <= rad && rad < 2.0 * PI &&
            0.0 <= deg && deg < 360.0 &&
            are_close(rad.cos(), angle.cos())
        }
        quickcheck(prop as fn(Angle) -> bool);
    }

    #[test]
    fn test_angle_minimal_distance() {
        fn prop(a: Angle, b: Angle) -> bool {
            let d = a.min_dist(b);
            0.0 <= d.in_radians() && d.in_radians() <= PI
        }
        quickcheck(prop as fn(Angle, Angle) -> bool);

        assert_that(Degrees(180.0).min_dist(Degrees(0.0)).in_degrees(), is(close_to(180.0, 0.000001)));
        assert_that(Degrees(0.1).min_dist(Degrees(359.9)).in_degrees(), is(close_to(0.2, 0.000001)));
        assert_that(Degrees(1.0).min_dist(Degrees(2.0)).in_degrees(), is(close_to(1.0, 0.000001)));
    }

    #[test]
    pub fn test_mean_angle() {
        assert_that(mean_angle(&[Degrees(90.0)]).in_degrees(), is(close_to(90.0, 0.000001)));
        assert_that(mean_angle(&[Degrees(90.0), Degrees(90.0)]).in_degrees(), is(close_to(90.0, 0.000001)));
        assert_that(mean_angle(&[Degrees(90.0), Degrees(180.0), Degrees(270.0)]).in_degrees(), is(close_to(180.0, 0.000001)));
        assert_that(mean_angle(&[Degrees(20.0), Degrees(350.0)]).in_degrees(), is(close_to(5.0, 0.000001)));
    }

    fn are_close<T: Float>(a: T, b: T) -> bool {
        (a - b).abs() < cast(1.0e-10).unwrap()
    }

    impl<T: Arbitrary> Arbitrary for Angle<T> {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            let v = Arbitrary::arbitrary(g);
            if bool::arbitrary(g) {
                Radians(v)
            } else {
                Degrees(v)
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(raw_pointer_derive)]

pub mod graph;
pub mod vertex;
pub mod edge;
pub mod traversal;

#[cfg(test)]
mod tests {
    use vertex::{Vertex, GraphProperty};
    use graph::Graph;
    #[test]
    fn test_unsafe_vertex() {
        let v = Vertex::new(1);

        let out_edges = &v.out_edges;
        let in_edges = &v.in_edges;
    }

    #[test]
    fn test_deref() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        let vertex = &*v1;
        assert!(vertex.id == 1);
    }

    #[test]
    fn test_new_vertex() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();

        assert_eq!(v1.id, 1);

        unsafe {
            let vertex = &*v1;
            assert_eq!((*v1).id, 1);
        }

        let v2 = g.add_vertex();
        assert!(v2.id == 2);
    }

    #[test]
    fn test_add_edge() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let mut v2 = g.add_vertex();

        let e1 = v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);

        assert_eq!(v1.out_edges.len(), v2.in_edges.len());

        // ensure the vertex and edge pointers are correct

        assert_eq!(v1.v, e1.from_vertex);
        assert_eq!(e1.to_vertex, v2.v);

        //assert_eq!(v1.v, *(e1.edge).from_vertex);
    }

    #[test]
    fn test_properties() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let key = "jon".to_string();
        let value = GraphProperty::Int(1);
        v1.set_property(key.clone(), value);

        let result = v1.get_property(key).unwrap();

        match result {
            &GraphProperty::Int(1) =>
                // we're ok
                println!("OK"),
            _ =>
                panic!("wrong graph property")
        }
    }

    fn test_get_vertex() {
        let mut g = Graph::new();
        let vertex = g.add_vertex();
        let v = g.get(1).unwrap();
        assert_eq!(v.id, 1);
    }

    fn test_graph_query_off_vertex() {
        let mut g = Graph::new();
        let vertex = g.add_vertex();
        let query = g.v(1);
    }

    fn test_traversal_map() {

    }
}
<commit_msg>fixed tests<commit_after>#![allow(raw_pointer_derive)]

pub mod graph;
pub mod vertex;
pub mod edge;
pub mod traversal;

#[cfg(test)]
mod tests {
    use vertex::{Vertex, GraphProperty};
    use graph::Graph;
    #[test]
    fn test_unsafe_vertex() {
        let v = Vertex::new(1);

        let out_edges = &v.out_edges;
        let in_edges = &v.in_edges;
    }

    #[test]
    fn test_deref() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        let vertex = &*v1;
        assert!(vertex.id == 1);
    }

    #[test]
    fn test_new_vertex() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();

        assert_eq!(v1.id, 1);

        unsafe {
            let vertex = &*v1;
            assert_eq!((*v1).id, 1);
        }

        let v2 = g.add_vertex();
        assert!(v2.id == 2);
    }

    #[test]
    fn test_add_edge() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let mut v2 = g.add_vertex();

        let e1 = v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);

        assert_eq!(v1.out_edges.len(), v2.in_edges.len());

        // ensure the vertex and edge pointers are correct

        assert_eq!(v1.v, e1.from_vertex);
        assert_eq!(e1.to_vertex, v2.v);

        //assert_eq!(v1.v, *(e1.edge).from_vertex);
    }

    #[test]
    fn test_properties() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let key = "jon".to_string();
        let value = GraphProperty::Int(1);
        v1.set_property(key.clone(), value);

        let result = v1.get_property(key).unwrap();

        match result {
            &GraphProperty::Int(1) =>
                // we're ok
                println!("OK"),
            _ =>
                panic!("wrong graph property")
        }
    }

    #[test]
    fn test_get_vertex() {
        let mut g = Graph::new();
        let vertex = g.add_vertex();
        let v = g.get(1).unwrap();
        assert_eq!(v.id, 1);
    }

    #[test]
    fn test_graph_query_off_vertex() {
        let mut g = Graph::new();
        let vertex = g.add_vertex();
        let query = g.v(1);
    }

    #[test]
    fn test_traversal_map() {

    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_char, c_int};

#[repr(C)]
#[derive(Copy)]
pub struct PamHandle;

#[repr(C)]
#[derive(Copy)]
pub struct PamConv;

extern "C" {
    /* --------------             pam_appl.h            ------------- */
    /* -------------- The Linux-PAM Framework layer API ------------- */

    pub fn pam_start(service_name: *const c_char, user: *const c_char,
        pam_conversation: *const PamConv, pamh: *mut *const PamHandle) -> c_int;

    pub fn pam_end(pamh: *const PamHandle, pam_status: c_int) -> c_int;

    /* Authentication API's */
    pub fn pam_authenticate(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_setcred(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Account Management API's */
    pub fn pam_acct_mgmt(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Session Management API's */
    pub fn pam_open_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_close_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Password Management API's */
    pub fn pam_chauthtok(pamh: *mut PamHandle, flags: c_int) -> c_int;
}
<commit_msg>Test signature change<commit_after>extern crate libc;

use libc::{c_char, c_int, c_void};

#[repr(C)]
#[derive(Copy)]
pub struct PamHandle;

#[repr(C)]
#[derive(Copy)]
pub struct PamConv {
    pub conv: *const c_void,
    pub data_ptr: *mut c_void
}

extern "C" {
    /* --------------             pam_appl.h            ------------- */
    /* -------------- The Linux-PAM Framework layer API ------------- */

    pub fn pam_start(service_name: *const c_char, user: *const c_char,
        pam_conversation: *const PamConv, pamh: *mut *const PamHandle) -> c_int;

    pub fn pam_end(pamh: *const PamHandle, pam_status: c_int) -> c_int;

    /* Authentication API's */
    pub fn pam_authenticate(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_setcred(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Account Management API's */
    pub fn pam_acct_mgmt(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Session Management API's */
    pub fn pam_open_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_close_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Password Management API's */
    pub fn pam_chauthtok(pamh: *mut PamHandle, flags: c_int) -> c_int;
}
<|endoftext|>


<commit_before>//! Tokio-based [EventStore](https://geteventstore.com/) client library in it's early stages.
//! Currently the most interesting API is the `tokio_service::service::Service` implemented by
//! `client::Client`, which allows sending values of `Package` to get back a `Future` of a response
//! `Package`. `Package` is the name for a frame in the protocol. See it's documentation for more
//! information.
//!
//! You can build values of `Package` using `builder::Builder` and it's functions. Actual payloads
//! are described as `Message` enum.
//!
//! The protocol is multiplexed so you can have multiple (hard limit is 128 currently) calls going
//! at any point in time. Current implementation is based on `tokio_proto::multiplex`, at the
//! moment using a custom fork. It does not yet support `tokio_proto::streaming::multiplex` which is
//! needed to support subscriptions.
//!
//! # Panics
//!
//! There should not be any panicing now that `adapted` and `raw` are separate.
//!
//! # Simplest example
//!
//! Example of writing to the database and simple handling of the response.
//!
//! ```no_run
//! extern crate futures;
//! extern crate tokio_core;
//! extern crate tokio_proto;
//! extern crate tokio_service;
//! extern crate eventstore_tcp;
//!
//! use std::net::SocketAddr;
//! use futures::Future;
//! use tokio_core::reactor::Core;
//! use tokio_service::Service;
//!
//! use eventstore_tcp::{EventStoreClient, Builder, AdaptedMessage, StreamVersion, ContentType};
//!
//! fn main() {
//!     let addr = "127.0.0.1:1113".parse::<SocketAddr>().unwrap();
//!     let mut core = Core::new().unwrap();
//!
//!     // connecting the client returns a future for an EventStoreClient
//!     // which implements tokio_service::Service
//!     let client = EventStoreClient::connect(&addr, &core.handle());
//!
//!     let value = client.and_then(|client| {
//!         // once the connection is made and EventStoreClient (`client`)
//!         // is created, send a WriteEvents request:
//!         client.call(Builder::write_events()
//!             .stream_id("my_stream-1")
//!             .expected_version(StreamVersion::from(42))
//!             .new_event()
//!                 .event_type("meaning_of_life")
//!                 .data("{ 'meaning': 42 }".as_bytes())
//!                 .data_content_type(ContentType::Json)
//!             .done()
//!             .build_package(None, None))
//!
//!         // call returns a future representing the response
//!     }).and_then(|resp| {
//!         // By default, `resp` is a `Package` that contains the raw protobuf defined message
//!         // (`RawMessage`). It is possible to refine it into AdaptedMessage which can fail:
//!         match resp.message.try_adapt().unwrap() {
//!             AdaptedMessage::WriteEventsCompleted(Ok(_)) =>
//!                 println!("Event was written successfully"),
//!             AdaptedMessage::WriteEventsCompleted(Err(fail)) =>
//!                 println!("Event writing failed: {:?}", fail),
//!             unexpected => println!("Unexpected response: {:#?}", unexpected),
//!         };
//!
//!         Ok(())
//!     });
//!
//!     core.run(value).unwrap();
//! }
//! ```
//!
//! More examples can be found in the aspiring command line tool under `examples/testclient`.
#![deny(missing_docs)]

#[macro_use]
extern crate bitflags;
extern crate quick_protobuf;
extern crate uuid;
extern crate byteorder;
#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate tokio_io;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;
extern crate bytes;
#[macro_use]
extern crate derive_more;

#[cfg(test)]
extern crate rustc_serialize;

use std::str;

pub mod raw;
pub use raw::RawMessage;
pub use raw::client_messages::{WriteEvents, ResolvedIndexedEvent, EventRecord, ReadAllEvents};
pub use raw::client_messages::mod_NotHandled::{NotHandledReason, MasterInfo};

pub mod adapted;
pub use adapted::AdaptedMessage;

pub mod package;
pub use package::Package;

pub mod codec;

mod client;
pub use client::EventStoreClient;

pub mod builder;
pub use builder::Builder;

mod auth;
pub use auth::UsernamePassword;

mod errors {
    use std::str;
    use std::io;
    use std::fmt;

    /// Enum describing the locations where a result value can be missing
    #[derive(Debug, PartialEq)]
    pub enum ResultStatusKind {
        /// Missing from WriteEventsCompleted
        WriteEvents,
        /// Missing from ReadEventCompleted
        ReadEvent,
        /// Missing from ReadStreamEventsCompleted
        ReadStream,
    }

    impl fmt::Display for ResultStatusKind {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            use self::ResultStatusKind::*;
            write!(fmt, "{}", match self {
                &WriteEvents => "WriteEventsCompleted::result",
                &ReadEvent => "ReadEventCompleted::result",
                &ReadStream => "ReadStreamEventsCompleted::result",
            })
        }
    }

    error_chain! {
        foreign_links {
            InvalidUtf8(str::Utf8Error);
        }

        errors {
            InvalidFlags(flags: u8) {
                display("Invalid flags: 0x{:02x}", flags)
            }
            MissingResultField(which: ResultStatusKind) {
                display("Missing result field: {}", which)
            }
            InvalidStreamVersion(value: i32) {
                display("Invalid StreamVersion: {}", value)
            }
            InvalidEventNumber(value: i32) {
                display("Invalid EventNumber: {}", value)
            }
            InvalidLogPosition(value: i64) {
                display("Invalid LogPosition: {}", value)
            }
            UnsupportedDiscriminator(d: u8) {
                display("Unsupported discriminator 0x{:02x}", d)
            }
            UnimplementedConversion {
                display("Unimplemented conversion")
            }
            WriteEventsInvalidTransaction {
                display("Unexpected WriteEvents result: InvalidTransaction")
            }
        }
    }

    impl Into<io::Error> for Error {
        fn into(self) -> io::Error {
            match self {
                e => io::Error::new(io::ErrorKind::Other, e),
            }
        }
    }

    impl Into<io::Error> for ErrorKind {
        fn into(self) -> io::Error {
            Error::from(self).into()
        }
    }
}

use self::errors::{Error, ErrorKind};

/// The direction in which events are read.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ReadDirection {
    /// Read from first (event 0) to the latest
    Forward,
    /// Read from latest (highest event number) to the first (event 0)
    Backward
}

impl Copy for ReadDirection {}

/// `ExpectedVersion` represents the different modes of optimistic locking when writing to a stream
/// using `WriteEventsBuilder`.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ExpectedVersion {
    /// No optimistic locking
    Any,
    /// Expect a stream not to exist
    NewStream,
    /// Expect exact number of events in the stream
    Exact(StreamVersion)
}

impl Copy for ExpectedVersion {}

impl Into<i32> for ExpectedVersion {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        use self::ExpectedVersion::*;
        match self {
            Any => -2,
            NewStream => -1,
            Exact(ver) => ver.into()
        }
    }
}

impl From<StreamVersion> for ExpectedVersion {
    fn from(ver: StreamVersion) -> Self {
        ExpectedVersion::Exact(ver)
    }
}

impl CustomTryFrom<i32> for ExpectedVersion {
    type Err = Error;

    fn try_from(val: i32) -> Result<ExpectedVersion, (i32, Self::Err)> {
        let ver = StreamVersion::try_from(val)?;
        Ok(ExpectedVersion::from(ver))
    }
}

/// `StreamVersion` represents the valid values for a stream version which is the same as the
/// event number of the latest event. As such, values are non-negative integers up to
/// `i32::max_value`. Negative values of `i32` have special meaning in the protocol, and are
/// restricted from being used with this type.
///
/// Conversions to StreamVersion are quite horrible until TryFrom is stabilized.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct StreamVersion(u32);

impl Copy for StreamVersion {}

impl StreamVersion {
    /// Converts the value to a StreamVersion or panics if the value is out of range
    pub fn from(version: u32) -> Self {
        Self::from_opt(version).expect("StreamVersion overflow")
    }

    /// Converts the value to a StreamVersion returning None if the input is out of range.
    pub fn from_opt(version: u32) -> Option<Self> {
        // TODO: MAX_VALUE might be some magical value, should be lower?
        if version < i32::max_value() as u32 {
            Some(StreamVersion(version))
        } else {
            None
        }
    }

    #[doc(hidden)]
    pub fn from_i32(version: i32) -> Self {
        Self::try_from(version).unwrap()

    }

    #[doc(hidden)]
    pub fn from_i32_opt(version: i32) -> Option<Self> {
        Self::try_from(version).ok()
    }
}

impl CustomTryFrom<i32> for StreamVersion {
    type Err = Error;

    fn try_from(val: i32) -> Result<Self, (i32, Self::Err)> {
        if val < 0 {
            Err((val, ErrorKind::InvalidStreamVersion(val).into()))
        } else {
            Ok(StreamVersion(val as u32))
        }
    }
}

impl Into<i32> for StreamVersion {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        self.0 as i32
    }
}

/// `EventNumber` is similar to `StreamVersion` and `ExpectedVersion` but is used when specifying a
/// position to read from in the stream. Allows specifying the first or last (when reading
/// backwards) event in addition to exact event number.
#[derive(Debug, Clone, Eq)]
pub enum EventNumber {
    /// The first event in a stream
    First,
    /// Exactly the given event number
    Exact(StreamVersion),
    /// The last event in a stream
    Last,
}

impl Copy for EventNumber {}

impl PartialEq<EventNumber> for EventNumber {
    fn eq(&self, other: &EventNumber) -> bool {
        let val: i32 = (*self).into();
        let other: i32 = (*other).into();
        val == other
    }
}

impl From<StreamVersion> for EventNumber {
    fn from(ver: StreamVersion) -> Self {
        EventNumber::Exact(ver)
    }
}

impl CustomTryFrom<i32> for EventNumber {
    type Err = Error;

    fn try_from(val: i32) -> Result<Self, (i32, Self::Err)> {
        match val {
            0 => Ok(EventNumber::First),
            -1 => Ok(EventNumber::Last),
            x if x > 0 => Ok(EventNumber::Exact(StreamVersion::from_i32(x))),
            invalid => {
                Err((invalid, ErrorKind::InvalidEventNumber(val).into()))
            }
        }
    }
}

impl Into<i32> for EventNumber {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        match self {
            EventNumber::First => 0,
            EventNumber::Exact(x) => x.into(),
            EventNumber::Last => -1
        }
    }
}

/// Content type of the event `data` or `metadata`.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ContentType {
    /// Raw bytes
    Bytes,
    /// JSON values usable with projections in EventStore
    Json
}

impl Copy for ContentType {}

impl Into<i32> for ContentType {
    fn into(self) -> i32 {
        match self {
            ContentType::Bytes => 0,
            ContentType::Json => 1,
        }
    }
}

/// Global unique position in the EventStore, used when reading all events.
/// Range -1..i64::max_value()
#[derive(Debug, Clone, Eq, PartialOrd, Ord)]
pub enum LogPosition {
    /// The first event ever
    First,
    /// Exact position
    Exact(u64),
    /// The last event written to the database at the moment
    Last,
}

impl Copy for LogPosition {}

impl PartialEq<LogPosition> for LogPosition {
    fn eq(&self, other: &LogPosition) -> bool {
        let left: i64 = (*self).into();
        let right: i64 = (*other).into();
        left == right
    }
}

impl From<i64> for LogPosition {
    fn from(val: i64) -> LogPosition {
        match LogPosition::from_i64_opt(val) {
            Some(x) => x,
            None => panic!("LogPosition undeflow: {}", val),
        }
    }
}

impl CustomTryFrom<i64> for LogPosition {
    type Err = Error;

    fn try_from(val: i64) -> Result<Self, (i64, Self::Err)> {
        match val {
            0 => Ok(LogPosition::First),
            -1 => Ok(LogPosition::Last),
            pos => {
                if pos > 0 {
                    Ok(LogPosition::Exact(pos as u64))
                } else {
                    Err((pos, ErrorKind::InvalidLogPosition(pos).into()))
                }
            }
        }
    }
}

impl Into<i64> for LogPosition {
    fn into(self) -> i64 {
        match self {
            LogPosition::First => 0,
            LogPosition::Exact(x) => x as i64,
            LogPosition::Last => -1,
        }
    }
}

impl LogPosition {
    /// Wraps the value into LogPosition or None, if it is larger than i64
    pub fn from_opt(pos: u64) -> Option<LogPosition> {
        match pos {
            0 => Some(LogPosition::First),
            pos => {
                if pos < i64::max_value() as u64 {
                    Some(LogPosition::Exact(pos))
                } else {
                    None
                }
            }
        }
    }

    #[doc(hidden)]
    pub fn from_i64_opt(pos: i64) -> Option<LogPosition> {
        Self::try_from(pos).ok()
    }
}

trait CustomTryFrom<T: Sized>: Sized {
    type Err;

    fn try_from(t: T) -> Result<Self, (T, Self::Err)>;
}

trait CustomTryInto<T: Sized>: Sized {
    type Err;

    fn try_into(self) -> Result<T, (Self, Self::Err)>;
}

impl<T, U> CustomTryInto<U> for T where U: CustomTryFrom<T> {
    type Err = U::Err;

    fn try_into(self) -> Result<U, (T, Self::Err)> {
        U::try_from(self)
    }
}
<commit_msg>misc-cleanup: Remove useless match<commit_after>//! Tokio-based [EventStore](https://geteventstore.com/) client library in it's early stages.
//! Currently the most interesting API is the `tokio_service::service::Service` implemented by
//! `client::Client`, which allows sending values of `Package` to get back a `Future` of a response
//! `Package`. `Package` is the name for a frame in the protocol. See it's documentation for more
//! information.
//!
//! You can build values of `Package` using `builder::Builder` and it's functions. Actual payloads
//! are described as `Message` enum.
//!
//! The protocol is multiplexed so you can have multiple (hard limit is 128 currently) calls going
//! at any point in time. Current implementation is based on `tokio_proto::multiplex`, at the
//! moment using a custom fork. It does not yet support `tokio_proto::streaming::multiplex` which is
//! needed to support subscriptions.
//!
//! # Panics
//!
//! There should not be any panicing now that `adapted` and `raw` are separate.
//!
//! # Simplest example
//!
//! Example of writing to the database and simple handling of the response.
//!
//! ```no_run
//! extern crate futures;
//! extern crate tokio_core;
//! extern crate tokio_proto;
//! extern crate tokio_service;
//! extern crate eventstore_tcp;
//!
//! use std::net::SocketAddr;
//! use futures::Future;
//! use tokio_core::reactor::Core;
//! use tokio_service::Service;
//!
//! use eventstore_tcp::{EventStoreClient, Builder, AdaptedMessage, StreamVersion, ContentType};
//!
//! fn main() {
//!     let addr = "127.0.0.1:1113".parse::<SocketAddr>().unwrap();
//!     let mut core = Core::new().unwrap();
//!
//!     // connecting the client returns a future for an EventStoreClient
//!     // which implements tokio_service::Service
//!     let client = EventStoreClient::connect(&addr, &core.handle());
//!
//!     let value = client.and_then(|client| {
//!         // once the connection is made and EventStoreClient (`client`)
//!         // is created, send a WriteEvents request:
//!         client.call(Builder::write_events()
//!             .stream_id("my_stream-1")
//!             .expected_version(StreamVersion::from(42))
//!             .new_event()
//!                 .event_type("meaning_of_life")
//!                 .data("{ 'meaning': 42 }".as_bytes())
//!                 .data_content_type(ContentType::Json)
//!             .done()
//!             .build_package(None, None))
//!
//!         // call returns a future representing the response
//!     }).and_then(|resp| {
//!         // By default, `resp` is a `Package` that contains the raw protobuf defined message
//!         // (`RawMessage`). It is possible to refine it into AdaptedMessage which can fail:
//!         match resp.message.try_adapt().unwrap() {
//!             AdaptedMessage::WriteEventsCompleted(Ok(_)) =>
//!                 println!("Event was written successfully"),
//!             AdaptedMessage::WriteEventsCompleted(Err(fail)) =>
//!                 println!("Event writing failed: {:?}", fail),
//!             unexpected => println!("Unexpected response: {:#?}", unexpected),
//!         };
//!
//!         Ok(())
//!     });
//!
//!     core.run(value).unwrap();
//! }
//! ```
//!
//! More examples can be found in the aspiring command line tool under `examples/testclient`.
#![deny(missing_docs)]

#[macro_use]
extern crate bitflags;
extern crate quick_protobuf;
extern crate uuid;
extern crate byteorder;
#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate tokio_io;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;
extern crate bytes;
#[macro_use]
extern crate derive_more;

#[cfg(test)]
extern crate rustc_serialize;

use std::str;

pub mod raw;
pub use raw::RawMessage;
pub use raw::client_messages::{WriteEvents, ResolvedIndexedEvent, EventRecord, ReadAllEvents};
pub use raw::client_messages::mod_NotHandled::{NotHandledReason, MasterInfo};

pub mod adapted;
pub use adapted::AdaptedMessage;

pub mod package;
pub use package::Package;

pub mod codec;

mod client;
pub use client::EventStoreClient;

pub mod builder;
pub use builder::Builder;

mod auth;
pub use auth::UsernamePassword;

mod errors {
    use std::str;
    use std::io;
    use std::fmt;

    /// Enum describing the locations where a result value can be missing
    #[derive(Debug, PartialEq)]
    pub enum ResultStatusKind {
        /// Missing from WriteEventsCompleted
        WriteEvents,
        /// Missing from ReadEventCompleted
        ReadEvent,
        /// Missing from ReadStreamEventsCompleted
        ReadStream,
    }

    impl fmt::Display for ResultStatusKind {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            use self::ResultStatusKind::*;
            write!(fmt, "{}", match self {
                &WriteEvents => "WriteEventsCompleted::result",
                &ReadEvent => "ReadEventCompleted::result",
                &ReadStream => "ReadStreamEventsCompleted::result",
            })
        }
    }

    error_chain! {
        foreign_links {
            InvalidUtf8(str::Utf8Error);
        }

        errors {
            InvalidFlags(flags: u8) {
                display("Invalid flags: 0x{:02x}", flags)
            }
            MissingResultField(which: ResultStatusKind) {
                display("Missing result field: {}", which)
            }
            InvalidStreamVersion(value: i32) {
                display("Invalid StreamVersion: {}", value)
            }
            InvalidEventNumber(value: i32) {
                display("Invalid EventNumber: {}", value)
            }
            InvalidLogPosition(value: i64) {
                display("Invalid LogPosition: {}", value)
            }
            UnsupportedDiscriminator(d: u8) {
                display("Unsupported discriminator 0x{:02x}", d)
            }
            UnimplementedConversion {
                display("Unimplemented conversion")
            }
            WriteEventsInvalidTransaction {
                display("Unexpected WriteEvents result: InvalidTransaction")
            }
        }
    }

    impl Into<io::Error> for Error {
        fn into(self) -> io::Error {
            io::Error::new(io::ErrorKind::Other, self)
        }
    }

    impl Into<io::Error> for ErrorKind {
        fn into(self) -> io::Error {
            Error::from(self).into()
        }
    }
}

use self::errors::{Error, ErrorKind};

/// The direction in which events are read.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ReadDirection {
    /// Read from first (event 0) to the latest
    Forward,
    /// Read from latest (highest event number) to the first (event 0)
    Backward
}

impl Copy for ReadDirection {}

/// `ExpectedVersion` represents the different modes of optimistic locking when writing to a stream
/// using `WriteEventsBuilder`.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ExpectedVersion {
    /// No optimistic locking
    Any,
    /// Expect a stream not to exist
    NewStream,
    /// Expect exact number of events in the stream
    Exact(StreamVersion)
}

impl Copy for ExpectedVersion {}

impl Into<i32> for ExpectedVersion {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        use self::ExpectedVersion::*;
        match self {
            Any => -2,
            NewStream => -1,
            Exact(ver) => ver.into()
        }
    }
}

impl From<StreamVersion> for ExpectedVersion {
    fn from(ver: StreamVersion) -> Self {
        ExpectedVersion::Exact(ver)
    }
}

impl CustomTryFrom<i32> for ExpectedVersion {
    type Err = Error;

    fn try_from(val: i32) -> Result<ExpectedVersion, (i32, Self::Err)> {
        let ver = StreamVersion::try_from(val)?;
        Ok(ExpectedVersion::from(ver))
    }
}

/// `StreamVersion` represents the valid values for a stream version which is the same as the
/// event number of the latest event. As such, values are non-negative integers up to
/// `i32::max_value`. Negative values of `i32` have special meaning in the protocol, and are
/// restricted from being used with this type.
///
/// Conversions to StreamVersion are quite horrible until TryFrom is stabilized.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct StreamVersion(u32);

impl Copy for StreamVersion {}

impl StreamVersion {
    /// Converts the value to a StreamVersion or panics if the value is out of range
    pub fn from(version: u32) -> Self {
        Self::from_opt(version).expect("StreamVersion overflow")
    }

    /// Converts the value to a StreamVersion returning None if the input is out of range.
    pub fn from_opt(version: u32) -> Option<Self> {
        // TODO: MAX_VALUE might be some magical value, should be lower?
        if version < i32::max_value() as u32 {
            Some(StreamVersion(version))
        } else {
            None
        }
    }

    #[doc(hidden)]
    pub fn from_i32(version: i32) -> Self {
        Self::try_from(version).unwrap()

    }

    #[doc(hidden)]
    pub fn from_i32_opt(version: i32) -> Option<Self> {
        Self::try_from(version).ok()
    }
}

impl CustomTryFrom<i32> for StreamVersion {
    type Err = Error;

    fn try_from(val: i32) -> Result<Self, (i32, Self::Err)> {
        if val < 0 {
            Err((val, ErrorKind::InvalidStreamVersion(val).into()))
        } else {
            Ok(StreamVersion(val as u32))
        }
    }
}

impl Into<i32> for StreamVersion {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        self.0 as i32
    }
}

/// `EventNumber` is similar to `StreamVersion` and `ExpectedVersion` but is used when specifying a
/// position to read from in the stream. Allows specifying the first or last (when reading
/// backwards) event in addition to exact event number.
#[derive(Debug, Clone, Eq)]
pub enum EventNumber {
    /// The first event in a stream
    First,
    /// Exactly the given event number
    Exact(StreamVersion),
    /// The last event in a stream
    Last,
}

impl Copy for EventNumber {}

impl PartialEq<EventNumber> for EventNumber {
    fn eq(&self, other: &EventNumber) -> bool {
        let val: i32 = (*self).into();
        let other: i32 = (*other).into();
        val == other
    }
}

impl From<StreamVersion> for EventNumber {
    fn from(ver: StreamVersion) -> Self {
        EventNumber::Exact(ver)
    }
}

impl CustomTryFrom<i32> for EventNumber {
    type Err = Error;

    fn try_from(val: i32) -> Result<Self, (i32, Self::Err)> {
        match val {
            0 => Ok(EventNumber::First),
            -1 => Ok(EventNumber::Last),
            x if x > 0 => Ok(EventNumber::Exact(StreamVersion::from_i32(x))),
            invalid => {
                Err((invalid, ErrorKind::InvalidEventNumber(val).into()))
            }
        }
    }
}

impl Into<i32> for EventNumber {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        match self {
            EventNumber::First => 0,
            EventNumber::Exact(x) => x.into(),
            EventNumber::Last => -1
        }
    }
}

/// Content type of the event `data` or `metadata`.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ContentType {
    /// Raw bytes
    Bytes,
    /// JSON values usable with projections in EventStore
    Json
}

impl Copy for ContentType {}

impl Into<i32> for ContentType {
    fn into(self) -> i32 {
        match self {
            ContentType::Bytes => 0,
            ContentType::Json => 1,
        }
    }
}

/// Global unique position in the EventStore, used when reading all events.
/// Range -1..i64::max_value()
#[derive(Debug, Clone, Eq, PartialOrd, Ord)]
pub enum LogPosition {
    /// The first event ever
    First,
    /// Exact position
    Exact(u64),
    /// The last event written to the database at the moment
    Last,
}

impl Copy for LogPosition {}

impl PartialEq<LogPosition> for LogPosition {
    fn eq(&self, other: &LogPosition) -> bool {
        let left: i64 = (*self).into();
        let right: i64 = (*other).into();
        left == right
    }
}

impl From<i64> for LogPosition {
    fn from(val: i64) -> LogPosition {
        match LogPosition::from_i64_opt(val) {
            Some(x) => x,
            None => panic!("LogPosition undeflow: {}", val),
        }
    }
}

impl CustomTryFrom<i64> for LogPosition {
    type Err = Error;

    fn try_from(val: i64) -> Result<Self, (i64, Self::Err)> {
        match val {
            0 => Ok(LogPosition::First),
            -1 => Ok(LogPosition::Last),
            pos => {
                if pos > 0 {
                    Ok(LogPosition::Exact(pos as u64))
                } else {
                    Err((pos, ErrorKind::InvalidLogPosition(pos).into()))
                }
            }
        }
    }
}

impl Into<i64> for LogPosition {
    fn into(self) -> i64 {
        match self {
            LogPosition::First => 0,
            LogPosition::Exact(x) => x as i64,
            LogPosition::Last => -1,
        }
    }
}

impl LogPosition {
    /// Wraps the value into LogPosition or None, if it is larger than i64
    pub fn from_opt(pos: u64) -> Option<LogPosition> {
        match pos {
            0 => Some(LogPosition::First),
            pos => {
                if pos < i64::max_value() as u64 {
                    Some(LogPosition::Exact(pos))
                } else {
                    None
                }
            }
        }
    }

    #[doc(hidden)]
    pub fn from_i64_opt(pos: i64) -> Option<LogPosition> {
        Self::try_from(pos).ok()
    }
}

trait CustomTryFrom<T: Sized>: Sized {
    type Err;

    fn try_from(t: T) -> Result<Self, (T, Self::Err)>;
}

trait CustomTryInto<T: Sized>: Sized {
    type Err;

    fn try_into(self) -> Result<T, (Self, Self::Err)>;
}

impl<T, U> CustomTryInto<U> for T where U: CustomTryFrom<T> {
    type Err = U::Err;

    fn try_into(self) -> Result<U, (T, Self::Err)> {
        U::try_from(self)
    }
}
<|endoftext|>


<commit_before>#[test]
pub mod tcpclient;
pub mod tcpserver;
<commit_msg>nothing<commit_after>pub mod tcpclient;
pub mod tcpserver;
<|endoftext|>


<commit_before>//! # Packet parsing for the Internet Protocol Suite
//!
//! ## Example usage
//! ```
//! use peel_ip::PeelIp;
//!
//! let mut peel = PeelIp::new();
//! let input = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0];
//! let result = peel.traverse(&input, vec![]).unwrap();
//! assert_eq!(result.len(), 1);
//! ```
#![deny(missing_docs)]

#[macro_use]
extern crate log;

#[macro_use]
extern crate nom;
extern crate peel;
extern crate path;

#[macro_use]
pub mod memcmp;

pub mod layer1;
pub mod layer2;
pub mod layer3;
pub mod layer4;

use prelude::*;

/// Provides sensible imports for packet parsers
pub mod prelude {
    pub use std::fmt;
    pub use std::str::{self, FromStr};
    pub use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
    pub use nom::*;
    pub use path::{Path, Data, Identifier};
    pub use peel::prelude::*;
    pub use super::{Layer, ParserVariant, PeelIp};

    /// A shorthand for our
    pub type PathIp = Path<IpProtocol, ()>;

    /// Link
    pub use layer1::*;
    pub use layer1::ethernet::*;
    pub use layer1::arp::*;

    /// Internet
    pub use layer2::*;
    pub use layer2::ipv4::*;
    pub use layer2::ipv6::*;

    // Transport
    pub use layer3::*;
    pub use layer3::tcp::*;
    pub use layer3::tls::*;
    pub use layer3::udp::*;

    // Application
    pub use layer4::http::*;
    pub use layer4::ntp::*;
}

#[derive(Debug)]
/// The return value for the variant retrieval of the Parser trait
pub enum ParserVariant {
    /// Ethernet parser
    Ethernet(EthernetParser),

    /// Address Resolution Protocol parser
    Arp(ArpParser),

    /// Internet Protocol version 4 parser
    Ipv4(Ipv4Parser),

    /// Internet Protocol version 6 parser
    Ipv6(Ipv6Parser),

    /// Transmission Control Protocol parser
    Tcp(TcpParser),

    /// Transport Layer Security parser
    Tls(TlsParser),

    /// Hypertext Transfer Protocol parser
    Http(HttpParser),

    /// User Datagram Protocol parser
    Udp(UdpParser),

    /// Network Time Protocol parser
    Ntp(NtpParser),
}

#[derive(Debug, Eq, PartialEq)]
/// Return values for the actual parsers
pub enum Layer {
    /// Ethernet protocol packet variant
    Ethernet(EthernetPacket),

    /// Address Resolution Protocol packet variant
    Arp(ArpPacket),

    /// Internet Protocol version 4 packet variant
    Ipv4(Ipv4Packet),

    /// Internet Protocol version 6 packet variant
    Ipv6(Ipv6Packet),

    /// Transmission Control Protocol packet variant
    Tcp(TcpPacket),

    /// Transport Layer Security packet variant
    Tls(TlsPacket),

    /// Hypertext Transfer Protocol packet variant
    Http(HttpPacket),

    /// User Datagram Protocol packet variant
    Udp(UdpPacket),

    /// Network Time Protocol packet variant
    Ntp(NtpPacket),
}

macro_rules! impl_fmt_display {
    ($name: ident) => {
        impl fmt::Display for $name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                match *self {
                    $name::Ethernet(_) => write!(f, "Ethernet"),
                    $name::Arp(_) => write!(f, "ARP"),
                    $name::Ipv4(_) => write!(f, "IPv4"),
                    $name::Ipv6(_) => write!(f, "IPv6"),
                    $name::Tcp(_) => write!(f, "TCP"),
                    $name::Tls(_) => write!(f, "TLS"),
                    $name::Http(_) => write!(f, "HTTP"),
                    $name::Udp(_) => write!(f, "UDP"),
                    $name::Ntp(_) => write!(f, "NTP"),
                }
            }
        }
    }
}

impl_fmt_display!(Layer);
impl_fmt_display!(ParserVariant);

/// Peel for TCP/IP packets
pub struct PeelIp;

impl PeelIp {
    /// Creates a new `Peel` structure for TCP/IP based packet parsing
    pub fn new() -> Peel<Layer, ParserVariant, PathIp> {
        // Create a tree
        let mut p = Peel::new();

        // Ethernet
        let eth = p.new_parser(EthernetParser);

        // ARP
        p.link_new_parser(eth, ArpParser);

        // IPv4/6
        let ipv4 = p.link_new_parser(eth, Ipv4Parser);
        let ipv6 = p.link_new_parser(eth, Ipv6Parser);
        p.link(ipv4, ipv6);
        p.link(ipv4, ipv4);
        p.link(ipv6, ipv6);

        // TCP
        let tcp = p.new_parser(TcpParser);
        p.link(ipv4, tcp);
        p.link(ipv6, tcp);

        // UDP
        let udp = p.new_parser(UdpParser);
        p.link(ipv4, udp);
        p.link(ipv6, udp);

        // TLS
        let tls = p.new_parser(TlsParser);
        p.link(tcp, tls);

        // HTTP
        let http = p.new_parser(HttpParser);
        p.link(tcp, http);
        p.link(tls, http);

        // NTP
        let ntp = p.new_parser(NtpParser);
        p.link(udp, ntp);

        // Create a path instance
        p.data = Some(Path::new());

        p
    }
}
<commit_msg>Fixed documentation<commit_after>//! # Packet parsing for the Internet Protocol Suite
//!
//! ## Example usage
//! ```
//! use peel_ip::PeelIp;
//!
//! let mut peel = PeelIp::new();
//! let input = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0];
//! let result = peel.traverse(&input, vec![]).unwrap();
//! assert_eq!(result.len(), 1);
//! ```
#![deny(missing_docs)]

#[macro_use]
extern crate log;

#[macro_use]
extern crate nom;
extern crate peel;
extern crate path;

#[macro_use]
pub mod memcmp;

pub mod layer1;
pub mod layer2;
pub mod layer3;
pub mod layer4;

use prelude::*;

/// Provides sensible imports for packet parsers
pub mod prelude {
    pub use std::fmt;
    pub use std::str::{self, FromStr};
    pub use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
    pub use nom::*;
    pub use path::{Path, Data, Identifier};
    pub use peel::prelude::*;
    pub use super::{Layer, ParserVariant, PeelIp};

    /// A shorthand for the `IpProtocol` based `Path`
    pub type PathIp = Path<IpProtocol, ()>;

    /// Link
    pub use layer1::*;
    pub use layer1::ethernet::*;
    pub use layer1::arp::*;

    /// Internet
    pub use layer2::*;
    pub use layer2::ipv4::*;
    pub use layer2::ipv6::*;

    // Transport
    pub use layer3::*;
    pub use layer3::tcp::*;
    pub use layer3::tls::*;
    pub use layer3::udp::*;

    // Application
    pub use layer4::http::*;
    pub use layer4::ntp::*;
}

#[derive(Debug)]
/// The return value for the variant retrieval of the Parser trait
pub enum ParserVariant {
    /// Ethernet parser
    Ethernet(EthernetParser),

    /// Address Resolution Protocol parser
    Arp(ArpParser),

    /// Internet Protocol version 4 parser
    Ipv4(Ipv4Parser),

    /// Internet Protocol version 6 parser
    Ipv6(Ipv6Parser),

    /// Transmission Control Protocol parser
    Tcp(TcpParser),

    /// Transport Layer Security parser
    Tls(TlsParser),

    /// Hypertext Transfer Protocol parser
    Http(HttpParser),

    /// User Datagram Protocol parser
    Udp(UdpParser),

    /// Network Time Protocol parser
    Ntp(NtpParser),
}

#[derive(Debug, Eq, PartialEq)]
/// Return values for the actual parsers
pub enum Layer {
    /// Ethernet protocol packet variant
    Ethernet(EthernetPacket),

    /// Address Resolution Protocol packet variant
    Arp(ArpPacket),

    /// Internet Protocol version 4 packet variant
    Ipv4(Ipv4Packet),

    /// Internet Protocol version 6 packet variant
    Ipv6(Ipv6Packet),

    /// Transmission Control Protocol packet variant
    Tcp(TcpPacket),

    /// Transport Layer Security packet variant
    Tls(TlsPacket),

    /// Hypertext Transfer Protocol packet variant
    Http(HttpPacket),

    /// User Datagram Protocol packet variant
    Udp(UdpPacket),

    /// Network Time Protocol packet variant
    Ntp(NtpPacket),
}

macro_rules! impl_fmt_display {
    ($name: ident) => {
        impl fmt::Display for $name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                match *self {
                    $name::Ethernet(_) => write!(f, "Ethernet"),
                    $name::Arp(_) => write!(f, "ARP"),
                    $name::Ipv4(_) => write!(f, "IPv4"),
                    $name::Ipv6(_) => write!(f, "IPv6"),
                    $name::Tcp(_) => write!(f, "TCP"),
                    $name::Tls(_) => write!(f, "TLS"),
                    $name::Http(_) => write!(f, "HTTP"),
                    $name::Udp(_) => write!(f, "UDP"),
                    $name::Ntp(_) => write!(f, "NTP"),
                }
            }
        }
    }
}

impl_fmt_display!(Layer);
impl_fmt_display!(ParserVariant);

/// Peel for TCP/IP packets
pub struct PeelIp;

impl PeelIp {
    /// Creates a new `Peel` structure for TCP/IP based packet parsing
    pub fn new() -> Peel<Layer, ParserVariant, PathIp> {
        // Create a tree
        let mut p = Peel::new();

        // Ethernet
        let eth = p.new_parser(EthernetParser);

        // ARP
        p.link_new_parser(eth, ArpParser);

        // IPv4/6
        let ipv4 = p.link_new_parser(eth, Ipv4Parser);
        let ipv6 = p.link_new_parser(eth, Ipv6Parser);
        p.link(ipv4, ipv6);
        p.link(ipv4, ipv4);
        p.link(ipv6, ipv6);

        // TCP
        let tcp = p.new_parser(TcpParser);
        p.link(ipv4, tcp);
        p.link(ipv6, tcp);

        // UDP
        let udp = p.new_parser(UdpParser);
        p.link(ipv4, udp);
        p.link(ipv6, udp);

        // TLS
        let tls = p.new_parser(TlsParser);
        p.link(tcp, tls);

        // HTTP
        let http = p.new_parser(HttpParser);
        p.link(tcp, http);
        p.link(tls, http);

        // NTP
        let ntp = p.new_parser(NtpParser);
        p.link(udp, ntp);

        // Create a path instance
        p.data = Some(Path::new());

        p
    }
}
<|endoftext|>


<commit_before>//! Eudex is a Soundex-esque phonetic reduction/hashing algorithm, providing locality sensitive
//! "hashes" of words, based on the spelling and pronunciation.

#![cfg_attr(test, feature(test))]
#[cfg(test)]
extern crate test;

/// The sound table.
///
/// The first bit each describes a certain property of the phone:
///
/// | Position | Modifier | Property     | Phones                   |
/// |----------|---------:|--------------|:------------------------:|
/// | 1        | 1        | Discriminant | (for tagging duplicates) |
/// | 2        | 2        | Nasal        | mn                       |
/// | 3        | 4        | Fricative    | fvsjxzhct                |
/// | 4        | 8        | Plosive      | pbtdcgqk                 |
/// | 5        | 16       | Dental       | tdnzs                    |
/// | 6        | 32       | Liquid       | lr                       |
/// | 7        | 64       | Labial       | bfpv                     |
/// | 8        | 128      | Confident¹   | lrxzq                    |
///
/// ¹hard to misspell.
///
/// Vowels are, to maxize the XOR distance, represented by 0 and 1 (open and closed, respectively).
const PHONES: [u64; LETTERS as usize] = [
    0, // a
    0b01001000, // b
    0b00001100, // c
    0b00011000, // d
    0, // e
    0b01000100, // f
    0b00001000, // g
    0b00000100, // h
    1, // i
    0b00000101, // j
    0b00001001, // k
    0b10100000, // l
    0b00000010, // m
    0b00010010, // n
    0, // o
    0b01001001, // p
    0b10101000, // q
    0b10100001, // r
    0b00010100, // s
    0b00011101, // t
    1, // u
    0b01000101, // v
    0b00000000, // w
    0b10000100, // x
    1, // y
    0b10010100, // z
];

/// An _injective_ phone table.
///
/// The first bit (MSD) is set if it is a vowel. If so, the second bit represent, if it is closed
/// or not, and the third is set, if it is a front vowel. The rest of the digits are used as
/// discriminants.
///
/// If it is a consonant, the rest of the bits are simply a right truncated version of the
/// [`PHONES`](./const.PHONES.hmtl) table, with the LSD used as discriminant.
const INJECTIVE_PHONES: [u64; LETTERS as usize] = [
    0b11100000, // a
    0b00100100, // b
    0b00000110, // c
    0b00001100, // d
    0b11100001, // e
    0b00100010, // f
    0b00000100, // g
    0b00000010, // h
    0b11000000, // i
    0b00000011, // j
    0b00000101, // k
    0b01010000, // l
    0b00000001, // m
    0b00001001, // n
    0b10100000, // o
    0b00100101, // p
    0b01010100, // q
    0b01010001, // r
    0b00001010, // s
    0b00001110, // t
    0b11000001, // u
    0b00100011, // v
    0b00000000, // w
    0b01000010, // x
    0b11100010, // y
    0b01001010, // z
];

/// Number of letters in our phone map.
const LETTERS: u8 =  26;

/// Phonetically hash this string.
///
/// This hashing function is based upon a phonetic reduction algorithm, and is locality sensitive.
///
/// This will map the string a Soundex-esque value, although to similar sounding strings will not
/// necessarily be mapped to the same, but will map to nearby values (nearby in this case means the
/// XOR having a low Hamming weight).
///
/// This is two orders of magnitude faster than Soundex, and several orders of magnitude faster
/// than Levenshtein distance, making it feasible to run on large sets of strings in very short
/// time.
///
/// Each byte in the string will be mapped to a value from a table, such that similarly sounding
/// characters have many overlapping bits. This way you ensure that strings sounding alike will be
/// mapped nearby each other. Vowels and duplicates will be skipped.
///
/// The first byte, however, is skipped and left in the most significant place, making it most
/// influential to the hash.
///
/// Case has no effect.
pub fn hash(s: &str) -> u64 {
    let mut bytes = s.bytes();
    let first_byte = bytes.next().map_or(0, |b| {
        let entry = (b | 32).wrapping_sub(b'a');
        if entry < LETTERS {
            INJECTIVE_PHONES[entry as usize]
        } else { 0 }
    });
    let mut res = 0;

    for b in bytes {
        let x = {
            let entry = (b | 32).wrapping_sub(b'a');
            if entry < LETTERS {
                PHONES[entry as usize]
            } else { 0 }
        };

        // Collapse consecutive vowels and similar sounding consonants into one.
        if res & 254 != x & 254 {
            res <<= 8;
            res |= x;
        }
    }

    res | (first_byte << 56)
}

/// Calculate the Eudex distance between two words.
///
/// This metric will only measure the bitwise distance between two strings, which is a XOR-like
/// metric, making it unfit for certain purposes.  Generally speaking, the lower this is, the more
/// similar are the two words, although each byte carries different weight (the first one carries
/// the most, and the following's weights are simply half the weight of the previous byte).
///
/// # Example
///
/// ```rust
/// let distance = eudex::distance("write", "right").count_ones();
/// // Hamming weight of the Eudex distance gives a "smoother" word metric.
///
/// assert_eq!(distance, 15);
/// ```
pub fn distance(a: &str, b: &str) -> u64 {
    hash(a) ^ hash(b)
}

/// Check if two sentences sound "similar".
pub fn similar(a: &str, b: &str) -> bool {
    distance(a, b) < 670000
}

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

    #[test]
    fn test_exact() {
        assert_eq!(hash("JAva"), hash("jAva"));
        assert_eq!(hash("co!mputer"), hash("computer"));
        //assert_eq!(hash("comp-uter"), hash("computer"));
        //assert_eq!(hash("comp@u#te?r"), hash("computer"));
        assert_eq!(hash("java"), hash("jiva"));
        assert_eq!(hash("lal"), hash("lel"));
        assert_eq!(hash("rindom"), hash("ryndom"));
        assert_eq!(hash("riiiindom"), hash("ryyyyyndom"));
        assert_eq!(hash("riyiyiiindom"), hash("ryyyyyndom"));
        assert_eq!(hash("triggered"), hash("TRIGGERED"));
        assert_eq!(hash("repert"), hash("ropert"));
    }

    #[test]
    fn test_mismatch() {
        assert!(hash("reddit") != hash("eddit"));
        assert!(hash("lol") != hash("lulz"));
        assert!(hash("ijava") != hash("java"));
        assert!(hash("jesus") != hash("iesus"));
        assert!(hash("aesus") != hash("iesus"));
        assert!(hash("iesus") != hash("yesus"));
        //assert!(hash("ripert") != hash("ropert"));
        //assert!(hash("rupirt") != hash("ropyrt"));
        assert!(hash("rrr") != hash("rraaaa"));
    }

    #[test]
    fn test_distance() {
        assert!(distance("lizzard", "wizzard") > distance("rick", "rolled"));
        assert!(distance("bannana", "panana") >= distance("apple", "abple"));
        //assert!(distance("franco", "sranco") < distance("unicode", "ASCII"));
        assert!(distance("trump", "drumpf") < distance("gangam", "style"));
        assert!(distance("right", "write").count_zeros() > distance("write", "abdominohysterotomy").count_zeros());
    }

    #[test]
    fn test_reflexivity() {
        assert_eq!(distance("a", "b"), distance("b", "a"));
        assert_eq!(distance("youtube", "facebook"), distance("facebook", "youtube"));
        assert_eq!(distance("Rust", "Go"), distance("Go", "Rust"));
        assert_eq!(distance("rick", "rolled"), distance("rolled", "rick"));
    }

    #[test]
    fn test_similar() {
        // Similar.
        assert!(similar("yay", "yuy"));
        assert!(distance("crack", "crakk").count_ones() < 10);
        assert!(similar("what", "wat"));
        assert!(similar("jesus", "jeuses"));
        assert!(similar("", ""));
        assert!(similar("jumpo", "jumbo"));
        assert!(similar("lol", "lulz"));
        assert!(similar("goth", "god"));
        assert!(similar("maier", "meyer"));
        //assert!(similar("schmid", "schmidt"));

        // Not similar.
        assert!(!similar("youtube", "reddit"));
        assert!(!similar("yet", "vet"));
        assert!(!similar("hacker", "4chan"));
        assert!(!similar("awesome", "me"));
        assert!(!similar("prisco", "vkisco"));
        assert!(!similar("no", "go"));
        assert!(!similar("horse", "norse"));
        assert!(!similar("nice", "mice"));
    }

    #[bench]
    fn bench_dict(b: &mut Bencher) {
        use std::fs;
        use std::io::{BufRead, BufReader};

        b.iter(|| {
            let dict = fs::File::open("/usr/share/dict/american-english").unwrap_or_else(|_| {
                fs::File::open("/usr/share/dict/words").unwrap()
            });
            let mut vec = Vec::new();

            for i in BufReader::new(dict).lines() {
                vec.push(hash(&i.unwrap()));
            }

            vec
        });
    }
}
<commit_msg>Ignore non-alphanumerics<commit_after>//! Eudex is a Soundex-esque phonetic reduction/hashing algorithm, providing locality sensitive
//! "hashes" of words, based on the spelling and pronunciation.

#![cfg_attr(test, feature(test))]
#[cfg(test)]
extern crate test;

/// The sound table.
///
/// The first bit each describes a certain property of the phone:
///
/// | Position | Modifier | Property     | Phones                   |
/// |----------|---------:|--------------|:------------------------:|
/// | 1        | 1        | Discriminant | (for tagging duplicates) |
/// | 2        | 2        | Nasal        | mn                       |
/// | 3        | 4        | Fricative    | fvsjxzhct                |
/// | 4        | 8        | Plosive      | pbtdcgqk                 |
/// | 5        | 16       | Dental       | tdnzs                    |
/// | 6        | 32       | Liquid       | lr                       |
/// | 7        | 64       | Labial       | bfpv                     |
/// | 8        | 128      | Confident¹   | lrxzq                    |
///
/// ¹hard to misspell.
///
/// Vowels are, to maxize the XOR distance, represented by 0 and 1 (open and close, respectively).
const PHONES: [u64; LETTERS as usize] = [
    0, // a
    0b01001000, // b
    0b00001100, // c
    0b00011000, // d
    0, // e
    0b01000100, // f
    0b00001000, // g
    0b00000100, // h
    1, // i
    0b00000101, // j
    0b00001001, // k
    0b10100000, // l
    0b00000010, // m
    0b00010010, // n
    0, // o
    0b01001001, // p
    0b10101000, // q
    0b10100001, // r
    0b00010100, // s
    0b00011101, // t
    1, // u
    0b01000101, // v
    0b00000000, // w
    0b10000100, // x
    1, // y
    0b10010100, // z
];

/// An _injective_ phone table.
///
/// The first bit (MSD) is set if it is a vowel. If so, the second bit represent, if it is close
/// or not, and the third is set, if it is a front vowel. The rest of the digits are used as
/// discriminants.
///
/// If it is a consonant, the rest of the bits are simply a right truncated version of the
/// [`PHONES`](./const.PHONES.hmtl) table, with the LSD used as discriminant.
const INJECTIVE_PHONES: [u64; LETTERS as usize] = [
    0b11100000, // a
    0b00100100, // b
    0b00000110, // c
    0b00001100, // d
    0b11100001, // e
    0b00100010, // f
    0b00000100, // g
    0b00000010, // h
    0b11000000, // i
    0b00000011, // j
    0b00000101, // k
    0b01010000, // l
    0b00000001, // m
    0b00001001, // n
    0b10100000, // o
    0b00100101, // p
    0b01010100, // q
    0b01010001, // r
    0b00001010, // s
    0b00001110, // t
    0b11000001, // u
    0b00100011, // v
    0b00000000, // w
    0b01000010, // x
    0b11100010, // y
    0b01001010, // z
];

/// Number of letters in our phone map.
const LETTERS: u8 =  26;

/// Phonetically hash this string.
///
/// This hashing function is based upon a phonetic reduction algorithm, and is locality sensitive.
///
/// This will map the string a Soundex-esque value, although to similar sounding strings will not
/// necessarily be mapped to the same, but will map to nearby values (nearby in this case means the
/// XOR having a low Hamming weight).
///
/// This is two orders of magnitude faster than Soundex, and several orders of magnitude faster
/// than Levenshtein distance, making it feasible to run on large sets of strings in very short
/// time.
///
/// Each byte in the string will be mapped to a value from a table, such that similarly sounding
/// characters have many overlapping bits. This way you ensure that strings sounding alike will be
/// mapped nearby each other. Vowels and duplicates will be skipped.
///
/// The first byte, however, is skipped and left in the most significant place, making it most
/// influential to the hash.
///
/// Case has no effect.
pub fn hash(s: &str) -> u64 {
    let mut bytes = s.bytes();
    let first_byte = bytes.next().map_or(0, |b| {
        let entry = (b | 32).wrapping_sub(b'a');
        if entry < LETTERS {
            INJECTIVE_PHONES[entry as usize]
        } else { 0 }
    });
    let mut res = 0;

    for b in bytes {
        let entry = (b | 32).wrapping_sub(b'a');
        if entry <= b'z' {
            let x = {
                if entry < LETTERS {
                    PHONES[entry as usize]
                } else { 0 }
            };

            // Collapse consecutive vowels and similar sounding consonants into one.
            if res & 254 != x & 254 {
                res <<= 8;
                res |= x;
            }
        }
    }

    res | (first_byte << 56)
}

/// Calculate the Eudex distance between two words.
///
/// This metric will only measure the bitwise distance between two strings, which is a XOR-like
/// metric, making it unfit for certain purposes.  Generally speaking, the lower this is, the more
/// similar are the two words, although each byte carries different weight (the first one carries
/// the most, and the following's weights are simply half the weight of the previous byte).
///
/// # Example
///
/// ```rust
/// let distance = eudex::distance("write", "right").count_ones();
/// // Hamming weight of the Eudex distance gives a "smoother" word metric.
///
/// assert_eq!(distance, 15);
/// ```
pub fn distance(a: &str, b: &str) -> u64 {
    hash(a) ^ hash(b)
}

/// Check if two sentences sound "similar".
pub fn similar(a: &str, b: &str) -> bool {
    distance(a, b) < 670000
}

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

    #[test]
    fn test_exact() {
        assert_eq!(hash("JAva"), hash("jAva"));
        assert_eq!(hash("co!mputer"), hash("computer"));
        assert_eq!(hash("comp-uter"), hash("computer"));
        assert_eq!(hash("comp@u#te?r"), hash("computer"));
        assert_eq!(hash("java"), hash("jiva"));
        assert_eq!(hash("lal"), hash("lel"));
        assert_eq!(hash("rindom"), hash("ryndom"));
        assert_eq!(hash("riiiindom"), hash("ryyyyyndom"));
        assert_eq!(hash("riyiyiiindom"), hash("ryyyyyndom"));
        assert_eq!(hash("triggered"), hash("TRIGGERED"));
        assert_eq!(hash("repert"), hash("ropert"));
    }

    #[test]
    fn test_mismatch() {
        assert!(hash("reddit") != hash("eddit"));
        assert!(hash("lol") != hash("lulz"));
        assert!(hash("ijava") != hash("java"));
        assert!(hash("jesus") != hash("iesus"));
        assert!(hash("aesus") != hash("iesus"));
        assert!(hash("iesus") != hash("yesus"));
        assert!(hash("rupirt") != hash("ropert"));
        assert!(hash("ripert") != hash("ropyrt"));
        assert!(hash("rrr") != hash("rraaaa"));
    }

    #[test]
    fn test_distance() {
        assert!(distance("lizzard", "wizzard") > distance("rick", "rolled"));
        assert!(distance("bannana", "panana") >= distance("apple", "abple"));
        //assert!(distance("franco", "sranco") < distance("unicode", "ASCII"));
        assert!(distance("trump", "drumpf") < distance("gangam", "style"));
        assert!(distance("right", "write").count_zeros() > distance("write", "abdominohysterotomy").count_zeros());
    }

    #[test]
    fn test_reflexivity() {
        assert_eq!(distance("a", "b"), distance("b", "a"));
        assert_eq!(distance("youtube", "facebook"), distance("facebook", "youtube"));
        assert_eq!(distance("Rust", "Go"), distance("Go", "Rust"));
        assert_eq!(distance("rick", "rolled"), distance("rolled", "rick"));
    }

    #[test]
    fn test_similar() {
        // Similar.
        assert!(similar("yay", "yuy"));
        assert!(distance("crack", "crakk").count_ones() < 10);
        assert!(similar("what", "wat"));
        assert!(similar("jesus", "jeuses"));
        assert!(similar("", ""));
        assert!(similar("jumpo", "jumbo"));
        assert!(similar("lol", "lulz"));
        assert!(similar("goth", "god"));
        assert!(similar("maier", "meyer"));
        //assert!(similar("schmid", "schmidt"));

        // Not similar.
        assert!(!similar("youtube", "reddit"));
        assert!(!similar("yet", "vet"));
        assert!(!similar("hacker", "4chan"));
        assert!(!similar("awesome", "me"));
        assert!(!similar("prisco", "vkisco"));
        assert!(!similar("no", "go"));
        assert!(!similar("horse", "norse"));
        assert!(!similar("nice", "mice"));
    }

    #[bench]
    fn bench_dict(b: &mut Bencher) {
        use std::fs;
        use std::io::{BufRead, BufReader};

        b.iter(|| {
            let dict = fs::File::open("/usr/share/dict/american-english").unwrap_or_else(|_| {
                fs::File::open("/usr/share/dict/words").unwrap()
            });
            let mut vec = Vec::new();

            for i in BufReader::new(dict).lines() {
                vec.push(hash(&i.unwrap()));
            }

            vec
        });
    }
}
<|endoftext|>


<commit_before>//! A toolkit for building command-line programs in Rust.
//!
//! `cli` aims to
//!
//! - reduce boilerplate
//! - canonicalize output formatting
//! - encourage adherence to the conventions of standard streams
//!   (e.g. when to print to stderr vs stdout)
//! - encourage appropriate use of exit statuses
//!
//! Concretely, `cli` is a collection of simple functions for formatting
//! command-line output, defining flags, and (eventually) things like
//! integrating with sysexits.
//!
//! It uses [getopts](http://doc.rust-lang.org/getopts/) for argument parsing
//! and thus currently inherits `getopt`'s `experimental` stability level.

#![crate_name = "cli"]
#![crate_type="rlib"]

extern crate getopts;
use getopts::{Matches, OptGroup, getopts, optflag, short_usage};
use getopts::usage as getopts_usage;
use std::{io, os};

mod test;

/// The name by which the executed program was called.
///
/// Typically the file name or path of the invoked executable.
pub fn argv0() -> String {
    os::args()[0].clone()
}

/// Construct a canonical usage string from a collection of `OptGroup`s.
///
/// Usage strings format:
///
///```ignore
///     Usage: <argv0> [option synopsis]...
///
///     Options:
///         [option description]...
///```
pub fn usage(opts: &[OptGroup]) -> String {
    format!("{}", getopts_usage(short_usage(argv0().as_slice(), opts).as_slice(), opts))
}

/// Parse the command-line arguments with which the program was executed
/// according to a collection of `OptGroup`s.
///
/// Any flag parsing failure results in task panic. The program's usage string
/// is printed to stderr prior to panic. Panic is induced in order to avoid
/// program execution with undefined configuration. In such cases, the presence
/// of unrecognized flags or invalid flag values implies confusion on the part
/// of the executor. While perhaps overbearing, it is preferable to halt
/// execution abruptly than to continue with the risk of unwanted behavior.
pub fn parse_args(opts: &[OptGroup]) -> Matches {
    match getopts(os::args().tail(), opts) {
        Ok(matches) => matches,
        Err(getopts_error) => {
            // Write usage string to stderr, then panic.
            match io::stderr().write_str(usage(opts).as_slice()) {
                Ok(()) => panic!(getopts_error.to_string()),
                Err(write_error) =>
                    // Write to stderr failed -- panic with both error messages.
                    panic!("{}\n{}", getopts_error.to_string(), write_error.to_string())
            }
        }
    }
}

/// Create a help flag `OptGroup`.
///
/// The returned `OptGroup` is an optional long option for the input `-h`
/// and `--help`.
pub fn helpopt() -> OptGroup {
    optflag("h", "help", "Print this help menu")
}

/// Create a version flag `OptGroup`.
///
/// The returned `OptGroup` is an optional long option for the input
/// `--version`. `-v` and `-V` are avoided in order to prevent confusion in the
/// event when a flag is needed for enabling verbose output.
pub fn versionopt() -> OptGroup {
    optflag("", "version", format!("Print the version of {} being run", argv0()).as_slice())
}
<commit_msg>Add `version_string` function, s/`usage`/`usage_string/<commit_after>//! A toolkit for building command-line programs in Rust.
//!
//! `cli` aims to
//!
//! - reduce boilerplate
//! - canonicalize output formatting
//! - encourage adherence to the conventions of standard streams
//!   (e.g. when to print to stderr vs stdout)
//! - encourage appropriate use of exit statuses
//!
//! Concretely, `cli` is a collection of simple functions for formatting
//! command-line output, defining flags, and (eventually) things like
//! integrating with sysexits.
//!
//! It uses [getopts](http://doc.rust-lang.org/getopts/) for argument parsing
//! and thus currently inherits `getopt`'s `experimental` stability level.

#![crate_name = "cli"]
#![crate_type="rlib"]

extern crate getopts;
use getopts::{Matches, OptGroup, getopts, optflag, short_usage, usage};
use std::{io, os};

mod test;

/// The name by which the executed program was called.
///
/// Typically the file name or path of the invoked executable.
pub fn argv0() -> String {
    os::args()[0].clone()
}

/// Construct a canonical usage string from a collection of `OptGroup`s.
///
/// Usage string format:
///
///```ignore
///     Usage: <argv0> [option synopsis]...
///
///     Options:
///         [option description]...
///```
pub fn usage_string(opts: &[OptGroup]) -> String {
    format!("{}", usage(short_usage(argv0().as_slice(), opts).as_slice(), opts))
}

/// Construct a version string.
///
/// Intended for use as output in response to `--version` as defined by
/// `cli::versionopt`.
///
/// Version string format:
///
///```ignore
///     <argv0> version <version>
///```
pub fn version_string(version: &str) -> String {
    format!("{} version {}", argv0(), version)
}

/// Parse the command-line arguments with which the program was executed
/// according to a collection of `OptGroup`s.
///
/// Any flag parsing failure results in task panic. The program's usage string
/// is printed to stderr prior to panic. Panic is induced in order to avoid
/// program execution with undefined configuration. In such cases, the presence
/// of unrecognized flags or invalid flag values implies confusion on the part
/// of the executor. While perhaps overbearing, it is preferable to halt
/// execution abruptly than to continue with the risk of unwanted behavior.
pub fn parse_args(opts: &[OptGroup]) -> Matches {
    match getopts(os::args().tail(), opts) {
        Ok(matches) => matches,
        Err(getopts_error) => {
            // Write usage string to stderr, then panic.
            match io::stderr().write_str(usage_string(opts).as_slice()) {
                Ok(()) => panic!(getopts_error.to_string()),
                Err(write_error) =>
                    // Write to stderr failed -- panic with both error messages.
                    panic!("{}\n{}", getopts_error.to_string(), write_error.to_string())
            }
        }
    }
}

/// Create a help flag `OptGroup`.
///
/// The returned `OptGroup` is an optional long option for the input `-h`
/// and `--help`.
pub fn helpopt() -> OptGroup {
    optflag("h", "help", "Print this help menu")
}

/// Create a version flag `OptGroup`.
///
/// The returned `OptGroup` is an optional long option for the input
/// `--version`. `-v` and `-V` are avoided in order to prevent confusion in the
/// event when a flag is needed for enabling verbose output.
pub fn versionopt() -> OptGroup {
    optflag("", "version", format!("Print the version of {} being run", argv0()).as_slice())
}
<|endoftext|>


<commit_before>/*
 *           _           _            _             _          _
 *          /\ \        /\ \         /\ \     _    /\ \       /\ \
 *         /  \ \      /  \ \       /  \ \   /\_\ /  \ \      \_\ \
 *        / /\ \ \    / /\ \ \     / /\ \ \_/ / // /\ \ \     /\__ \
 *       / / /\ \_\  / / /\ \_\   / / /\ \___/ // / /\ \_\   / /_ \ \
 *      / / /_/ / / / /_/_ \/_/  / / /  \/____// /_/_ \/_/  / / /\ \ \
 *     / / /__\/ / / /____/\    / / /    / / // /____/\    / / /  \/_/
 *    / / /_____/ / /\____\/   / / /    / / // /\____\/   / / /
 *   / / /\ \ \  / / /______  / / /    / / // / /______  / / /
 *  / / /  \ \ \/ / /_______\/ / /    / / // / /_______\/_/ /
 *  \/_/    \_\/\/__________/\/_/     \/_/ \/__________/\_\/
 *
 *
 * This file is released under terms described in the LICENSE file at
 * the top directory of this repository.
 *
 * Please contact Mark McDermott <mark.elias.mcdermott@gmail.com> or
 * the current maintainer of this software if you do not have a copy of
 * the license file.
 *
 * -------------------------------------------------------------------
 *  REnet is a rust language wrapper for the ENet networking library
 *
 *  TODO List
 * -------------------------------------------------------------------
 */

extern crate libc;

use libc::{c_uint,c_void,size_t};
use std::io::net::ip::ToSocketAddr;
use std::io::net::ip::IpAddr;

pub mod ffi;

pub fn initialize() -> Result<(), i32>  {
    unsafe {
        match ffi::enet_initialize() {
            0    => Ok(()),
            code => Err(code)
        }
    }
}

pub fn deinitialize() {
    unsafe {
        ffi::enet_deinitialize();
    }
}

pub fn linked_version() -> u32 {
    unsafe {
        ffi::enet_linked_version() as u32
    }
}

/*
 * ------------------------------------------------------------------
 * Host object: a wrapper around ENetHost*
 * ------------------------------------------------------------------
 */
pub struct Host {
    ffi_handle : *mut c_void,
}

impl Host {
    pub fn new<A: ToSocketAddr>(address: Option<A>,
                                peer_count: u32,
                                channel_count: u32,
                                incomming_bandwidth: u32,
                                outgoing_bandwidth: u32)
    -> Result<Host, &'static str> {

        let p_addr = match address {
            Some(addr) => {
                let socket_addr = match addr.to_socket_addr() {
                    Ok(a)      => a,
                    Err(ioerr) => return Err(ioerr.desc)
                };

                let socket_ip : u32 = match socket_addr.ip {
                    IpAddr::Ipv4Addr(a,b,c,d) => (a as u32 <<24) + (b as u32 <<16) + (c as u32 <<8) + d as u32,
                    _                         => return Err("IPv6 not currently supported")
                };
                let eaddr = ffi::ENetAddress{host:socket_ip, port:socket_addr.port};
                &eaddr as *const _ as *const c_void
            }
            None => 0 as *const c_void
        };

        let host = unsafe { ffi::enet_host_create(p_addr,
                                                  peer_count as size_t,
                                                  channel_count as size_t,
                                                  incomming_bandwidth as c_uint,
                                                  outgoing_bandwidth as c_uint)
                          };

        let p_host = host as *mut Host;

        if p_host.is_null() { return Err("Could not initialize host"); }
        else                { return Ok(Host{ffi_handle:host}); }
    }

    pub fn hello(&self) {
        println!("hi");
    }
}

impl Drop for Host {
    fn drop(&mut self) {
        println!("deleting host");

        unsafe { ffi::enet_host_destroy(self.ffi_handle); }
    }
}
<commit_msg>remove debug prints<commit_after>/*
 *           _           _            _             _          _
 *          /\ \        /\ \         /\ \     _    /\ \       /\ \
 *         /  \ \      /  \ \       /  \ \   /\_\ /  \ \      \_\ \
 *        / /\ \ \    / /\ \ \     / /\ \ \_/ / // /\ \ \     /\__ \
 *       / / /\ \_\  / / /\ \_\   / / /\ \___/ // / /\ \_\   / /_ \ \
 *      / / /_/ / / / /_/_ \/_/  / / /  \/____// /_/_ \/_/  / / /\ \ \
 *     / / /__\/ / / /____/\    / / /    / / // /____/\    / / /  \/_/
 *    / / /_____/ / /\____\/   / / /    / / // /\____\/   / / /
 *   / / /\ \ \  / / /______  / / /    / / // / /______  / / /
 *  / / /  \ \ \/ / /_______\/ / /    / / // / /_______\/_/ /
 *  \/_/    \_\/\/__________/\/_/     \/_/ \/__________/\_\/
 *
 *
 * This file is released under terms described in the LICENSE file at
 * the top directory of this repository.
 *
 * Please contact Mark McDermott <mark.elias.mcdermott@gmail.com> or
 * the current maintainer of this software if you do not have a copy of
 * the license file.
 *
 * -------------------------------------------------------------------
 *  REnet is a rust language wrapper for the ENet networking library
 *
 *  TODO List
 * -------------------------------------------------------------------
 */

extern crate libc;

use libc::{c_uint,c_void,size_t};
use std::io::net::ip::ToSocketAddr;
use std::io::net::ip::IpAddr;

pub mod ffi;

pub fn initialize() -> Result<(), i32>  {
    unsafe {
        match ffi::enet_initialize() {
            0    => Ok(()),
            code => Err(code)
        }
    }
}

pub fn deinitialize() {
    unsafe {
        ffi::enet_deinitialize();
    }
}

pub fn linked_version() -> u32 {
    unsafe {
        ffi::enet_linked_version() as u32
    }
}

/*
 * ------------------------------------------------------------------
 * Host object: a wrapper around ENetHost*
 * ------------------------------------------------------------------
 */
pub struct Host {
    ffi_handle : *mut c_void,
}

impl Host {
    pub fn new<A: ToSocketAddr>(address: Option<A>,
                                peer_count: u32,
                                channel_count: u32,
                                incomming_bandwidth: u32,
                                outgoing_bandwidth: u32)
    -> Result<Host, &'static str> {

        let p_addr = match address {
            Some(addr) => {
                let socket_addr = match addr.to_socket_addr() {
                    Ok(a)      => a,
                    Err(ioerr) => return Err(ioerr.desc)
                };

                let socket_ip : u32 = match socket_addr.ip {
                    IpAddr::Ipv4Addr(a,b,c,d) => (a as u32 <<24) + (b as u32 <<16) + (c as u32 <<8) + d as u32,
                    _                         => return Err("IPv6 not currently supported")
                };
                let eaddr = ffi::ENetAddress{host:socket_ip, port:socket_addr.port};
                &eaddr as *const _ as *const c_void
            }
            None => 0 as *const c_void
        };

        let host = unsafe { ffi::enet_host_create(p_addr,
                                                  peer_count as size_t,
                                                  channel_count as size_t,
                                                  incomming_bandwidth as c_uint,
                                                  outgoing_bandwidth as c_uint)
                          };

        let p_host = host as *mut Host;

        if p_host.is_null() { return Err("Could not initialize host"); }
        else                { return Ok(Host{ffi_handle:host}); }
    }
}

impl Drop for Host {
    fn drop(&mut self) {
        unsafe { ffi::enet_host_destroy(self.ffi_handle); }
    }
}
<|endoftext|>