<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Complex numbers.

use std::fmt;
use std::num::{Zero,One,ToStrRadix};

// FIXME #1284: handle complex NaN & infinity etc. This
// probably doesn't map to C's _Complex correctly.

// FIXME #5734:: Need generic sin/cos for .to/from_polar().
// FIXME #5735: Need generic sqrt to implement .norm().

/// A complex number in Cartesian form.
#[deriving(Eq,Clone)]
pub struct Cmplx<T> {
    /// Real portion of the complex number
    re: T,
    /// Imaginary portion of the complex number
    im: T
}

pub type Complex32 = Cmplx<f32>;
pub type Complex64 = Cmplx<f64>;

impl<T: Clone + Num> Cmplx<T> {
    /// Create a new Cmplx
    #[inline]
    pub fn new(re: T, im: T) -> Cmplx<T> {
        Cmplx { re: re, im: im }
    }

    /**
    Returns the square of the norm (since `T` doesn't necessarily
    have a sqrt function), i.e. `re^2 + im^2`.
    */
    #[inline]
    pub fn norm_sqr(&self) -> T {
        self.re * self.re + self.im * self.im
    }

    /// Returns the complex conjugate. i.e. `re - i im`
    #[inline]
    pub fn conj(&self) -> Cmplx<T> {
        Cmplx::new(self.re.clone(), -self.im)
    }

    /// Multiplies `self` by the scalar `t`.
    #[inline]
    pub fn scale(&self, t: T) -> Cmplx<T> {
        Cmplx::new(self.re * t, self.im * t)
    }

    /// Divides `self` by the scalar `t`.
    #[inline]
    pub fn unscale(&self, t: T) -> Cmplx<T> {
        Cmplx::new(self.re / t, self.im / t)
    }

    /// Returns `1/self`
    #[inline]
    pub fn inv(&self) -> Cmplx<T> {
        let norm_sqr = self.norm_sqr();
        Cmplx::new(self.re / norm_sqr,
                    -self.im / norm_sqr)
    }
}

impl<T: Clone + Float> Cmplx<T> {
    /// Calculate |self|
    #[inline]
    pub fn norm(&self) -> T {
        self.re.hypot(&self.im)
    }
}

impl<T: Clone + Float> Cmplx<T> {
    /// Calculate the principal Arg of self.
    #[inline]
    pub fn arg(&self) -> T {
        self.im.atan2(&self.re)
    }
    /// Convert to polar form (r, theta), such that `self = r * exp(i
    /// * theta)`
    #[inline]
    pub fn to_polar(&self) -> (T, T) {
        (self.norm(), self.arg())
    }
    /// Convert a polar representation into a complex number.
    #[inline]
    pub fn from_polar(r: &T, theta: &T) -> Cmplx<T> {
        Cmplx::new(*r * theta.cos(), *r * theta.sin())
    }
}

/* arithmetic */
// (a + i b) + (c + i d) == (a + c) + i (b + d)
impl<T: Clone + Num> Add<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn add(&self, other: &Cmplx<T>) -> Cmplx<T> {
        Cmplx::new(self.re + other.re, self.im + other.im)
    }
}
// (a + i b) - (c + i d) == (a - c) + i (b - d)
impl<T: Clone + Num> Sub<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn sub(&self, other: &Cmplx<T>) -> Cmplx<T> {
        Cmplx::new(self.re - other.re, self.im - other.im)
    }
}
// (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c)
impl<T: Clone + Num> Mul<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn mul(&self, other: &Cmplx<T>) -> Cmplx<T> {
        Cmplx::new(self.re*other.re - self.im*other.im,
                   self.re*other.im + self.im*other.re)
    }
}

// (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d)
//   == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)]
impl<T: Clone + Num> Div<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn div(&self, other: &Cmplx<T>) -> Cmplx<T> {
        let norm_sqr = other.norm_sqr();
        Cmplx::new((self.re*other.re + self.im*other.im) / norm_sqr,
                   (self.im*other.re - self.re*other.im) / norm_sqr)
    }
}

impl<T: Clone + Num> Neg<Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn neg(&self) -> Cmplx<T> {
        Cmplx::new(-self.re, -self.im)
    }
}

/* constants */
impl<T: Clone + Num> Zero for Cmplx<T> {
    #[inline]
    fn zero() -> Cmplx<T> {
        Cmplx::new(Zero::zero(), Zero::zero())
    }

    #[inline]
    fn is_zero(&self) -> bool {
        self.re.is_zero() && self.im.is_zero()
    }
}

impl<T: Clone + Num> One for Cmplx<T> {
    #[inline]
    fn one() -> Cmplx<T> {
        Cmplx::new(One::one(), Zero::zero())
    }
}

/* string conversions */
impl<T: fmt::Show + Num + Ord> fmt::Show for Cmplx<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.im < Zero::zero() {
            write!(f.buf, "{}-{}i", self.re, -self.im)
        } else {
            write!(f.buf, "{}+{}i", self.re, self.im)
        }
    }
}

impl<T: ToStrRadix + Num + Ord> ToStrRadix for Cmplx<T> {
    fn to_str_radix(&self, radix: uint) -> ~str {
        if self.im < Zero::zero() {
            format!("{}-{}i", self.re.to_str_radix(radix), (-self.im).to_str_radix(radix))
        } else {
            format!("{}+{}i", self.re.to_str_radix(radix), self.im.to_str_radix(radix))
        }
    }
}

#[cfg(test)]
mod test {
    #![allow(non_uppercase_statics)]

    use super::{Complex64, Cmplx};
    use std::num::{Zero,One,Float};

    pub static _0_0i : Complex64 = Cmplx { re: 0.0, im: 0.0 };
    pub static _1_0i : Complex64 = Cmplx { re: 1.0, im: 0.0 };
    pub static _1_1i : Complex64 = Cmplx { re: 1.0, im: 1.0 };
    pub static _0_1i : Complex64 = Cmplx { re: 0.0, im: 1.0 };
    pub static _neg1_1i : Complex64 = Cmplx { re: -1.0, im: 1.0 };
    pub static _05_05i : Complex64 = Cmplx { re: 0.5, im: 0.5 };
    pub static all_consts : [Complex64, .. 5] = [_0_0i, _1_0i, _1_1i, _neg1_1i, _05_05i];

    #[test]
    fn test_consts() {
        // check our constants are what Cmplx::new creates
        fn test(c : Complex64, r : f64, i: f64) {
            assert_eq!(c, Cmplx::new(r,i));
        }
        test(_0_0i, 0.0, 0.0);
        test(_1_0i, 1.0, 0.0);
        test(_1_1i, 1.0, 1.0);
        test(_neg1_1i, -1.0, 1.0);
        test(_05_05i, 0.5, 0.5);

        assert_eq!(_0_0i, Zero::zero());
        assert_eq!(_1_0i, One::one());
    }

    #[test]
    #[ignore(cfg(target_arch = "x86"))]
    // FIXME #7158: (maybe?) currently failing on x86.
    fn test_norm() {
        fn test(c: Complex64, ns: f64) {
            assert_eq!(c.norm_sqr(), ns);
            assert_eq!(c.norm(), ns.sqrt())
        }
        test(_0_0i, 0.0);
        test(_1_0i, 1.0);
        test(_1_1i, 2.0);
        test(_neg1_1i, 2.0);
        test(_05_05i, 0.5);
    }

    #[test]
    fn test_scale_unscale() {
        assert_eq!(_05_05i.scale(2.0), _1_1i);
        assert_eq!(_1_1i.unscale(2.0), _05_05i);
        for &c in all_consts.iter() {
            assert_eq!(c.scale(2.0).unscale(2.0), c);
        }
    }

    #[test]
    fn test_conj() {
        for &c in all_consts.iter() {
            assert_eq!(c.conj(), Cmplx::new(c.re, -c.im));
            assert_eq!(c.conj().conj(), c);
        }
    }

    #[test]
    fn test_inv() {
        assert_eq!(_1_1i.inv(), _05_05i.conj());
        assert_eq!(_1_0i.inv(), _1_0i.inv());
    }

    #[test]
    #[should_fail]
    #[ignore]
    fn test_inv_zero() {
        // FIXME #5736: should this really fail, or just NaN?
        _0_0i.inv();
    }

    #[test]
    fn test_arg() {
        fn test(c: Complex64, arg: f64) {
            assert!((c.arg() - arg).abs() < 1.0e-6)
        }
        test(_1_0i, 0.0);
        test(_1_1i, 0.25 * Float::pi());
        test(_neg1_1i, 0.75 * Float::pi());
        test(_05_05i, 0.25 * Float::pi());
    }

    #[test]
    fn test_polar_conv() {
        fn test(c: Complex64) {
            let (r, theta) = c.to_polar();
            assert!((c - Cmplx::from_polar(&r, &theta)).norm() < 1e-6);
        }
        for &c in all_consts.iter() { test(c); }
    }

    mod arith {
        use super::{_0_0i, _1_0i, _1_1i, _0_1i, _neg1_1i, _05_05i, all_consts};
        use std::num::Zero;

        #[test]
        fn test_add() {
            assert_eq!(_05_05i + _05_05i, _1_1i);
            assert_eq!(_0_1i + _1_0i, _1_1i);
            assert_eq!(_1_0i + _neg1_1i, _0_1i);

            for &c in all_consts.iter() {
                assert_eq!(_0_0i + c, c);
                assert_eq!(c + _0_0i, c);
            }
        }

        #[test]
        fn test_sub() {
            assert_eq!(_05_05i - _05_05i, _0_0i);
            assert_eq!(_0_1i - _1_0i, _neg1_1i);
            assert_eq!(_0_1i - _neg1_1i, _1_0i);

            for &c in all_consts.iter() {
                assert_eq!(c - _0_0i, c);
                assert_eq!(c - c, _0_0i);
            }
        }

        #[test]
        fn test_mul() {
            assert_eq!(_05_05i * _05_05i, _0_1i.unscale(2.0));
            assert_eq!(_1_1i * _0_1i, _neg1_1i);

            // i^2 & i^4
            assert_eq!(_0_1i * _0_1i, -_1_0i);
            assert_eq!(_0_1i * _0_1i * _0_1i * _0_1i, _1_0i);

            for &c in all_consts.iter() {
                assert_eq!(c * _1_0i, c);
                assert_eq!(_1_0i * c, c);
            }
        }
        #[test]
        fn test_div() {
            assert_eq!(_neg1_1i / _0_1i, _1_1i);
            for &c in all_consts.iter() {
                if c != Zero::zero() {
                    assert_eq!(c / c, _1_0i);
                }
            }
        }
        #[test]
        fn test_neg() {
            assert_eq!(-_1_0i + _0_1i, _neg1_1i);
            assert_eq!((-_0_1i) * _0_1i, _1_0i);
            for &c in all_consts.iter() {
                assert_eq!(-(-c), c);
            }
        }
    }

    #[test]
    fn test_to_str() {
        fn test(c : Complex64, s: ~str) {
            assert_eq!(c.to_str(), s);
        }
        test(_0_0i, ~"0+0i");
        test(_1_0i, ~"1+0i");
        test(_0_1i, ~"0+1i");
        test(_1_1i, ~"1+1i");
        test(_neg1_1i, ~"-1+1i");
        test(-_neg1_1i, ~"1-1i");
        test(_05_05i, ~"0.5+0.5i");
    }
}
<commit_msg>auto merge of #13248 : tedhorst/rust/master, r=alexcrichton<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Complex numbers.

use std::fmt;
use std::num::{Zero,One,ToStrRadix};

// FIXME #1284: handle complex NaN & infinity etc. This
// probably doesn't map to C's _Complex correctly.

// FIXME #5734:: Need generic sin/cos for .to/from_polar().
// FIXME #5735: Need generic sqrt to implement .norm().

/// A complex number in Cartesian form.
#[deriving(Eq,Clone)]
pub struct Cmplx<T> {
    /// Real portion of the complex number
    pub re: T,
    /// Imaginary portion of the complex number
    pub im: T
}

pub type Complex32 = Cmplx<f32>;
pub type Complex64 = Cmplx<f64>;

impl<T: Clone + Num> Cmplx<T> {
    /// Create a new Cmplx
    #[inline]
    pub fn new(re: T, im: T) -> Cmplx<T> {
        Cmplx { re: re, im: im }
    }

    /**
    Returns the square of the norm (since `T` doesn't necessarily
    have a sqrt function), i.e. `re^2 + im^2`.
    */
    #[inline]
    pub fn norm_sqr(&self) -> T {
        self.re * self.re + self.im * self.im
    }

    /// Returns the complex conjugate. i.e. `re - i im`
    #[inline]
    pub fn conj(&self) -> Cmplx<T> {
        Cmplx::new(self.re.clone(), -self.im)
    }

    /// Multiplies `self` by the scalar `t`.
    #[inline]
    pub fn scale(&self, t: T) -> Cmplx<T> {
        Cmplx::new(self.re * t, self.im * t)
    }

    /// Divides `self` by the scalar `t`.
    #[inline]
    pub fn unscale(&self, t: T) -> Cmplx<T> {
        Cmplx::new(self.re / t, self.im / t)
    }

    /// Returns `1/self`
    #[inline]
    pub fn inv(&self) -> Cmplx<T> {
        let norm_sqr = self.norm_sqr();
        Cmplx::new(self.re / norm_sqr,
                    -self.im / norm_sqr)
    }
}

impl<T: Clone + Float> Cmplx<T> {
    /// Calculate |self|
    #[inline]
    pub fn norm(&self) -> T {
        self.re.hypot(&self.im)
    }
}

impl<T: Clone + Float> Cmplx<T> {
    /// Calculate the principal Arg of self.
    #[inline]
    pub fn arg(&self) -> T {
        self.im.atan2(&self.re)
    }
    /// Convert to polar form (r, theta), such that `self = r * exp(i
    /// * theta)`
    #[inline]
    pub fn to_polar(&self) -> (T, T) {
        (self.norm(), self.arg())
    }
    /// Convert a polar representation into a complex number.
    #[inline]
    pub fn from_polar(r: &T, theta: &T) -> Cmplx<T> {
        Cmplx::new(*r * theta.cos(), *r * theta.sin())
    }
}

/* arithmetic */
// (a + i b) + (c + i d) == (a + c) + i (b + d)
impl<T: Clone + Num> Add<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn add(&self, other: &Cmplx<T>) -> Cmplx<T> {
        Cmplx::new(self.re + other.re, self.im + other.im)
    }
}
// (a + i b) - (c + i d) == (a - c) + i (b - d)
impl<T: Clone + Num> Sub<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn sub(&self, other: &Cmplx<T>) -> Cmplx<T> {
        Cmplx::new(self.re - other.re, self.im - other.im)
    }
}
// (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c)
impl<T: Clone + Num> Mul<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn mul(&self, other: &Cmplx<T>) -> Cmplx<T> {
        Cmplx::new(self.re*other.re - self.im*other.im,
                   self.re*other.im + self.im*other.re)
    }
}

// (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d)
//   == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)]
impl<T: Clone + Num> Div<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn div(&self, other: &Cmplx<T>) -> Cmplx<T> {
        let norm_sqr = other.norm_sqr();
        Cmplx::new((self.re*other.re + self.im*other.im) / norm_sqr,
                   (self.im*other.re - self.re*other.im) / norm_sqr)
    }
}

impl<T: Clone + Num> Neg<Cmplx<T>> for Cmplx<T> {
    #[inline]
    fn neg(&self) -> Cmplx<T> {
        Cmplx::new(-self.re, -self.im)
    }
}

/* constants */
impl<T: Clone + Num> Zero for Cmplx<T> {
    #[inline]
    fn zero() -> Cmplx<T> {
        Cmplx::new(Zero::zero(), Zero::zero())
    }

    #[inline]
    fn is_zero(&self) -> bool {
        self.re.is_zero() && self.im.is_zero()
    }
}

impl<T: Clone + Num> One for Cmplx<T> {
    #[inline]
    fn one() -> Cmplx<T> {
        Cmplx::new(One::one(), Zero::zero())
    }
}

/* string conversions */
impl<T: fmt::Show + Num + Ord> fmt::Show for Cmplx<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.im < Zero::zero() {
            write!(f.buf, "{}-{}i", self.re, -self.im)
        } else {
            write!(f.buf, "{}+{}i", self.re, self.im)
        }
    }
}

impl<T: ToStrRadix + Num + Ord> ToStrRadix for Cmplx<T> {
    fn to_str_radix(&self, radix: uint) -> ~str {
        if self.im < Zero::zero() {
            format!("{}-{}i", self.re.to_str_radix(radix), (-self.im).to_str_radix(radix))
        } else {
            format!("{}+{}i", self.re.to_str_radix(radix), self.im.to_str_radix(radix))
        }
    }
}

#[cfg(test)]
mod test {
    #![allow(non_uppercase_statics)]

    use super::{Complex64, Cmplx};
    use std::num::{Zero,One,Float};

    pub static _0_0i : Complex64 = Cmplx { re: 0.0, im: 0.0 };
    pub static _1_0i : Complex64 = Cmplx { re: 1.0, im: 0.0 };
    pub static _1_1i : Complex64 = Cmplx { re: 1.0, im: 1.0 };
    pub static _0_1i : Complex64 = Cmplx { re: 0.0, im: 1.0 };
    pub static _neg1_1i : Complex64 = Cmplx { re: -1.0, im: 1.0 };
    pub static _05_05i : Complex64 = Cmplx { re: 0.5, im: 0.5 };
    pub static all_consts : [Complex64, .. 5] = [_0_0i, _1_0i, _1_1i, _neg1_1i, _05_05i];

    #[test]
    fn test_consts() {
        // check our constants are what Cmplx::new creates
        fn test(c : Complex64, r : f64, i: f64) {
            assert_eq!(c, Cmplx::new(r,i));
        }
        test(_0_0i, 0.0, 0.0);
        test(_1_0i, 1.0, 0.0);
        test(_1_1i, 1.0, 1.0);
        test(_neg1_1i, -1.0, 1.0);
        test(_05_05i, 0.5, 0.5);

        assert_eq!(_0_0i, Zero::zero());
        assert_eq!(_1_0i, One::one());
    }

    #[test]
    #[ignore(cfg(target_arch = "x86"))]
    // FIXME #7158: (maybe?) currently failing on x86.
    fn test_norm() {
        fn test(c: Complex64, ns: f64) {
            assert_eq!(c.norm_sqr(), ns);
            assert_eq!(c.norm(), ns.sqrt())
        }
        test(_0_0i, 0.0);
        test(_1_0i, 1.0);
        test(_1_1i, 2.0);
        test(_neg1_1i, 2.0);
        test(_05_05i, 0.5);
    }

    #[test]
    fn test_scale_unscale() {
        assert_eq!(_05_05i.scale(2.0), _1_1i);
        assert_eq!(_1_1i.unscale(2.0), _05_05i);
        for &c in all_consts.iter() {
            assert_eq!(c.scale(2.0).unscale(2.0), c);
        }
    }

    #[test]
    fn test_conj() {
        for &c in all_consts.iter() {
            assert_eq!(c.conj(), Cmplx::new(c.re, -c.im));
            assert_eq!(c.conj().conj(), c);
        }
    }

    #[test]
    fn test_inv() {
        assert_eq!(_1_1i.inv(), _05_05i.conj());
        assert_eq!(_1_0i.inv(), _1_0i.inv());
    }

    #[test]
    #[should_fail]
    #[ignore]
    fn test_inv_zero() {
        // FIXME #5736: should this really fail, or just NaN?
        _0_0i.inv();
    }

    #[test]
    fn test_arg() {
        fn test(c: Complex64, arg: f64) {
            assert!((c.arg() - arg).abs() < 1.0e-6)
        }
        test(_1_0i, 0.0);
        test(_1_1i, 0.25 * Float::pi());
        test(_neg1_1i, 0.75 * Float::pi());
        test(_05_05i, 0.25 * Float::pi());
    }

    #[test]
    fn test_polar_conv() {
        fn test(c: Complex64) {
            let (r, theta) = c.to_polar();
            assert!((c - Cmplx::from_polar(&r, &theta)).norm() < 1e-6);
        }
        for &c in all_consts.iter() { test(c); }
    }

    mod arith {
        use super::{_0_0i, _1_0i, _1_1i, _0_1i, _neg1_1i, _05_05i, all_consts};
        use std::num::Zero;

        #[test]
        fn test_add() {
            assert_eq!(_05_05i + _05_05i, _1_1i);
            assert_eq!(_0_1i + _1_0i, _1_1i);
            assert_eq!(_1_0i + _neg1_1i, _0_1i);

            for &c in all_consts.iter() {
                assert_eq!(_0_0i + c, c);
                assert_eq!(c + _0_0i, c);
            }
        }

        #[test]
        fn test_sub() {
            assert_eq!(_05_05i - _05_05i, _0_0i);
            assert_eq!(_0_1i - _1_0i, _neg1_1i);
            assert_eq!(_0_1i - _neg1_1i, _1_0i);

            for &c in all_consts.iter() {
                assert_eq!(c - _0_0i, c);
                assert_eq!(c - c, _0_0i);
            }
        }

        #[test]
        fn test_mul() {
            assert_eq!(_05_05i * _05_05i, _0_1i.unscale(2.0));
            assert_eq!(_1_1i * _0_1i, _neg1_1i);

            // i^2 & i^4
            assert_eq!(_0_1i * _0_1i, -_1_0i);
            assert_eq!(_0_1i * _0_1i * _0_1i * _0_1i, _1_0i);

            for &c in all_consts.iter() {
                assert_eq!(c * _1_0i, c);
                assert_eq!(_1_0i * c, c);
            }
        }
        #[test]
        fn test_div() {
            assert_eq!(_neg1_1i / _0_1i, _1_1i);
            for &c in all_consts.iter() {
                if c != Zero::zero() {
                    assert_eq!(c / c, _1_0i);
                }
            }
        }
        #[test]
        fn test_neg() {
            assert_eq!(-_1_0i + _0_1i, _neg1_1i);
            assert_eq!((-_0_1i) * _0_1i, _1_0i);
            for &c in all_consts.iter() {
                assert_eq!(-(-c), c);
            }
        }
    }

    #[test]
    fn test_to_str() {
        fn test(c : Complex64, s: ~str) {
            assert_eq!(c.to_str(), s);
        }
        test(_0_0i, ~"0+0i");
        test(_1_0i, ~"1+0i");
        test(_0_1i, ~"0+1i");
        test(_1_1i, ~"1+1i");
        test(_neg1_1i, ~"-1+1i");
        test(-_neg1_1i, ~"1-1i");
        test(_05_05i, ~"0.5+0.5i");
    }
}
<|endoftext|>


<commit_before>//! Virtualize processor hardware for multiple software environments using Virtual Machine Extensions.

use crate::bits64::rflags::{self, RFlags};
use crate::vmx::{Result, VmFail};

/// Helper used to extract VMX-specific Result in accordance with
/// conventions described in Intel SDM, Volume 3C, Section 30.2.
#[inline(always)]
fn vmx_capture_status() -> Result<()> {
    let flags = unsafe { rflags::read() };

    if flags.contains(RFlags::FLAGS_ZF) {
        Err(VmFail::VmFailValid)
    } else if flags.contains(RFlags::FLAGS_CF) {
        Err(VmFail::VmFailInvalid)
    } else {
        Ok(())
    }
}

/// Enable VMX operation.
///
/// `addr` specifies a 4KB-aligned physical address of VMXON region initialized
/// in accordance with Intel SDM, Volume 3C, Section 24.11.5.
#[inline(always)]
pub unsafe fn vmxon(addr: u64) -> Result<()> {
    asm!("vmxon $0" : /* no outputs */ : "m"(addr));
    vmx_capture_status()
}

/// Disable VMX operation.
#[inline(always)]
pub unsafe fn vmxoff() -> Result<()> {
    asm!("vmxoff");
    vmx_capture_status()
}

/// Clear VMCS.
///
/// Ensures that VMCS data maintained on the processor is copied to the VMCS region
/// located at 4KB-aligned physical address `addr` and initializes some parts of it.
#[inline(always)]
pub unsafe fn vmclear(addr: u64) -> Result<()> {
    asm!("vmclear $0" : /* no outputs */ : "m"(addr));
    vmx_capture_status()
}

/// Load current VMCS pointer.
///
/// Marks the current-VMCS pointer valid and loads it with the physical address `addr`.
#[inline(always)]
pub unsafe fn vmptrld(addr: u64) -> Result<()> {
    asm!("vmptrld $0" : /* no outputs */ : "m"(addr));
    vmx_capture_status()
}

/// Return current VMCS pointer.
#[inline(always)]
pub unsafe fn vmptrst() -> Result<u64> {
    let value: u64 = 0;
    asm!("vmptrst ($0)" : /* no outputs */ : "r"(&value) : "memory");
    vmx_capture_status().and(Ok(value))
}

/// Read a specified field from a VMCS.
#[inline(always)]
pub unsafe fn vmread(field: u32) -> Result<u64> {
    let field: u64 = field.into();
    let value: u64;
    asm!("vmread $1, $0" : "=r"(value) : "r"(field));
    vmx_capture_status().and(Ok(value))
}

/// Write to a specified field in a VMCS.
#[inline(always)]
pub unsafe fn vmwrite(field: u32, value: u64) -> Result<()> {
    let field: u64 = field.into();
    asm!("vmwrite $1, $0" : /* no outputs */ : "r"(field), "r"(value));
    vmx_capture_status()
}

/// Launch virtual machine.
#[inline(always)]
pub unsafe fn vmlaunch() -> Result<()> {
    asm!("vmlaunch");
    vmx_capture_status()
}

/// Resume virtual machine.
#[inline(always)]
pub unsafe fn vmresume() -> Result<()> {
    asm!("vmresume");
    vmx_capture_status()
}
<commit_msg>No need to inline VMX intrinsics<commit_after>//! Virtualize processor hardware for multiple software environments using Virtual Machine Extensions.

use crate::bits64::rflags::{self, RFlags};
use crate::vmx::{Result, VmFail};

/// Helper used to extract VMX-specific Result in accordance with
/// conventions described in Intel SDM, Volume 3C, Section 30.2.
#[inline(always)]
fn vmx_capture_status() -> Result<()> {
    let flags = unsafe { rflags::read() };

    if flags.contains(RFlags::FLAGS_ZF) {
        Err(VmFail::VmFailValid)
    } else if flags.contains(RFlags::FLAGS_CF) {
        Err(VmFail::VmFailInvalid)
    } else {
        Ok(())
    }
}

/// Enable VMX operation.
///
/// `addr` specifies a 4KB-aligned physical address of VMXON region initialized
/// in accordance with Intel SDM, Volume 3C, Section 24.11.5.
pub unsafe fn vmxon(addr: u64) -> Result<()> {
    asm!("vmxon $0" : /* no outputs */ : "m"(addr));
    vmx_capture_status()
}

/// Disable VMX operation.
pub unsafe fn vmxoff() -> Result<()> {
    asm!("vmxoff");
    vmx_capture_status()
}

/// Clear VMCS.
///
/// Ensures that VMCS data maintained on the processor is copied to the VMCS region
/// located at 4KB-aligned physical address `addr` and initializes some parts of it.
pub unsafe fn vmclear(addr: u64) -> Result<()> {
    asm!("vmclear $0" : /* no outputs */ : "m"(addr));
    vmx_capture_status()
}

/// Load current VMCS pointer.
///
/// Marks the current-VMCS pointer valid and loads it with the physical address `addr`.
pub unsafe fn vmptrld(addr: u64) -> Result<()> {
    asm!("vmptrld $0" : /* no outputs */ : "m"(addr));
    vmx_capture_status()
}

/// Return current VMCS pointer.
pub unsafe fn vmptrst() -> Result<u64> {
    let value: u64 = 0;
    asm!("vmptrst ($0)" : /* no outputs */ : "r"(&value) : "memory");
    vmx_capture_status().and(Ok(value))
}

/// Read a specified field from a VMCS.
pub unsafe fn vmread(field: u32) -> Result<u64> {
    let field: u64 = field.into();
    let value: u64;
    asm!("vmread $1, $0" : "=r"(value) : "r"(field));
    vmx_capture_status().and(Ok(value))
}

/// Write to a specified field in a VMCS.
pub unsafe fn vmwrite(field: u32, value: u64) -> Result<()> {
    let field: u64 = field.into();
    asm!("vmwrite $1, $0" : /* no outputs */ : "r"(field), "r"(value));
    vmx_capture_status()
}

/// Launch virtual machine.
pub unsafe fn vmlaunch() -> Result<()> {
    asm!("vmlaunch");
    vmx_capture_status()
}

/// Resume virtual machine.
pub unsafe fn vmresume() -> Result<()> {
    asm!("vmresume");
    vmx_capture_status()
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Many programming languages have a 'prelude': a particular subset of the
libraries that come with the language. Every program imports the prelude by
default.

For example, it would be annoying to add `use std::io::println;` to every single
program, and the vast majority of Rust programs will wish to print to standard
output. Therefore, it makes sense to import it into every program.

Rust's prelude has three main parts:

1. io::print and io::println.
2. Core operators, such as `Add`, `Mul`, and `Not`.
3. Various types and traits, such as `Clone`, `Eq`, and `comm::Chan`.

*/

// Reexported core operators
pub use either::{Either, Left, Right};
pub use kinds::{Const, Copy, Owned, Sized};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

// Reexported functions
pub use io::{print, println};

// Reexported types and traits
pub use clone::{Clone, DeepClone};
pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use char::Char;
pub use container::{Container, Mutable, Map, Set};
pub use hash::Hash;
pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
pub use old_iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
pub use old_iter::{ExtendedMutableIter};
pub use iter::{Times, FromIter};
// FIXME: #5898 pub use iterator::{Iterator, IteratorUtil};
pub use num::{Num, NumCast};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, Int, Float};
pub use path::GenericPath;
pub use path::Path;
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::RawPtr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use str::{StrVector, StrSlice, OwnedStr, StrUtil};
pub use from_str::{FromStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12};
pub use tuple::{ImmutableTuple2, ImmutableTuple3, ImmutableTuple4, ImmutableTuple5};
pub use tuple::{ImmutableTuple6, ImmutableTuple7, ImmutableTuple8, ImmutableTuple9};
pub use tuple::{ImmutableTuple10, ImmutableTuple11, ImmutableTuple12};
pub use vec::{VectorVector, CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};

// Reexported runtime types
pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
pub use task::spawn;
<commit_msg>add the Iterator trait to the prelude<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Many programming languages have a 'prelude': a particular subset of the
libraries that come with the language. Every program imports the prelude by
default.

For example, it would be annoying to add `use std::io::println;` to every single
program, and the vast majority of Rust programs will wish to print to standard
output. Therefore, it makes sense to import it into every program.

Rust's prelude has three main parts:

1. io::print and io::println.
2. Core operators, such as `Add`, `Mul`, and `Not`.
3. Various types and traits, such as `Clone`, `Eq`, and `comm::Chan`.

*/

// Reexported core operators
pub use either::{Either, Left, Right};
pub use kinds::{Const, Copy, Owned, Sized};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

// Reexported functions
pub use io::{print, println};

// Reexported types and traits
pub use clone::{Clone, DeepClone};
pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use char::Char;
pub use container::{Container, Mutable, Map, Set};
pub use hash::Hash;
pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
pub use old_iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
pub use old_iter::{ExtendedMutableIter};
pub use iter::{Times, FromIter};
// FIXME: #5898 pub use iterator::{Iterator, IteratorUtil};
pub use iterator::Iterator;
pub use num::{Num, NumCast};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, Int, Float};
pub use path::GenericPath;
pub use path::Path;
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::RawPtr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use str::{StrVector, StrSlice, OwnedStr, StrUtil};
pub use from_str::{FromStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12};
pub use tuple::{ImmutableTuple2, ImmutableTuple3, ImmutableTuple4, ImmutableTuple5};
pub use tuple::{ImmutableTuple6, ImmutableTuple7, ImmutableTuple8, ImmutableTuple9};
pub use tuple::{ImmutableTuple10, ImmutableTuple11, ImmutableTuple12};
pub use vec::{VectorVector, CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};

// Reexported runtime types
pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
pub use task::spawn;
<|endoftext|>


<commit_before>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    use prelude::v1::*;
    use self::OsRngInner::*;

    use libc;
    use mem;
    use old_io::{IoResult, File};
    use old_path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use sys::os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
        const NR_GETRANDOM: libc::c_long = 384;
        #[cfg(target_arch = "powerpc")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        if !GETRANDOM_CHECKED.load(Ordering::Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Ordering::Relaxed);
            GETRANDOM_CHECKED.store(true, Ordering::Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Ordering::Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    use prelude::v1::*;

    use old_io::IoResult;
    use mem;
    use os;
    use rand::Rng;
    use libc::{c_int, size_t};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    use prelude::v1::*;

    use io;
    use mem;
    use old_io::{IoResult, IoError};
    use rand::Rng;
    use libc::types::os::arch::extra::{LONG_PTR};
    use libc::{DWORD, BYTE, LPCSTR, BOOL};

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    const PROV_RSA_FULL: DWORD = 1;
    const CRYPT_SILENT: DWORD = 64;
    const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}",
                       io::Error::last_os_error());
            }
        }
    }
}

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

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in 0..20 {
            let (tx, rx) = channel();
            txs.push(tx);

            thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                thread::yield_now();
                let mut v = [0; 1000];

                for _ in 0..100 {
                    r.next_u32();
                    thread::yield_now();
                    r.next_u64();
                    thread::yield_now();
                    r.fill_bytes(&mut v);
                    thread::yield_now();
                }
            });
        }

        // start all the tasks
        for tx in &txs {
            tx.send(()).unwrap();
        }
    }
}
<commit_msg>rollup merge of #23942: vhbit/ios-rand<commit_after>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    use prelude::v1::*;
    use self::OsRngInner::*;

    use libc;
    use mem;
    use old_io::{IoResult, File};
    use old_path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use sys::os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
        const NR_GETRANDOM: libc::c_long = 384;
        #[cfg(target_arch = "powerpc")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        if !GETRANDOM_CHECKED.load(Ordering::Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Ordering::Relaxed);
            GETRANDOM_CHECKED.store(true, Ordering::Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Ordering::Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    use prelude::v1::*;

    use io;
    use old_io::IoResult;
    use mem;
    use rand::Rng;
    use libc::{c_int, size_t};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    use prelude::v1::*;

    use io;
    use mem;
    use old_io::{IoResult, IoError};
    use rand::Rng;
    use libc::types::os::arch::extra::{LONG_PTR};
    use libc::{DWORD, BYTE, LPCSTR, BOOL};

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    const PROV_RSA_FULL: DWORD = 1;
    const CRYPT_SILENT: DWORD = 64;
    const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}",
                       io::Error::last_os_error());
            }
        }
    }
}

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

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in 0..20 {
            let (tx, rx) = channel();
            txs.push(tx);

            thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                thread::yield_now();
                let mut v = [0; 1000];

                for _ in 0..100 {
                    r.next_u32();
                    thread::yield_now();
                    r.next_u64();
                    thread::yield_now();
                    r.fill_bytes(&mut v);
                    thread::yield_now();
                }
            });
        }

        // start all the tasks
        for tx in &txs {
            tx.send(()).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
 * A key,value store that works on anything.
 *
 * This works using a binary search tree. In the first version, it's a
 * very naive algorithm, but it will probably be updated to be a
 * red-black tree or something else.
 */
#[forbid(deprecated_mode)];

use core::cmp::{Eq, Ord};
use core::option::{Option, Some, None};
use core::prelude::*;

pub type TreeMap<K: Copy Eq Ord, V: Copy> = @mut TreeEdge<K, V>;

type TreeEdge<K: Copy Eq Ord, V: Copy> = Option<@TreeNode<K, V>>;

struct TreeNode<K: Copy Eq Ord, V: Copy> {
    key: K,
    mut value: V,
    mut left: TreeEdge<K, V>,
    mut right: TreeEdge<K, V>
}

/// Create a treemap
pub fn TreeMap<K: Copy Eq Ord, V: Copy>() -> TreeMap<K, V> { @mut None }

/// Insert a value into the map
pub fn insert<K: Copy Eq Ord, V: Copy>(m: &mut TreeEdge<K, V>, k: K, v: V) {
    match copy *m {
      None => {
        *m = Some(@TreeNode {key: k,
                             mut value: v,
                             mut left: None,
                             mut right: None});
        return;
      }
      Some(node) => {
        if k == node.key {
            node.value = v;
        } else if k < node.key {
            insert(&mut node.left, k, v);
        } else {
            insert(&mut node.right, k, v);
        }
      }
    };
}

/// Find a value based on the key
pub fn find<K: Copy Eq Ord, V: Copy>(m: &const TreeEdge<K, V>, k: K)
                              -> Option<V> {
    match copy *m {
      None => None,

      // FIXME (#2808): was that an optimization?
      Some(node) => {
        if k == node.key {
            Some(node.value)
        } else if k < node.key {
            find(&const node.left, k)
        } else {
            find(&const node.right, k)
        }
      }
    }
}

/// Visit all pairs in the map in order.
pub fn traverse<K: Copy Eq Ord, V: Copy>(m: &const TreeEdge<K, V>,
                                         f: fn((&K), (&V))) {
    match copy *m {
      None => (),
      Some(node) => {
        traverse(&const node.left, f);
        // copy of value is req'd as f() requires an immutable ptr
        f(&node.key, &copy node.value);
        traverse(&const node.right, f);
      }
    }
}

/// Compare two treemaps and return true iff
/// they contain same keys and values
pub fn equals<K: Copy Eq Ord, V: Copy Eq>(t1: &const TreeEdge<K, V>,
                                          t2: &const TreeEdge<K, V>)
                                        -> bool {
    let mut v1 = ~[];
    let mut v2 = ~[];
    traverse(t1, |k,v| { v1.push((copy *k, copy *v)) });
    traverse(t2, |k,v| { v2.push((copy *k, copy *v)) });
    return v1 == v2;
}

#[cfg(test)]
mod tests {
    #[legacy_exports];

    use treemap::*;

    use core::option::{None, Option, Some};
    use core::str;

    #[test]
    fn init_treemap() { let _m = TreeMap::<int, int>(); }

    #[test]
    fn insert_one() { let m = TreeMap(); insert(m, 1, 2); }

    #[test]
    fn insert_two() { let m = TreeMap(); insert(m, 1, 2); insert(m, 3, 4); }

    #[test]
    fn insert_find() {
        let m = TreeMap();
        insert(m, 1, 2);
        assert (find(m, 1) == Some(2));
    }

    #[test]
    fn find_empty() {
        let m = TreeMap::<int, int>(); assert (find(m, 1) == None);
    }

    #[test]
    fn find_not_found() {
        let m = TreeMap();
        insert(m, 1, 2);
        assert (find(m, 2) == None);
    }

    #[test]
    fn traverse_in_order() {
        let m = TreeMap();
        insert(m, 3, ());
        insert(m, 0, ());
        insert(m, 4, ());
        insert(m, 2, ());
        insert(m, 1, ());

        let n = @mut 0;
        fn t(n: @mut int, k: int, _v: ()) {
            assert (*n == k); *n += 1;
        }
        traverse(m, |x,y| t(n, *x, *y));
    }

    #[test]
    fn equality() {
        let m1 = TreeMap();
        insert(m1, 3, ());
        insert(m1, 0, ());
        insert(m1, 4, ());
        insert(m1, 2, ());
        insert(m1, 1, ());
        let m2 = TreeMap();
        insert(m2, 2, ());
        insert(m2, 1, ());
        insert(m2, 3, ());
        insert(m2, 0, ());
        insert(m2, 4, ());

        assert equals(m1, m2);

        let m3 = TreeMap();
        assert !equals(m1,m3);

    }

    #[test]
    fn u8_map() {
        let m = TreeMap();

        let k1 = str::to_bytes(~"foo");
        let k2 = str::to_bytes(~"bar");

        insert(m, k1, ~"foo");
        insert(m, k2, ~"bar");

        assert (find(m, k2) == Some(~"bar"));
        assert (find(m, k1) == Some(~"foo"));
    }
}
<commit_msg>replace treemap with a balanced tree<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An ordered map and set implemented as self-balancing binary search
//! trees. The only requirement for the types is that the key implements
//! `Ord`, and that the `lt` method provides a total ordering.

#[forbid(deprecated_mode)];

use core::cmp::{Eq, Ord};
use core::option::{Option, Some, None};
use core::prelude::*;

// This is implemented as an AA tree, which is a simplified variation of
// a red-black tree where where red (horizontal) nodes can only be added
// as a right child. The time complexity is the same, and re-balancing
// operations are more frequent but also cheaper.

// TODO: lazy iteration, for O(n) Eq and set operations instead of O(n*log(m))

// TODO: implement Ord for TreeSet
// could be superset/subset-based or in-order lexicographic comparison... but
// there are methods for is_superset/is_subset so lexicographic is more useful

// TODO: (possibly) implement the overloads Python does for sets:
//   * union: |
//   * intersection: &
//   * difference: -
//   * symmetric difference: ^
// These would be convenient since the methods will work like `each`

pub struct TreeMap<K: Ord, V> {
    priv root: Option<~TreeNode<K, V>>,
    priv length: uint
}

// FIXME: this is a naive O(n*log(m)) implementation, could be O(n)
impl <K: Ord, V: Eq> TreeMap<K, V>: Eq {
    pure fn eq(&self, other: &TreeMap<K, V>) -> bool {
        if self.len() != other.len() {
            return false
        }
        for self.each |x, y| {
            match other.find(x) {
                Some(z) => if z != y { return false },
                None => return false
            }
        }
        true
    }
    pure fn ne(&self, other: &TreeMap<K, V>) -> bool {
        !self.eq(other)
    }
}

impl <K: Ord, V> TreeMap<K, V> {
    /// Create an empty TreeMap
    static pure fn new() -> TreeMap<K, V> { TreeMap{root: None, length: 0} }

    /// Return the number of elements in the map
    pure fn len(&self) -> uint { self.length }

    /// Return true if the map contains no elements
    pure fn is_empty(&self) -> bool { self.root.is_none() }

    /// Return true if the map contains some elements
    pure fn is_not_empty(&self) -> bool { self.root.is_some() }

    /// Visit all key-value pairs in order
    pure fn each(&self, f: fn(&K, &V) -> bool) { each(&self.root, f) }

    /// Visit all keys in order
    pure fn each_key(&self, f: fn(&K) -> bool) { self.each(|k, _| f(k)) }

    /// Visit all values in order
    pure fn each_value(&self, f: fn(&V) -> bool) { self.each(|_, v| f(v)) }

    /// Visit all key-value pairs in reverse order
    pure fn each_reverse(&self, f: fn(&K, &V) -> bool) {
        each_reverse(&self.root, f);
    }

    /// Visit all keys in reverse order
    pure fn each_key_reverse(&self, f: fn(&K) -> bool) {
        self.each_reverse(|k, _| f(k))
    }

    /// Visit all values in reverse order
    pure fn each_value_reverse(&self, f: fn(&V) -> bool) {
        self.each_reverse(|_, v| f(v))
    }

    /// Return true if the map contains a value for the specified key
    pure fn contains_key(&self, key: &K) -> bool {
        self.find(key).is_some()
    }

    /// Return the value corresponding to the key in the map
    pure fn find(&self, key: &K) -> Option<&self/V> {
        let mut current: &self/Option<~TreeNode<K, V>> = &self.root;
        loop {
            match *current {
              Some(ref r) => {
                let r: &self/~TreeNode<K, V> = r; // FIXME: #3148
                if *key < r.key {
                    current = &r.left;
                } else if r.key < *key {
                    current = &r.right;
                } else {
                    return Some(&r.value);
                }
              }
              None => return None
            }
        }
    }

    /// Insert a key-value pair into the map. An existing value for a
    /// key is replaced by the new value. Return true if the key did
    /// not already exist in the map.
    fn insert(&mut self, key: K, value: V) -> bool {
        let ret = insert(&mut self.root, key, value);
        if ret { self.length += 1 }
        ret
    }

    /// Remove a key-value pair from the map. Return true if the key
    /// was present in the map, otherwise false.
    fn remove(&mut self, key: &K) -> bool {
        let ret = remove(&mut self.root, key);
        if ret { self.length -= 1 }
        ret
    }
}

pub struct TreeSet<T: Ord> {
    priv map: TreeMap<T, ()>
}

impl <T: Ord> TreeSet<T>: iter::BaseIter<T> {
    /// Visit all values in order
    pure fn each(&self, f: fn(&T) -> bool) { self.map.each_key(f) }
    pure fn size_hint(&self) -> Option<uint> { Some(self.len()) }
}

impl <T: Ord> TreeSet<T>: Eq {
    pure fn eq(&self, other: &TreeSet<T>) -> bool { self.map == other.map }
    pure fn ne(&self, other: &TreeSet<T>) -> bool { self.map != other.map }
}

impl <T: Ord> TreeSet<T> {
    /// Create an empty TreeSet
    static pure fn new() -> TreeSet<T> { TreeSet{map: TreeMap::new()} }

    /// Return the number of elements in the set
    pure fn len(&self) -> uint { self.map.len() }

    /// Return true if the set contains no elements
    pure fn is_empty(&self) -> bool { self.map.is_empty() }

    /// Return true if the set contains some elements
    pure fn is_not_empty(&self) -> bool { self.map.is_not_empty() }

    /// Visit all values in reverse order
    pure fn each_reverse(&self, f: fn(&T) -> bool) {
        self.map.each_key_reverse(f)
    }

    /// Return true if the set contains a value
    pure fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }

    /// Add a value to the set. Return true if the value was not
    /// already present in the set.
    fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) }

    /// Remove a value from the set. Return true if the value was
    /// present in the set.
    fn remove(&mut self, value: &T) -> bool { self.map.remove(value) }

    /// Return true if the set has no elements in common with `other`.
    /// This is equivalent to checking for an empty intersection.
    pure fn is_disjoint(&self, other: &TreeSet<T>) -> bool {
        // FIXME: this is a naive O(n*log(m)) implementation, could be O(n)
        !iter::any(self, |x| other.contains(x))
    }

    /// Check of the set is a subset of another
    pure fn is_subset(&self, other: &TreeSet<T>) -> bool {
        // FIXME: this is a naive O(n*log(m)) implementation, could be O(n)
        !iter::any(self, |x| !other.contains(x))
    }

    /// Check of the set is a superset of another
    pure fn is_superset(&self, other: &TreeSet<T>) -> bool {
        other.is_subset(self)
    }

    /// Visit the values (in-order) representing the difference
    pure fn difference(&self, _other: &TreeSet<T>,
                       _f: fn(&T) -> bool) {
        fail ~"not yet implemented" // TODO
    }

    /// Visit the values (in-order) representing the symmetric difference
    pure fn symmetric_difference(&self, _other: &TreeSet<T>,
                                 _f: fn(&T) -> bool) {
        fail ~"not yet implemented" // TODO
    }

    /// Visit the values (in-order) representing the intersection
    pure fn intersection(&self, other: &TreeSet<T>,
                         f: fn(&T) -> bool) {
        // FIXME: this is a naive O(n*log(m)) implementation, could be O(n)
        for self.each |x| {
            if other.contains(x) {
                if !f(x) { break }
            }
        }
    }

    /// Visit the values (in-order) representing the union
    pure fn union(&self, _other: &TreeSet<T>, _f: fn(&T) -> bool) -> TreeSet<T> {
        fail ~"not yet implemented" // TODO
    }
}

// Nodes keep track of their level in the tree, starting at 1 in the
// leaves and with a red child sharing the level of the parent.
struct TreeNode<K: Ord, V> {
    key: K,
    value: V,
    left: Option<~TreeNode<K, V>>,
    right: Option<~TreeNode<K, V>>,
    level: uint
}

impl <K: Ord, V> TreeNode<K, V> {
    #[inline(always)]
    static pure fn new(key: K, value: V) -> TreeNode<K, V> {
        TreeNode{key: key, value: value, left: None, right: None, level: 1}
    }
}

pure fn each<K: Ord, V>(node: &Option<~TreeNode<K, V>>,
                        f: fn(&K, &V) -> bool) {
    do node.map |x| {
        each(&x.left, f);
        if f(&x.key, &x.value) { each(&x.right, f) }
    };
}

pure fn each_reverse<K: Ord, V>(node: &Option<~TreeNode<K, V>>,
                                f: fn(&K, &V) -> bool) {
    do node.map |x| {
        each_reverse(&x.right, f);
        if f(&x.key, &x.value) { each_reverse(&x.left, f) }
    };
}

// Remove left horizontal link by rotating right
fn skew<K: Ord, V>(node: ~TreeNode<K, V>) -> ~TreeNode<K, V> {
    if node.left.map_default(false, |x| x.level == node.level) {
        let mut node = node;
        let mut save = node.left.swap_unwrap();
        node.left <-> save.right; // save.right now None
        save.right = Some(node);
        save
    } else {
        node // nothing to do
    }
}

// Remove dual horizontal link by rotating left and increasing level of
// the parent
fn split<K: Ord, V>(node: ~TreeNode<K, V>) -> ~TreeNode<K, V> {
    if node.right.map_default(false, |x| x.right.map_default(false, |y| y.level == node.level)) {
        let mut node = node;
        let mut save = node.right.swap_unwrap();
        node.right <-> save.left; // save.left now None
        save.left = Some(node);
        save.level += 1;
        save
    } else {
        node // nothing to do
    }
}

fn insert<K: Ord, V>(node: &mut Option<~TreeNode<K, V>>, key: K,
                     value: V) -> bool {
    if node.is_none() {
        *node = Some(~TreeNode::new(key, value));
        true
    } else {
        let mut save = node.swap_unwrap();
        if key < save.key {
            let inserted = insert(&mut save.left, key, value);
            *node = Some(split(skew(save))); // re-balance, if necessary
            inserted
        } else if save.key < key {
            let inserted = insert(&mut save.right, key, value);
            *node = Some(split(skew(save))); // re-balance, if necessary
            inserted
        } else {
            save.key = key;
            save.value = value;
            *node = Some(save);
            false
        }
    }
}

fn remove<K: Ord, V>(node: &mut Option<~TreeNode<K, V>>, key: &K) -> bool {
    fn heir_swap<K: Ord, V>(node: &mut TreeNode<K, V>,
                            child: &mut Option<~TreeNode<K, V>>) {
        // *could* be done without recursion, but it won't borrow check
        do child.mutate |child| {
            let mut child = child;
            if child.right.is_some() {
                heir_swap(node, &mut child.right);
            } else {
                node.key <-> child.key;
                node.value <-> child.value;
            }
            child
        }
    }

    if node.is_none() {
        return false // bottom of tree
    } else {
        let mut save = node.swap_unwrap();

        let removed = if save.key < *key {
            remove(&mut save.right, key)
        } else if *key < save.key {
            remove(&mut save.left, key)
        } else {
            if save.left.is_some() {
                if save.right.is_some() {
                    let mut left = save.left.swap_unwrap();
                    if left.right.is_some() {
                        heir_swap(save, &mut left.right);
                        save.left = Some(left);
                        remove(&mut save.left, key);
                    } else {
                        save.key <-> left.key;
                        save.value <-> left.value;
                        save.left = Some(left);
                        remove(&mut save.left, key);
                    }
                } else {
                    let mut rm = save.left.swap_unwrap();
                    save.key <-> rm.key;
                    save.value <-> rm.value;
                    save.level <-> rm.level; // FIXME: may not be needed
                    save.left <-> rm.left; // FIXME: may not be needed
                    save.right <-> rm.right; // FIXME: may not be needed
                }
            } else if save.right.is_some() {
                let mut rm = save.right.swap_unwrap();
                save.key <-> rm.key;
                save.value <-> rm.value;
                save.level <-> rm.level; // FIXME: may not be needed
                save.left <-> rm.left; // FIXME: may not be needed
                save.right <-> rm.right; // FIXME: may not be needed
            } else {
                return true // leaf
            }
            true
        };

        let left_level = save.left.map_default(0, |x| x.level);
        let right_level = save.right.map_default(0, |x| x.level);

        // re-balance, if necessary
        if left_level < save.level - 1 || right_level < save.level - 1 {
            save.level -= 1;

            if right_level > save.level {
                do save.right.mutate |x| {
                    let mut x = x; x.level = save.level; x
                }
            }

            save = skew(save);

            do save.right.mutate |right| {
                let mut right = skew(right);
                right.right.mutate(skew);
                right
            }
            save = split(save);
            save.right.mutate(split);
        }

        *node = Some(save);
        removed
    }
}

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

    #[test]
    fn find_empty() {
        let m = TreeMap::new::<int, int>(); assert m.find(&5) == None;
    }

    #[test]
    fn find_not_found() {
        let mut m = TreeMap::new();
        assert m.insert(1, 2);
        assert m.insert(5, 3);
        assert m.insert(9, 3);
        assert m.find(&2) == None;
    }

    #[test]
    fn insert_replace() {
        let mut m = TreeMap::new();
        assert m.insert(5, 2);
        assert m.insert(2, 9);
        assert !m.insert(2, 11);
        assert m.find(&2).unwrap() == &11;
    }

    #[test]
    fn u8_map() {
        let mut m = TreeMap::new();

        let k1 = str::to_bytes(~"foo");
        let k2 = str::to_bytes(~"bar");
        let v1 = str::to_bytes(~"baz");
        let v2 = str::to_bytes(~"foobar");

        m.insert(k1, v1);
        m.insert(k2, v2);

        assert m.find(&k2) == Some(&v2);
        assert m.find(&k1) == Some(&v1);
    }

    fn check_equal<K: Eq Ord, V: Eq>(ctrl: &[(K, V)], map: &TreeMap<K, V>) {
        assert ctrl.is_empty() == map.is_empty();
        assert ctrl.is_not_empty() == map.is_not_empty();
        for ctrl.each |x| {
            let &(k, v) = x;
            assert map.find(&k).unwrap() == &v
        }
        for map.each |map_k, map_v| {
            let mut found = false;
            for ctrl.each |x| {
                let &(ctrl_k, ctrl_v) = x;
                if *map_k == ctrl_k {
                    assert *map_v == ctrl_v;
                    found = true;
                    break;
                }
            }
            assert found;
        }
    }

    fn check_left<K: Ord, V>(node: &Option<~TreeNode<K, V>>, parent: &~TreeNode<K, V>) {
        match *node {
          Some(ref r) => {
            assert r.key < parent.key;
            assert r.level == parent.level - 1; // left is black
            check_left(&r.left, r);
            check_right(&r.right, r, false);
          }
          None => assert parent.level == 1 // parent is leaf
        }
    }

    fn check_right<K: Ord, V>(node: &Option<~TreeNode<K, V>>,
                              parent: &~TreeNode<K, V>, parent_red: bool) {
        match *node {
          Some(ref r) => {
            assert r.key > parent.key;
            let red = r.level == parent.level;
            if parent_red { assert !red } // no dual horizontal links
            assert red || r.level == parent.level - 1; // right is red or black
            check_left(&r.left, r);
            check_right(&r.right, r, red);
          }
          None => assert parent.level == 1 // parent is leaf
        }
    }

    fn check_structure<K: Ord, V>(map: &TreeMap<K, V>) {
        match map.root {
          Some(ref r) => {
            check_left(&r.left, r);
            check_right(&r.right, r, false);
          }
          None => ()
        }
    }

    #[test]
    fn test_rand_int() {
        let mut map = TreeMap::new::<int, int>();
        let mut ctrl = ~[];

        check_equal(ctrl, &map);
        assert map.find(&5).is_none();

        let rng = rand::seeded_rng(&~[42]);

        for 3.times {
            for 90.times {
                let k = rng.gen_int();
                let v = rng.gen_int();
                if !ctrl.contains(&(k, v)) {
                    assert map.insert(k, v);
                    ctrl.push((k, v));
                    check_structure(&map);
                    check_equal(ctrl, &map);
                }
            }

            for 30.times {
                let r = rng.gen_uint_range(0, ctrl.len());
                let (key, _) = vec::remove(&mut ctrl, r);
                assert map.remove(&key);
                check_structure(&map);
                check_equal(ctrl, &map);
            }
        }
    }

    #[test]
    fn test_len() {
        let mut m = TreeMap::new();
        assert m.insert(3, 6);
        assert m.len() == 1;
        assert m.insert(0, 0);
        assert m.len() == 2;
        assert m.insert(4, 8);
        assert m.len() == 3;
        assert m.remove(&3);
        assert m.len() == 2;
        assert !m.remove(&5);
        assert m.len() == 2;
        assert m.insert(2, 4);
        assert m.len() == 3;
        assert m.insert(1, 2);
        assert m.len() == 4;
    }

    #[test]
    fn test_each() {
        let mut m = TreeMap::new();

        assert m.insert(3, 6);
        assert m.insert(0, 0);
        assert m.insert(4, 8);
        assert m.insert(2, 4);
        assert m.insert(1, 2);

        let mut n = 0;
        for m.each |k, v| {
            assert *k == n;
            assert *v == n * 2;
            n += 1;
        }
    }

    #[test]
    fn test_each_reverse() {
        let mut m = TreeMap::new();

        assert m.insert(3, 6);
        assert m.insert(0, 0);
        assert m.insert(4, 8);
        assert m.insert(2, 4);
        assert m.insert(1, 2);

        let mut n = 4;
        for m.each_reverse |k, v| {
            assert *k == n;
            assert *v == n * 2;
            n -= 1;
        }
    }

    #[test]
    fn test_eq() {
        let mut a = TreeMap::new();
        let mut b = TreeMap::new();

        assert a == b;
        assert a.insert(0, 5);
        assert a != b;
        assert b.insert(0, 4);
        assert a != b;
        assert a.insert(5, 19);
        assert a != b;
        assert !b.insert(0, 5);
        assert a != b;
        assert b.insert(5, 19);
        assert a == b;
    }
}

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

    #[test]
    fn test_disjoint() {
        let mut xs = TreeSet::new();
        let mut ys = TreeSet::new();
        assert xs.is_disjoint(&ys);
        assert ys.is_disjoint(&xs);
        assert xs.insert(5);
        assert ys.insert(11);
        assert xs.is_disjoint(&ys);
        assert ys.is_disjoint(&xs);
        assert xs.insert(7);
        assert xs.insert(19);
        assert xs.insert(4);
        assert ys.insert(2);
        assert ys.insert(-11);
        assert xs.is_disjoint(&ys);
        assert ys.is_disjoint(&xs);
        assert ys.insert(7);
        assert !xs.is_disjoint(&ys);
        assert !ys.is_disjoint(&xs);
    }

    #[test]
    fn test_subset_and_superset() {
        let mut a = TreeSet::new();
        assert a.insert(0);
        assert a.insert(5);
        assert a.insert(11);
        assert a.insert(7);

        let mut b = TreeSet::new();
        assert b.insert(0);
        assert b.insert(7);
        assert b.insert(19);
        assert b.insert(250);
        assert b.insert(11);
        assert b.insert(200);

        assert !a.is_subset(&b);
        assert !a.is_superset(&b);
        assert !b.is_subset(&a);
        assert !b.is_superset(&a);

        assert b.insert(5);

        assert a.is_subset(&b);
        assert !a.is_superset(&b);
        assert !b.is_subset(&a);
        assert b.is_superset(&a);
    }

    #[test]
    fn test_each() {
        let mut m = TreeSet::new();

        assert m.insert(3);
        assert m.insert(0);
        assert m.insert(4);
        assert m.insert(2);
        assert m.insert(1);

        let mut n = 0;
        for m.each |x| {
            assert *x == n;
            n += 1
        }
    }

    #[test]
    fn test_each_reverse() {
        let mut m = TreeSet::new();

        assert m.insert(3);
        assert m.insert(0);
        assert m.insert(4);
        assert m.insert(2);
        assert m.insert(1);

        let mut n = 4;
        for m.each_reverse |x| {
            assert *x == n;
            n -= 1
        }
    }

    #[test]
    fn test_intersection() {
        let mut a = TreeSet::new();
        let mut b = TreeSet::new();

        a.insert(11);
        a.insert(1);
        a.insert(3);
        a.insert(77);
        a.insert(103);
        a.insert(5);
        a.insert(-5);

        b.insert(2);
        b.insert(11);
        b.insert(77);
        b.insert(-9);
        b.insert(-42);
        b.insert(5);
        b.insert(3);

        let mut i = 0;
        let expected = [3, 5, 11, 77];
        for a.intersection(&b) |x| {
            assert *x == expected[i];
            i += 1
        }
        assert i == expected.len();
    }
}
<|endoftext|>


<commit_before>use arrayvec::ArrayVec;
use std::collections::VecDeque;
use std::iter::IntoIterator;

use math::{self, FScalar};
use super::primitive::{Polygon, Polygonal, Primitive, Triangle, Quad};

// A type `F` constrained to `Fn(P, D) -> R` could be used here, but it would
// not be possible to name that type for anything but functions (not closures).
// Instead of a limited and somewhat redundant type `F`, just use `fn(P, D) ->
// R` for the member `f`.
pub struct Decompose
where
    D: Copy,
    R: IntoIterator<Item = Q>,
{
    input: I,
    output: VecDeque<Q>,
    parameter: D,
    f: fn(P, D) -> R,
}

impl Decompose
where
    D: Copy,
    R: IntoIterator<Item = Q>,
{
    pub(super) fn new(input: I, parameter: D, f: fn(P, D) -> R) -> Self {
        Decompose {
            input: input,
            output: VecDeque::new(),
            parameter: parameter,
            f: f,
        }
    }
}

impl Iterator for Decompose
where
    I: Iterator<Item = P>,
    D: Copy,
    R: IntoIterator<Item = Q>,
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(polygon) = self.output.pop_front() {
                return Some(polygon);
            }
            if let Some(polygon) = self.input.next() {
                self.output.extend((self.f)(polygon, self.parameter));
            }
            else {
                return None;
            }
        }
    }
}

pub trait Interpolate: math::Interpolate<FScalar> {}

impl<T> Interpolate for T
where
    T: math::Interpolate<FScalar>,
{
}

pub trait IntoSubdivisions: Polygonal
where
    Self::Point: Clone + Interpolate,
{
    fn into_subdivisions(self, n: usize) -> Vec<Self>;
}

pub trait IntoTetrahedrons: Polygonal
where
    Self::Point: Clone + Interpolate,
{
    fn into_tetrahedrons(self) -> ArrayVec<[Triangle<Self::Point>; 4]>;
}

impl<T> IntoSubdivisions for Triangle<T>
where
    T: Clone + Interpolate,
{
    fn into_subdivisions(self, n: usize) -> Vec<Self> {
        n_map_polygon(n, self, |triangle| {
            let Triangle { a, b, c } = triangle;
            let ac = a.midpoint(&c);
            vec![
                Triangle::new(b.clone(), ac.clone(), a),
                Triangle::new(c, ac, b),
            ]
        })
    }
}

impl<T> IntoSubdivisions for Quad<T>
where
    T: Clone + Interpolate,
{
    fn into_subdivisions(self, n: usize) -> Vec<Self> {
        n_map_polygon(n, self, |quad| {
            let Quad { a, b, c, d } = quad;
            let ab = a.midpoint(&b);
            let bc = b.midpoint(&c);
            let cd = c.midpoint(&d);
            let da = d.midpoint(&a);
            let ac = a.midpoint(&c); // Diagonal.
            vec![
                Quad::new(a, ab.clone(), ac.clone(), da.clone()),
                Quad::new(ab, b, bc.clone(), ac.clone()),
                Quad::new(ac.clone(), bc, c, cd.clone()),
                Quad::new(da, ac, cd, d),
            ]
        })
    }
}

impl<T> IntoTetrahedrons for Quad<T>
where
    T: Clone + Interpolate,
{
    fn into_tetrahedrons(self) -> ArrayVec<[Triangle<Self::Point>; 4]> {
        let Quad { a, b, c, d } = self;
        let ac = a.midpoint(&c); // Diagonal.
        ArrayVec::from(
            [
                Triangle::new(a.clone(), b.clone(), ac.clone()),
                Triangle::new(b, c.clone(), ac.clone()),
                Triangle::new(c, d.clone(), ac.clone()),
                Triangle::new(d, a, ac),
            ],
        )
    }
}

impl<T> IntoSubdivisions for Polygon<T>
where
    T: Clone + Interpolate,
{
    fn into_subdivisions(self, n: usize) -> Vec<Self> {
        match self {
            Polygon::Triangle(triangle) => {
                triangle
                    .into_subdivisions(n)
                    .into_iter()
                    .map(|triangle| triangle.into())
                    .collect()
            }
            Polygon::Quad(quad) => {
                quad.into_subdivisions(n)
                    .into_iter()
                    .map(|quad| quad.into())
                    .collect()
            }
        }
    }
}

pub trait Points
: Sized
where
    P: Primitive,
{
    fn points(self) -> Decompose<Self, P, P::Point, (), Vec
>;
}

impl Points
 for I
where
    I: Iterator<Item = P>,
    P: Primitive<Point = T>,
    T: Clone,
{
    fn points(self) -> Decompose<Self, P, P::Point, (), Vec
> {
        Decompose::new(self, (), into_points)
    }
}

pub trait Triangulate
: Sized
where
    P: Polygonal,
{
    #[allow(type_complexity)]
    fn triangulate(self) -> Decompose<Self, P, Triangle
, (), Vec<Triangle
>>;
}

impl Triangulate
 for I
where
    I: Iterator<Item = P>,
    P: Polygonal<Point = T>,
    T: Clone,
{
    #[allow(type_complexity)]
    fn triangulate(self) -> Decompose<Self, P, Triangle
, (), Vec<Triangle
>> {
        Decompose::new(self, (), into_triangles)
    }
}

pub trait Subdivide
: Sized
where
    P: Polygonal,
{
    fn subdivide(self, n: usize) -> Decompose<Self, P, P, usize, Vec
>;
}

impl Subdivide
 for I
where
    I: Iterator<Item = P>,
    P: IntoSubdivisions<Point = T>,
    T: Clone + Interpolate,
{
    fn subdivide(self, n: usize) -> Decompose<Self, P, P, usize, Vec
> {
        Decompose::new(self, n, into_subdivisions)
    }
}

pub trait Tetrahedrons<T>: Sized {
    fn tetrahedrons(self) -> Decompose<Self, Quad<T>, Triangle<T>, (), ArrayVec<[Triangle<T>; 4]>>;
}

impl Tetrahedrons<T> for I
where
    I: Iterator<Item = Quad<T>>,
    T: Clone + Interpolate,
{
    fn tetrahedrons(self) -> Decompose<Self, Quad<T>, Triangle<T>, (), ArrayVec<[Triangle<T>; 4]>> {
        Decompose::new(self, (), into_tetrahedrons)
    }
}

fn into_points
(primitive: P, _: ()) -> Vec<T>
where
    P: Primitive<Point = T>,
    T: Clone,
{
    primitive.into_points()
}

fn into_triangles
(polygon: P, _: ()) -> Vec<Triangle<T>>
where
    P: Polygonal<Point = T>,
    T: Clone,
{
    polygon.into_triangles()
}

fn into_subdivisions
(polygon: P, n: usize) -> Vec

where
    P: IntoSubdivisions<Point = T>,
    T: Clone + Interpolate,
{
    polygon.into_subdivisions(n)
}

fn into_tetrahedrons<T>(quad: Quad<T>, _: ()) -> ArrayVec<[Triangle<T>; 4]>
where
    T: Clone + Interpolate,
{
    quad.into_tetrahedrons()
}

fn n_map_polygon<T, P, F>(n: usize, polygon: P, f: F) -> Vec

where
    P: Polygonal<Point = T>,
    T: Clone,
    F: Fn(P) -> Vec
,
{
    let mut polygons = vec![polygon];
    for _ in 0..n {
        polygons = polygons
            .into_iter()
            .flat_map(|polygon| f(polygon))
            .collect();
    }
    polygons
}
<commit_msg>Remove unnecessary decompose mapping function.<commit_after>use arrayvec::ArrayVec;
use std::collections::VecDeque;
use std::iter::IntoIterator;

use math::{self, FScalar};
use super::primitive::{Polygon, Polygonal, Primitive, Triangle, Quad};

// A type `F` constrained to `Fn(P, D) -> R` could be used here, but it would
// not be possible to name that type for anything but functions (not closures).
// Instead of a limited and somewhat redundant type `F`, just use `fn(P, D) ->
// R` for the member `f`.
pub struct Decompose
where
    D: Copy,
    R: IntoIterator<Item = Q>,
{
    input: I,
    output: VecDeque<Q>,
    parameter: D,
    f: fn(P, D) -> R,
}

impl Decompose
where
    D: Copy,
    R: IntoIterator<Item = Q>,
{
    pub(super) fn new(input: I, parameter: D, f: fn(P, D) -> R) -> Self {
        Decompose {
            input: input,
            output: VecDeque::new(),
            parameter: parameter,
            f: f,
        }
    }
}

impl Iterator for Decompose
where
    I: Iterator<Item = P>,
    D: Copy,
    R: IntoIterator<Item = Q>,
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(polygon) = self.output.pop_front() {
                return Some(polygon);
            }
            if let Some(polygon) = self.input.next() {
                self.output.extend((self.f)(polygon, self.parameter));
            }
            else {
                return None;
            }
        }
    }
}

pub trait Interpolate: math::Interpolate<FScalar> {}

impl<T> Interpolate for T
where
    T: math::Interpolate<FScalar>,
{
}

pub trait IntoSubdivisions: Polygonal
where
    Self::Point: Clone + Interpolate,
{
    fn into_subdivisions(self, n: usize) -> Vec<Self>;
}

pub trait IntoTetrahedrons: Polygonal
where
    Self::Point: Clone + Interpolate,
{
    fn into_tetrahedrons(self) -> ArrayVec<[Triangle<Self::Point>; 4]>;
}

impl<T> IntoSubdivisions for Triangle<T>
where
    T: Clone + Interpolate,
{
    fn into_subdivisions(self, n: usize) -> Vec<Self> {
        n_map_polygon(n, self, |triangle| {
            let Triangle { a, b, c } = triangle;
            let ac = a.midpoint(&c);
            vec![
                Triangle::new(b.clone(), ac.clone(), a),
                Triangle::new(c, ac, b),
            ]
        })
    }
}

impl<T> IntoSubdivisions for Quad<T>
where
    T: Clone + Interpolate,
{
    fn into_subdivisions(self, n: usize) -> Vec<Self> {
        n_map_polygon(n, self, |quad| {
            let Quad { a, b, c, d } = quad;
            let ab = a.midpoint(&b);
            let bc = b.midpoint(&c);
            let cd = c.midpoint(&d);
            let da = d.midpoint(&a);
            let ac = a.midpoint(&c); // Diagonal.
            vec![
                Quad::new(a, ab.clone(), ac.clone(), da.clone()),
                Quad::new(ab, b, bc.clone(), ac.clone()),
                Quad::new(ac.clone(), bc, c, cd.clone()),
                Quad::new(da, ac, cd, d),
            ]
        })
    }
}

impl<T> IntoTetrahedrons for Quad<T>
where
    T: Clone + Interpolate,
{
    fn into_tetrahedrons(self) -> ArrayVec<[Triangle<Self::Point>; 4]> {
        let Quad { a, b, c, d } = self;
        let ac = a.midpoint(&c); // Diagonal.
        ArrayVec::from(
            [
                Triangle::new(a.clone(), b.clone(), ac.clone()),
                Triangle::new(b, c.clone(), ac.clone()),
                Triangle::new(c, d.clone(), ac.clone()),
                Triangle::new(d, a, ac),
            ],
        )
    }
}

impl<T> IntoSubdivisions for Polygon<T>
where
    T: Clone + Interpolate,
{
    fn into_subdivisions(self, n: usize) -> Vec<Self> {
        match self {
            Polygon::Triangle(triangle) => {
                triangle
                    .into_subdivisions(n)
                    .into_iter()
                    .map(|triangle| triangle.into())
                    .collect()
            }
            Polygon::Quad(quad) => {
                quad.into_subdivisions(n)
                    .into_iter()
                    .map(|quad| quad.into())
                    .collect()
            }
        }
    }
}

pub trait Points
: Sized
where
    P: Primitive,
{
    fn points(self) -> Decompose<Self, P, P::Point, (), Vec
>;
}

impl Points
 for I
where
    I: Iterator<Item = P>,
    P: Primitive<Point = T>,
    T: Clone,
{
    fn points(self) -> Decompose<Self, P, P::Point, (), Vec
> {
        Decompose::new(self, (), into_points)
    }
}

pub trait Triangulate
: Sized
where
    P: Polygonal,
{
    #[allow(type_complexity)]
    fn triangulate(self) -> Decompose<Self, P, Triangle
, (), Vec<Triangle
>>;
}

impl Triangulate
 for I
where
    I: Iterator<Item = P>,
    P: Polygonal<Point = T>,
    T: Clone,
{
    #[allow(type_complexity)]
    fn triangulate(self) -> Decompose<Self, P, Triangle
, (), Vec<Triangle
>> {
        Decompose::new(self, (), into_triangles)
    }
}

pub trait Subdivide
: Sized
where
    P: Polygonal,
{
    fn subdivide(self, n: usize) -> Decompose<Self, P, P, usize, Vec
>;
}

impl Subdivide
 for I
where
    I: Iterator<Item = P>,
    P: IntoSubdivisions<Point = T>,
    T: Clone + Interpolate,
{
    fn subdivide(self, n: usize) -> Decompose<Self, P, P, usize, Vec
> {
        Decompose::new(self, n, P::into_subdivisions)
    }
}

pub trait Tetrahedrons<T>: Sized {
    fn tetrahedrons(self) -> Decompose<Self, Quad<T>, Triangle<T>, (), ArrayVec<[Triangle<T>; 4]>>;
}

impl Tetrahedrons<T> for I
where
    I: Iterator<Item = Quad<T>>,
    T: Clone + Interpolate,
{
    fn tetrahedrons(self) -> Decompose<Self, Quad<T>, Triangle<T>, (), ArrayVec<[Triangle<T>; 4]>> {
        Decompose::new(self, (), into_tetrahedrons)
    }
}

fn into_points
(primitive: P, _: ()) -> Vec<T>
where
    P: Primitive<Point = T>,
    T: Clone,
{
    primitive.into_points()
}

fn into_triangles
(polygon: P, _: ()) -> Vec<Triangle<T>>
where
    P: Polygonal<Point = T>,
    T: Clone,
{
    polygon.into_triangles()
}

fn into_tetrahedrons<T>(quad: Quad<T>, _: ()) -> ArrayVec<[Triangle<T>; 4]>
where
    T: Clone + Interpolate,
{
    quad.into_tetrahedrons()
}

fn n_map_polygon<T, P, F>(n: usize, polygon: P, f: F) -> Vec

where
    P: Polygonal<Point = T>,
    T: Clone,
    F: Fn(P) -> Vec
,
{
    let mut polygons = vec![polygon];
    for _ in 0..n {
        polygons = polygons
            .into_iter()
            .flat_map(|polygon| f(polygon))
            .collect();
    }
    polygons
}
<|endoftext|>