<commit_before>use ndarray::*;
use ndarray_linalg::*;

#[test]
fn dgeev() {
    // https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/dgeev_ex.f.htm
    let a: Array2<f64> = arr2(&[
        [-1.01, 0.86, -4.60, 3.31, -4.81],
        [3.98, 0.53, -7.04, 5.29, 3.55],
        [3.30, 8.26, -3.89, 8.20, -1.51],
        [4.43, 4.96, -7.66, -7.33, 6.18],
        [7.31, -6.43, -6.16, 2.47, 5.58],
    ]);
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eig().unwrap();
    assert_close_l2!(
        &e,
        &arr1(&[
            c64::new(2.86, 10.76),
            c64::new(2.86, -10.76),
            c64::new(-0.69, 4.70),
            c64::new(-0.69, -4.70),
            c64::new(-10.46, 0.00)
        ]),
        1.0e-3
    );

    /*
    let answer = &arr2(&[[c64::new(  0.11,  0.17), c64::new(  0.11, -0.17), c64::new(  0.73,  0.00), c64::new(  0.73,  0.00), c64::new(  0.46,  0.00)],
                         [c64::new(  0.41, -0.26), c64::new(  0.41,  0.26), c64::new( -0.03, -0.02), c64::new( -0.03,  0.02), c64::new(  0.34,  0.00)],
                         [c64::new(  0.10, -0.51), c64::new(  0.10,  0.51), c64::new(  0.19, -0.29), c64::new(  0.19,  0.29), c64::new(  0.31,  0.00)],
                         [c64::new(  0.40, -0.09), c64::new(  0.40,  0.09), c64::new( -0.08, -0.08), c64::new( -0.08,  0.08), c64::new( -0.74,  0.00)],
                         [c64::new(  0.54,  0.00), c64::new(  0.54,  0.00), c64::new( -0.29, -0.49), c64::new( -0.29,  0.49), c64::new(  0.16,  0.00)]]);
    */

    let a_c: Array2<c64> = a.map(|f| c64::new(*f, 0.0));
    for (i, v) in vecs.axis_iter(Axis(1)).enumerate() {
        let av = a_c.dot(&v);
        let ev = v.mapv(|f| e[i] * f);
        assert_close_l2!(&av, &ev, 1.0e-7);
    }
}

#[test]
fn fgeev() {
    // https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/dgeev_ex.f.htm
    let a: Array2<f32> = arr2(&[
        [-1.01, 0.86, -4.60, 3.31, -4.81],
        [3.98, 0.53, -7.04, 5.29, 3.55],
        [3.30, 8.26, -3.89, 8.20, -1.51],
        [4.43, 4.96, -7.66, -7.33, 6.18],
        [7.31, -6.43, -6.16, 2.47, 5.58],
    ]);
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eig().unwrap();
    assert_close_l2!(
        &e,
        &arr1(&[
            c32::new(2.86, 10.76),
            c32::new(2.86, -10.76),
            c32::new(-0.69, 4.70),
            c32::new(-0.69, -4.70),
            c32::new(-10.46, 0.00)
        ]),
        1.0e-3
    );

    /*
    let answer = &arr2(&[[c32::new(  0.11,  0.17), c32::new(  0.11, -0.17), c32::new(  0.73,  0.00), c32::new(  0.73,  0.00), c32::new(  0.46,  0.00)],
                         [c32::new(  0.41, -0.26), c32::new(  0.41,  0.26), c32::new( -0.03, -0.02), c32::new( -0.03,  0.02), c32::new(  0.34,  0.00)],
                         [c32::new(  0.10, -0.51), c32::new(  0.10,  0.51), c32::new(  0.19, -0.29), c32::new(  0.19,  0.29), c32::new(  0.31,  0.00)],
                         [c32::new(  0.40, -0.09), c32::new(  0.40,  0.09), c32::new( -0.08, -0.08), c32::new( -0.08,  0.08), c32::new( -0.74,  0.00)],
                         [c32::new(  0.54,  0.00), c32::new(  0.54,  0.00), c32::new( -0.29, -0.49), c32::new( -0.29,  0.49), c32::new(  0.16,  0.00)]]);
    */

    let a_c: Array2<c32> = a.map(|f| c32::new(*f, 0.0));
    for (i, v) in vecs.axis_iter(Axis(1)).enumerate() {
        let av = a_c.dot(&v);
        let ev = v.mapv(|f| e[i] * f);
        assert_close_l2!(&av, &ev, 1.0e-5);
    }
}

#[test]
fn zgeev() {
    // https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/zgeev_ex.f.htm
    let a: Array2<c64> = arr2(&[
        [
            c64::new(-3.84, 2.25),
            c64::new(-8.94, -4.75),
            c64::new(8.95, -6.53),
            c64::new(-9.87, 4.82),
        ],
        [
            c64::new(-0.66, 0.83),
            c64::new(-4.40, -3.82),
            c64::new(-3.50, -4.26),
            c64::new(-3.15, 7.36),
        ],
        [
            c64::new(-3.99, -4.73),
            c64::new(-5.88, -6.60),
            c64::new(-3.36, -0.40),
            c64::new(-0.75, 5.23),
        ],
        [
            c64::new(7.74, 4.18),
            c64::new(3.66, -7.53),
            c64::new(2.58, 3.60),
            c64::new(4.59, 5.41),
        ],
    ]);
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eig().unwrap();
    assert_close_l2!(
        &e,
        &arr1(&[
            c64::new(-9.43, -12.98),
            c64::new(-3.44, 12.69),
            c64::new(0.11, -3.40),
            c64::new(5.76, 7.13)
        ]),
        1.0e-3
    );

    /*
    let answer = &arr2(&[[c64::new(  0.43,  0.33), c64::new(  0.83,  0.00), c64::new(  0.60,  0.00), c64::new( -0.31,  0.03)],
                         [c64::new(  0.51, -0.03), c64::new(  0.08, -0.25), c64::new( -0.40, -0.20), c64::new(  0.04,  0.34)],
                         [c64::new(  0.62,  0.00), c64::new( -0.25,  0.28), c64::new( -0.09, -0.48), c64::new(  0.36,  0.06)],
                         [c64::new( -0.23,  0.11), c64::new( -0.10, -0.32), c64::new( -0.43,  0.13), c64::new(  0.81,  0.00)]]);
    */

    for (i, v) in vecs.axis_iter(Axis(1)).enumerate() {
        let av = a.dot(&v);
        let ev = v.mapv(|f| e[i] * f);
        assert_close_l2!(&av, &ev, 1.0e-7);
    }
}

#[test]
fn cgeev() {
    // https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/zgeev_ex.f.htm
    let a: Array2<c32> = arr2(&[
        [
            c32::new(-3.84, 2.25),
            c32::new(-8.94, -4.75),
            c32::new(8.95, -6.53),
            c32::new(-9.87, 4.82),
        ],
        [
            c32::new(-0.66, 0.83),
            c32::new(-4.40, -3.82),
            c32::new(-3.50, -4.26),
            c32::new(-3.15, 7.36),
        ],
        [
            c32::new(-3.99, -4.73),
            c32::new(-5.88, -6.60),
            c32::new(-3.36, -0.40),
            c32::new(-0.75, 5.23),
        ],
        [
            c32::new(7.74, 4.18),
            c32::new(3.66, -7.53),
            c32::new(2.58, 3.60),
            c32::new(4.59, 5.41),
        ],
    ]);
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eig().unwrap();
    assert_close_l2!(
        &e,
        &arr1(&[
            c32::new(-9.43, -12.98),
            c32::new(-3.44, 12.69),
            c32::new(0.11, -3.40),
            c32::new(5.76, 7.13)
        ]),
        1.0e-3
    );

    /*
    let answer = &arr2(&[[c32::new(  0.43,  0.33), c32::new(  0.83,  0.00), c32::new(  0.60,  0.00), c32::new( -0.31,  0.03)],
                         [c32::new(  0.51, -0.03), c32::new(  0.08, -0.25), c32::new( -0.40, -0.20), c32::new(  0.04,  0.34)],
                         [c32::new(  0.62,  0.00), c32::new( -0.25,  0.28), c32::new( -0.09, -0.48), c32::new(  0.36,  0.06)],
                         [c32::new( -0.23,  0.11), c32::new( -0.10, -0.32), c32::new( -0.43,  0.13), c32::new(  0.81,  0.00)]]);
    */

    for (i, v) in vecs.axis_iter(Axis(1)).enumerate() {
        let av = a.dot(&v);
        let ev = v.mapv(|f| e[i] * f);
        assert_close_l2!(&av, &ev, 1.0e-5);
    }
}
<commit_msg>Split eigenvalue and eigenvector tests<commit_after>use ndarray::*;
use ndarray_linalg::*;

// Test Av_i = e_i v_i for i = 0..n
fn test_eig<T: Scalar>(a: Array2<T>, eigs: Array1<T::Complex>, vecs: Array2<T::Complex>)
where
    T::Complex: Lapack,
{
    println!("a\n{:+.4}", &a);
    println!("eigs\n{:+.4}", &eigs);
    println!("vec\n{:+.4}", &vecs);
    let a: Array2<T::Complex> = a.map(|v| v.as_c());
    for (&e, v) in eigs.iter().zip(vecs.axis_iter(Axis(1))) {
        let av = a.dot(&v);
        let ev = v.mapv(|val| val * e);
        println!("av = {:+.4}", &av);
        println!("ev = {:+.4}", &ev);
        assert_close_l2!(&av, &ev, T::real(1e-3));
    }
}

// Test case for real Eigenvalue problem
//
//  -1.01   0.86  -4.60   3.31  -4.81
//   3.98   0.53  -7.04   5.29   3.55
//   3.30   8.26  -3.89   8.20  -1.51
//   4.43   4.96  -7.66  -7.33   6.18
//   7.31  -6.43  -6.16   2.47   5.58
//
// Eigenvalues
// (  2.86, 10.76) (  2.86,-10.76) ( -0.69,  4.70) ( -0.69, -4.70) -10.46
//
// Left eigenvectors
// (  0.04,  0.29) (  0.04, -0.29) ( -0.13, -0.33) ( -0.13,  0.33)   0.04
// (  0.62,  0.00) (  0.62,  0.00) (  0.69,  0.00) (  0.69,  0.00)   0.56
// ( -0.04, -0.58) ( -0.04,  0.58) ( -0.39, -0.07) ( -0.39,  0.07)  -0.13
// (  0.28,  0.01) (  0.28, -0.01) ( -0.02, -0.19) ( -0.02,  0.19)  -0.80
// ( -0.04,  0.34) ( -0.04, -0.34) ( -0.40,  0.22) ( -0.40, -0.22)   0.18
//
// Right eigenvectors
// (  0.11,  0.17) (  0.11, -0.17) (  0.73,  0.00) (  0.73,  0.00)   0.46
// (  0.41, -0.26) (  0.41,  0.26) ( -0.03, -0.02) ( -0.03,  0.02)   0.34
// (  0.10, -0.51) (  0.10,  0.51) (  0.19, -0.29) (  0.19,  0.29)   0.31
// (  0.40, -0.09) (  0.40,  0.09) ( -0.08, -0.08) ( -0.08,  0.08)  -0.74
// (  0.54,  0.00) (  0.54,  0.00) ( -0.29, -0.49) ( -0.29,  0.49)   0.16
//
// - https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/dgeev_ex.f.htm
//
fn test_matrix_real<T: Scalar>() -> Array2<T::Real> {
    array![
        [
            T::real(-1.01),
            T::real(0.86),
            T::real(-4.60),
            T::real(3.31),
            T::real(-4.81)
        ],
        [
            T::real(3.98),
            T::real(0.53),
            T::real(-7.04),
            T::real(5.29),
            T::real(3.55)
        ],
        [
            T::real(3.30),
            T::real(8.26),
            T::real(-3.89),
            T::real(8.20),
            T::real(-1.51)
        ],
        [
            T::real(4.43),
            T::real(4.96),
            T::real(-7.66),
            T::real(-7.33),
            T::real(6.18)
        ],
        [
            T::real(7.31),
            T::real(-6.43),
            T::real(-6.16),
            T::real(2.47),
            T::real(5.58)
        ],
    ]
}

fn test_matrix_real_t<T: Scalar>() -> Array2<T::Real> {
    test_matrix_real::<T>().t().permuted_axes([1, 0]).to_owned()
}

fn answer_eig_real<T: Scalar>() -> Array1<T::Complex> {
    array![
        T::complex(2.86, 10.76),
        T::complex(2.86, -10.76),
        T::complex(-0.69, 4.70),
        T::complex(-0.69, -4.70),
        T::complex(-10.46, 0.00),
    ]
}

// Test case for {c,z}geev
//
// ( -3.84,  2.25) ( -8.94, -4.75) (  8.95, -6.53) ( -9.87,  4.82)
// ( -0.66,  0.83) ( -4.40, -3.82) ( -3.50, -4.26) ( -3.15,  7.36)
// ( -3.99, -4.73) ( -5.88, -6.60) ( -3.36, -0.40) ( -0.75,  5.23)
// (  7.74,  4.18) (  3.66, -7.53) (  2.58,  3.60) (  4.59,  5.41)
//
// Eigenvalues
// ( -9.43,-12.98) ( -3.44, 12.69) (  0.11, -3.40) (  5.76,  7.13)
//
// Left eigenvectors
// (  0.24, -0.18) (  0.61,  0.00) ( -0.18, -0.33) (  0.28,  0.09)
// (  0.79,  0.00) ( -0.05, -0.27) (  0.82,  0.00) ( -0.55,  0.16)
// (  0.22, -0.27) ( -0.21,  0.53) ( -0.37,  0.15) (  0.45,  0.09)
// ( -0.02,  0.41) (  0.40, -0.24) (  0.06,  0.12) (  0.62,  0.00)
//
// Right eigenvectors
// (  0.43,  0.33) (  0.83,  0.00) (  0.60,  0.00) ( -0.31,  0.03)
// (  0.51, -0.03) (  0.08, -0.25) ( -0.40, -0.20) (  0.04,  0.34)
// (  0.62,  0.00) ( -0.25,  0.28) ( -0.09, -0.48) (  0.36,  0.06)
// ( -0.23,  0.11) ( -0.10, -0.32) ( -0.43,  0.13) (  0.81,  0.00)
//
// - https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/zgeev_ex.f.htm
//
fn test_matrix_complex<T: Scalar>() -> Array2<T::Complex> {
    array![
        [
            T::complex(-3.84, 2.25),
            T::complex(-8.94, -4.75),
            T::complex(8.95, -6.53),
            T::complex(-9.87, 4.82)
        ],
        [
            T::complex(-0.66, 0.83),
            T::complex(-4.40, -3.82),
            T::complex(-3.50, -4.26),
            T::complex(-3.15, 7.36)
        ],
        [
            T::complex(-3.99, -4.73),
            T::complex(-5.88, -6.60),
            T::complex(-3.36, -0.40),
            T::complex(-0.75, 5.23)
        ],
        [
            T::complex(7.74, 4.18),
            T::complex(3.66, -7.53),
            T::complex(2.58, 3.60),
            T::complex(4.59, 5.41)
        ]
    ]
}

fn test_matrix_complex_t<T: Scalar>() -> Array2<T::Complex> {
    test_matrix_complex::<T>()
        .t()
        .permuted_axes([1, 0])
        .to_owned()
}

fn answer_eig_complex<T: Scalar>() -> Array1<T::Complex> {
    array![
        T::complex(-9.43, -12.98),
        T::complex(-3.44, 12.69),
        T::complex(0.11, -3.40),
        T::complex(5.76, 7.13)
    ]
}

// re-evaluated eigenvalues in f64 accuracy
fn answer_eigvectors_complex<T: Scalar>() -> Array2<T::Complex> {
    array![
        [
            T::complex(0.4308565200776108, 0.32681273781262143),
            T::complex(0.8256820507672813, 0.),
            T::complex(0.5983959785539453, 0.),
            T::complex(-0.30543190348437826, 0.03333164861799901)
        ],
        [
            T::complex(0.5087414602970965, -0.02883342170692809),
            T::complex(0.07502916788141115, -0.2487285045091665),
            T::complex(-0.40047616275207687, -0.2014492227625603),
            T::complex(0.03978282815783273, 0.34450765221546126)
        ],
        [
            T::complex(0.6198496527657755, 0.),
            T::complex(-0.24575578997801528, 0.27887240221169646),
            T::complex(-0.09008001907594984, -0.4752646215391732),
            T::complex(0.3583254365159844, 0.06064506988524665)
        ],
        [
            T::complex(-0.22692824331926856, 0.11043927846403584),
            T::complex(-0.10343406372814358, -0.3192014653632327),
            T::complex(-0.43484029549540404, 0.13372491785816037),
            T::complex(0.8082432893178352, 0.)
        ]
    ]
}

macro_rules! impl_test_real {
    ($real:ty) => {
        paste::item! {
            #[test]
            fn [<$real _eigvals >]() {
                let a = test_matrix_real::<$real>();
                let (e, _vecs) = a.eig().unwrap();
                assert_close_l2!(&e, &answer_eig_real::<$real>(), 1.0e-3);
            }

            #[test]
            fn [<$real _eigvals_t>]() {
                let a = test_matrix_real_t::<$real>();
                let (e, _vecs) = a.eig().unwrap();
                assert_close_l2!(&e, &answer_eig_real::<$real>(), 1.0e-3);
            }

            #[test]
            fn [<$real _eig>]() {
                let a = test_matrix_real::<$real>();
                let (e, vecs) = a.eig().unwrap();
                test_eig(a, e, vecs);
            }

            #[test]
            fn [<$real _eig_t>]() {
                let a = test_matrix_real_t::<$real>();
                let (e, vecs) = a.eig().unwrap();
                test_eig(a, e, vecs);
            }

        } // paste::item!
    };
}

impl_test_real!(f32);
impl_test_real!(f64);

macro_rules! impl_test_complex {
    ($complex:ty) => {
        paste::item! {
            #[test]
            fn [<$complex _eigvals >]() {
                let a = test_matrix_complex::<$complex>();
                let (e, _vecs) = a.eig().unwrap();
                assert_close_l2!(&e, &answer_eig_complex::<$complex>(), 1.0e-3);
            }

            #[test]
            fn [<$complex _eigvals_t>]() {
                let a = test_matrix_complex_t::<$complex>();
                let (e, _vecs) = a.eig().unwrap();
                assert_close_l2!(&e, &answer_eig_complex::<$complex>(), 1.0e-3);
            }

            #[test]
            fn [<$complex _eigvector>]() {
                let a = test_matrix_complex::<$complex>();
                let (_e, vecs) = a.eig().unwrap();
                assert_close_l2!(&vecs, &answer_eigvectors_complex::<$complex>(), 1.0e-3);
            }

            #[test]
            fn [<$complex _eigvector_t>]() {
                let a = test_matrix_complex_t::<$complex>();
                let (_e, vecs) = a.eig().unwrap();
                assert_close_l2!(&vecs, &answer_eigvectors_complex::<$complex>(), 1.0e-3);
            }

            #[test]
            fn [<$complex _eig>]() {
                let a = test_matrix_complex::<$complex>();
                let (e, vecs) = a.eig().unwrap();
                test_eig(a, e, vecs);
            }

            #[test]
            fn [<$complex _eig_t>]() {
                let a = test_matrix_complex_t::<$complex>();
                let (e, vecs) = a.eig().unwrap();
                test_eig(a, e, vecs);
            }
        } // paste::item!
    };
}

impl_test_complex!(c32);
impl_test_complex!(c64);
<|endoftext|>


<commit_before>use std::ptr;
use std::os::unix::io::RawFd;
use std::cmp;
use std::io::{
    Result,
    Error,
};

use libc;
use time::Duration;
use event::{
    EventSet,
    self,
};

mod ffi {
    use std::mem;
    use std::os::unix::io::RawFd;

    use libc;

    const FD_SETSIZE: usize = 1024;

    // This is a hack until there is some way to get the size of a type at compile time.
    // This also assumes the size of a `c_long` is the size of the target's pointer, which is from
    // what I can tell, true. (With the glaring exception of windows, but we don't target them).
    #[cfg(target_pointer_width = "32")]
    const NFD_BITS: usize = 32;
    #[cfg(target_pointer_width = "64")]
    const NFD_BITS: usize = 64;

    #[repr(C)]
    type fd_mask = libc::c_long;

    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    #[repr(C)]
    pub struct fd_set {
        fds_bits: [fd_mask; (FD_SETSIZE / NFD_BITS)],
    }

    fn get_elt(fd: RawFd) -> usize {
        fd as usize / NFD_BITS
    }

    fn get_mask(fd: RawFd) -> fd_mask {
        (1usize << (fd as usize % NFD_BITS)) as fd_mask
    }

    impl fd_set {
        // Creates a new `fd_set`.
        pub fn new() -> fd_set {
            unsafe {
                mem::zeroed()
            }
        }

        pub fn set(&mut self, fd: RawFd) {
            self.fds_bits[get_elt(fd)] |= get_mask(fd);
        }

        pub fn unset(&mut self, fd: RawFd) {
            self.fds_bits[get_elt(fd)] &= !get_mask(fd);
        }

        pub fn is_set(&self, fd: RawFd) -> bool {
            (self.fds_bits[get_elt(fd)] & get_mask(fd)) != 0
        }

        pub fn find_max(&self, prev_max: RawFd) -> RawFd {
            let mut idx = get_elt(prev_max);
            for elt in self.fds_bits[..(idx + 1)].iter().rev() {
                if *elt == 0 {
                    idx -= 1;
                    continue;
                } else {
                    let zeros = elt.leading_zeros() as usize;
                    let shift = NFD_BITS - (zeros + 1);

                    let new_max = (idx * NFD_BITS) + shift;

                    return new_max as RawFd;
                }
            }
            0
        }
    }

    extern {
        pub fn select(nfds: libc::c_int,
                      readfds: *mut fd_set,
                      writefds: *mut fd_set,
                      exceptfds: *mut fd_set,
                      timeout: *mut libc::timeval) -> libc::c_int;

    }
}

fn select(nfds: RawFd,
          rset: &mut ffi::fd_set,
          wset: &mut ffi::fd_set,
          timeout: Option<Duration>) -> Result<usize>
{
    let tv = if let Some(dur) = timeout {
        let sec = dur.num_seconds() as libc::time_t;
        let usec = (dur - Duration::seconds(sec))
            .num_microseconds().unwrap() as libc::suseconds_t;

        &mut libc::timeval {
            tv_sec: sec,
            tv_usec: usec,
        } as *mut libc::timeval
    } else {
        ptr::null_mut()
    };

    let res = unsafe {
        ffi::select(nfds, rset, wset, ptr::null_mut(), tv)
    };

    if res == -1 {
        Err(Error::last_os_error())
    } else {
        Ok(res as usize)
    }
}

#[derive(Debug)]
pub struct Selector {
    maxfd: RawFd,

    rfds: ffi::fd_set,
    wfds: ffi::fd_set,

    // Copies of above as `select` will modify the `fd_set`s.
    _rfds: ffi::fd_set,
    _wfds: ffi::fd_set,
}

impl Selector {
    pub fn new() -> Result<Selector> {
        Ok(Selector {
            maxfd: 0,
            rfds: ffi::fd_set::new(),
            wfds: ffi::fd_set::new(),
            _rfds: ffi::fd_set::new(),
            _wfds: ffi::fd_set::new(),
        })
    }

    pub fn poll(&mut self) -> Result<IterFired> {
        self._rfds = self.rfds.clone();
        self._wfds = self.wfds.clone();

        try!(select(self.maxfd + 1, &mut self._rfds, &mut self._wfds, None));

        Ok(IterFired {
            maxfd: self.maxfd,
            curfd: 0,
            rfds: &self._rfds,
            wfds: &self._wfds,
        })
    }

    pub fn poll_timeout(&mut self, timeout: Duration) -> Result<IterFired> {
        self._rfds = self.rfds.clone();
        self._wfds = self.wfds.clone();

        try!(select(self.maxfd + 1, &mut self._rfds, &mut self._wfds, Some(timeout)));

        Ok(IterFired {
            maxfd: self.maxfd,
            curfd: 0,
            rfds: &self._rfds,
            wfds: &self._wfds,
        })
    }

    pub fn register(&mut self, fd: RawFd, evset: EventSet) -> Result<()> {
        if evset.is_readable() {
            self.rfds.set(fd);
            self.maxfd = cmp::max(fd, self.maxfd);
        }
        if evset.is_writable() {
            self.wfds.set(fd);
            self.maxfd = cmp::max(fd, self.maxfd);
        }

        Ok(())
    }

    pub fn reregister(&mut self, fd: RawFd, evset: EventSet) -> Result<()> {
        if evset.intersects(event::READABLE | event::WRITABLE) {
            self.register(fd, evset)
        } else {
            self.deregister(fd)
        }
    }

    pub fn deregister(&mut self, fd: RawFd) -> Result<()> {
        self.rfds.unset(fd);
        self.wfds.unset(fd);

        if fd == self.maxfd {
            self.maxfd = cmp::max(self.rfds.find_max(fd), self.wfds.find_max(fd));
        }

        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Fired {
    fd: RawFd,
    evset: EventSet,
}

impl Fired {
    pub fn fd(&self) -> RawFd {
        self.fd
    }

    pub fn evset(&self) -> EventSet {
        self.evset
    }
}

#[derive(Debug)]
pub struct IterFired<'a> {
    maxfd: RawFd,
    curfd: RawFd,
    rfds: &'a ffi::fd_set,
    wfds: &'a ffi::fd_set,
}

impl<'a> Iterator for IterFired<'a> {
    type Item = Fired;

    fn next(&mut self) -> Option<Fired> {
        while self.curfd <= self.maxfd {
            let is_read = self.rfds.is_set(self.curfd);
            let is_write = self.wfds.is_set(self.curfd);

            if !is_read && !is_write {
                self.curfd += 1;
                continue;
            } else {
                let mut evset = EventSet::empty();

                if is_read {
                    evset.insert(event::READABLE);
                }
                if is_write {
                    evset.insert(event::WRITABLE);
                }

                let fired = Fired {
                    fd: self.curfd,
                    evset: evset,
                };

                self.curfd += 1;
                return Some(fired);
            }
        }
        None
    }
}
<commit_msg>fix overflow in fd_set::find_max when the set is empty<commit_after>use std::ptr;
use std::os::unix::io::RawFd;
use std::cmp;
use std::io::{
    Result,
    Error,
};

use libc;
use time::Duration;
use event::{
    EventSet,
    self,
};

mod ffi {
    use std::mem;
    use std::os::unix::io::RawFd;

    use libc;

    const FD_SETSIZE: usize = 1024;

    // This is a hack until there is some way to get the size of a type at compile time.
    // This also assumes the size of a `c_long` is the size of the target's pointer, which is from
    // what I can tell, true. (With the glaring exception of windows, but we don't target them).
    #[cfg(target_pointer_width = "32")]
    const NFD_BITS: usize = 32;
    #[cfg(target_pointer_width = "64")]
    const NFD_BITS: usize = 64;

    #[repr(C)]
    type fd_mask = libc::c_long;

    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    #[repr(C)]
    pub struct fd_set {
        fds_bits: [fd_mask; (FD_SETSIZE / NFD_BITS)],
    }

    fn get_elt(fd: RawFd) -> usize {
        fd as usize / NFD_BITS
    }

    fn get_mask(fd: RawFd) -> fd_mask {
        (1usize << (fd as usize % NFD_BITS)) as fd_mask
    }

    impl fd_set {
        // Creates a new `fd_set`.
        pub fn new() -> fd_set {
            unsafe {
                mem::zeroed()
            }
        }

        pub fn set(&mut self, fd: RawFd) {
            self.fds_bits[get_elt(fd)] |= get_mask(fd);
        }

        pub fn unset(&mut self, fd: RawFd) {
            self.fds_bits[get_elt(fd)] &= !get_mask(fd);
        }

        pub fn is_set(&self, fd: RawFd) -> bool {
            (self.fds_bits[get_elt(fd)] & get_mask(fd)) != 0
        }

        pub fn find_max(&self, prev_max: RawFd) -> RawFd {
            let max_idx = get_elt(prev_max);
            for (idx, &elt) in self.fds_bits[..(max_idx + 1)].iter().enumerate().rev() {
                if elt != 0 {
                    let zeros = elt.leading_zeros() as usize;
                    let shift = NFD_BITS - (zeros + 1);

                    let new_max = (idx * NFD_BITS) + shift;

                    return new_max as RawFd;
                }
            }
            0
        }
    }

    extern {
        pub fn select(nfds: libc::c_int,
                      readfds: *mut fd_set,
                      writefds: *mut fd_set,
                      exceptfds: *mut fd_set,
                      timeout: *mut libc::timeval) -> libc::c_int;

    }
}

fn select(nfds: RawFd,
          rset: &mut ffi::fd_set,
          wset: &mut ffi::fd_set,
          timeout: Option<Duration>) -> Result<usize>
{
    let tv = if let Some(dur) = timeout {
        let sec = dur.num_seconds() as libc::time_t;
        let usec = (dur - Duration::seconds(sec))
            .num_microseconds().unwrap() as libc::suseconds_t;

        &mut libc::timeval {
            tv_sec: sec,
            tv_usec: usec,
        } as *mut libc::timeval
    } else {
        ptr::null_mut()
    };

    let res = unsafe {
        ffi::select(nfds, rset, wset, ptr::null_mut(), tv)
    };

    if res == -1 {
        Err(Error::last_os_error())
    } else {
        Ok(res as usize)
    }
}

#[derive(Debug)]
pub struct Selector {
    maxfd: RawFd,

    rfds: ffi::fd_set,
    wfds: ffi::fd_set,

    // Copies of above as `select` will modify the `fd_set`s.
    _rfds: ffi::fd_set,
    _wfds: ffi::fd_set,
}

impl Selector {
    pub fn new() -> Result<Selector> {
        Ok(Selector {
            maxfd: 0,
            rfds: ffi::fd_set::new(),
            wfds: ffi::fd_set::new(),
            _rfds: ffi::fd_set::new(),
            _wfds: ffi::fd_set::new(),
        })
    }

    pub fn poll(&mut self) -> Result<IterFired> {
        self._rfds = self.rfds.clone();
        self._wfds = self.wfds.clone();

        try!(select(self.maxfd + 1, &mut self._rfds, &mut self._wfds, None));

        Ok(IterFired {
            maxfd: self.maxfd,
            curfd: 0,
            rfds: &self._rfds,
            wfds: &self._wfds,
        })
    }

    pub fn poll_timeout(&mut self, timeout: Duration) -> Result<IterFired> {
        self._rfds = self.rfds.clone();
        self._wfds = self.wfds.clone();

        try!(select(self.maxfd + 1, &mut self._rfds, &mut self._wfds, Some(timeout)));

        Ok(IterFired {
            maxfd: self.maxfd,
            curfd: 0,
            rfds: &self._rfds,
            wfds: &self._wfds,
        })
    }

    pub fn register(&mut self, fd: RawFd, evset: EventSet) -> Result<()> {
        if evset.is_readable() {
            self.rfds.set(fd);
            self.maxfd = cmp::max(fd, self.maxfd);
        }
        if evset.is_writable() {
            self.wfds.set(fd);
            self.maxfd = cmp::max(fd, self.maxfd);
        }

        Ok(())
    }

    pub fn reregister(&mut self, fd: RawFd, evset: EventSet) -> Result<()> {
        if evset.intersects(event::READABLE | event::WRITABLE) {
            self.register(fd, evset)
        } else {
            self.deregister(fd)
        }
    }

    pub fn deregister(&mut self, fd: RawFd) -> Result<()> {
        self.rfds.unset(fd);
        self.wfds.unset(fd);

        if fd == self.maxfd {
            self.maxfd = cmp::max(self.rfds.find_max(fd), self.wfds.find_max(fd));
        }

        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Fired {
    fd: RawFd,
    evset: EventSet,
}

impl Fired {
    pub fn fd(&self) -> RawFd {
        self.fd
    }

    pub fn evset(&self) -> EventSet {
        self.evset
    }
}

#[derive(Debug)]
pub struct IterFired<'a> {
    maxfd: RawFd,
    curfd: RawFd,
    rfds: &'a ffi::fd_set,
    wfds: &'a ffi::fd_set,
}

impl<'a> Iterator for IterFired<'a> {
    type Item = Fired;

    fn next(&mut self) -> Option<Fired> {
        while self.curfd <= self.maxfd {
            let is_read = self.rfds.is_set(self.curfd);
            let is_write = self.wfds.is_set(self.curfd);

            if !is_read && !is_write {
                self.curfd += 1;
                continue;
            } else {
                let mut evset = EventSet::empty();

                if is_read {
                    evset.insert(event::READABLE);
                }
                if is_write {
                    evset.insert(event::WRITABLE);
                }

                let fired = Fired {
                    fd: self.curfd,
                    evset: evset,
                };

                self.curfd += 1;
                return Some(fired);
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>use std::error;
use std::process;
use std::fmt;
use std::io;
use std::io::{Read, Write};
use std::string::FromUtf8Error;

use hyper::status::StatusCode;
use hyper::header::ContentType;

use ini::ini;
use clap;
use hyper;
use serde_json;
use url;
use walkdir;
use zip;
use sourcemap;

pub type CliResult<T> = Result<T, CliError>;

#[derive(Debug)]
pub struct CliError {
    repr: CliErrorRepr,
}

#[derive(Debug)]
enum CliErrorRepr {
    ClapError(clap::Error),
    HyperResponse(StatusCode, String),
    BasicError(String),
}

#[derive(Debug, Deserialize)]
struct ErrorInfo {
    detail: Option<String>,
}

macro_rules! basic_error {
    ($ty:ty, $msg:expr) => {
        impl From<$ty> for CliError {
            fn from(err: $ty) -> CliError {
                CliError {
                    repr: CliErrorRepr::BasicError(format!("{}: {}", $msg, err))
                }
            }
        }
    }
}

basic_error!(io::Error, "i/o failure");
basic_error!(zip::result::ZipError, "could not zip");
basic_error!(walkdir::Error, "could not walk path");
basic_error!(url::ParseError, "could not parse URL");
basic_error!(hyper::error::Error, "could not perform HTTP request");
basic_error!(serde_json::Error, "failed to parse JSON");
basic_error!(FromUtf8Error, "invalid UTF-8");
basic_error!(ini::Error, "ini error");
basic_error!(sourcemap::Error, "sourcemap error");

impl From<hyper::client::response::Response> for CliError {
    fn from(mut resp: hyper::client::response::Response) -> CliError {
        let mut err = None;
        let mut body = String::new();
        resp.read_to_string(&mut body).ok();

        if resp.headers.get::<ContentType>() == Some(&ContentType::json()) {
            let rv : serde_json::Result<ErrorInfo> = serde_json::from_reader(body.as_bytes());
            if let Ok(error_info) = rv {
                err = error_info.detail;
            }
        }
        if err.is_none() {
            err = Some(body);
        }
        CliError {
            repr: CliErrorRepr::HyperResponse(resp.status, err.unwrap())
        }
    }
}

impl From<clap::Error> for CliError {
    fn from(err: clap::Error) -> CliError {
        CliError {
            repr: CliErrorRepr::ClapError(err)
        }
    }
}

impl From<String> for CliError {
    fn from(err: String) -> CliError {
        CliError {
            repr: CliErrorRepr::BasicError(err)
        }
    }
}

impl<'a> From<&'a str> for CliError {
    fn from(err: &'a str) -> CliError {
        CliError {
            repr: CliErrorRepr::BasicError(err.to_owned())
        }
    }
}

impl CliError {

    pub fn exit(&self) -> ! {
        match self.repr {
            CliErrorRepr::ClapError(ref err) => err.exit(),
            CliErrorRepr::HyperResponse(status, _) => {
                writeln!(&mut io::stderr(), "error: {}", self).ok();
                if status == StatusCode::Unauthorized {
                    writeln!(&mut io::stderr(), "").ok();
                    writeln!(&mut io::stderr(), "You can use 'sentry-cli login' to sign in.").ok();
                }
                process::exit(1)
            },
            _ => {
                writeln!(&mut io::stderr(), "error: {}", self).ok();
                process::exit(1)
            },
        }
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.repr {
            CliErrorRepr::BasicError(ref msg) => write!(f, "{}", msg),
            CliErrorRepr::ClapError(ref err) => write!(f, "{}", err),
            CliErrorRepr::HyperResponse(status, ref err) => {
                write!(f, "request failed ({}: {})", status, err)
            },
        }
    }
}

impl error::Error for CliError {
    fn description(&self) -> &str {
        match self.repr {
            CliErrorRepr::BasicError(ref msg) => &msg,
            CliErrorRepr::ClapError(ref err) => err.description(),
            CliErrorRepr::HyperResponse(_, _) => "HTTP response error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.repr {
            CliErrorRepr::ClapError(ref err) => Some(&*err),
            _ => None,
        }
    }
}
<commit_msg>Improved error handling for response errors<commit_after>use std::error;
use std::process;
use std::fmt;
use std::io;
use std::io::{Read, Write};
use std::string::FromUtf8Error;

use hyper::status::StatusCode;
use hyper::header::ContentType;

use ini::ini;
use clap;
use hyper;
use serde_json;
use url;
use walkdir;
use zip;
use sourcemap;

pub type CliResult<T> = Result<T, CliError>;

#[derive(Debug)]
pub struct CliError {
    repr: CliErrorRepr,
}

#[derive(Debug)]
enum CliErrorRepr {
    ClapError(clap::Error),
    HyperResponse(StatusCode, String),
    BasicError(String),
}

#[derive(Debug, Deserialize)]
struct ErrorInfo {
    detail: Option<String>,
    error: Option<String>,
}

macro_rules! basic_error {
    ($ty:ty, $msg:expr) => {
        impl From<$ty> for CliError {
            fn from(err: $ty) -> CliError {
                CliError {
                    repr: CliErrorRepr::BasicError(format!("{}: {}", $msg, err))
                }
            }
        }
    }
}

basic_error!(io::Error, "i/o failure");
basic_error!(zip::result::ZipError, "could not zip");
basic_error!(walkdir::Error, "could not walk path");
basic_error!(url::ParseError, "could not parse URL");
basic_error!(hyper::error::Error, "could not perform HTTP request");
basic_error!(serde_json::Error, "failed to parse JSON");
basic_error!(FromUtf8Error, "invalid UTF-8");
basic_error!(ini::Error, "ini error");
basic_error!(sourcemap::Error, "sourcemap error");

impl From<hyper::client::response::Response> for CliError {
    fn from(mut resp: hyper::client::response::Response) -> CliError {
        let mut err = None;
        let mut body = String::new();
        resp.read_to_string(&mut body).ok();

        if resp.headers.get::<ContentType>() == Some(&ContentType::json()) {
            let rv : serde_json::Result<ErrorInfo> = serde_json::from_reader(body.as_bytes());
            if let Ok(error_info) = rv {
                err = error_info.detail.or(error_info.error);
            }
        }
        if err.is_none() {
            err = Some(body);
        }
        CliError {
            repr: CliErrorRepr::HyperResponse(resp.status, err.unwrap())
        }
    }
}

impl From<clap::Error> for CliError {
    fn from(err: clap::Error) -> CliError {
        CliError {
            repr: CliErrorRepr::ClapError(err)
        }
    }
}

impl From<String> for CliError {
    fn from(err: String) -> CliError {
        CliError {
            repr: CliErrorRepr::BasicError(err)
        }
    }
}

impl<'a> From<&'a str> for CliError {
    fn from(err: &'a str) -> CliError {
        CliError {
            repr: CliErrorRepr::BasicError(err.to_owned())
        }
    }
}

impl CliError {

    pub fn exit(&self) -> ! {
        match self.repr {
            CliErrorRepr::ClapError(ref err) => err.exit(),
            CliErrorRepr::HyperResponse(status, _) => {
                writeln!(&mut io::stderr(), "error: {}", self).ok();
                if status == StatusCode::Unauthorized {
                    writeln!(&mut io::stderr(), "").ok();
                    writeln!(&mut io::stderr(), "You can use 'sentry-cli login' to sign in.").ok();
                }
                process::exit(1)
            },
            _ => {
                writeln!(&mut io::stderr(), "error: {}", self).ok();
                process::exit(1)
            },
        }
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.repr {
            CliErrorRepr::BasicError(ref msg) => write!(f, "{}", msg),
            CliErrorRepr::ClapError(ref err) => write!(f, "{}", err),
            CliErrorRepr::HyperResponse(status, ref err) => {
                write!(f, "request failed ({}: {})", status, err)
            },
        }
    }
}

impl error::Error for CliError {
    fn description(&self) -> &str {
        match self.repr {
            CliErrorRepr::BasicError(ref msg) => &msg,
            CliErrorRepr::ClapError(ref err) => err.description(),
            CliErrorRepr::HyperResponse(_, _) => "HTTP response error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.repr {
            CliErrorRepr::ClapError(ref err) => Some(&*err),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io;
use std::io::Write;
use std::path::Path;
#[cfg(windows)]
use winapi::um::winnt::{FILE_GENERIC_READ, FILE_GENERIC_WRITE, STANDARD_RIGHTS_ALL};

/// This is the security identifier in Windows for the owner of a file. See:
/// - https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/security-identifiers-in-windows#well-known-sids-all-versions-of-windows
#[cfg(windows)]
const OWNER_SID_STR: &str = "S-1-3-4";
/// We don't need any of the `AceFlags` listed here:
/// - https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
#[cfg(windows)]
const OWNER_ACL_ENTRY_FLAGS: u8 = 0;
/// Generic Rights:
///  - https://docs.microsoft.com/en-us/windows/win32/fileio/file-security-and-access-rights
/// Individual Read/Write/Execute Permissions (referenced in generic rights link):
///  - https://docs.microsoft.com/en-us/windows/win32/wmisdk/file-and-directory-access-rights-constants
/// STANDARD_RIGHTS_ALL
///  - https://docs.microsoft.com/en-us/windows/win32/secauthz/access-mask
#[cfg(windows)]
const OWNER_ACL_ENTRY_MASK: u32 = FILE_GENERIC_READ | FILE_GENERIC_WRITE | STANDARD_RIGHTS_ALL;

#[derive(Debug)]
pub enum Error {
    /// The file could not be created
    UnableToCreateFile(io::Error),
    /// The file could not be copied
    UnableToCopyFile(io::Error),
    /// The file could not be opened
    UnableToOpenFile(io::Error),
    /// The file could not be renamed
    UnableToRenameFile(io::Error),
    /// Failed to set permissions
    UnableToSetPermissions(io::Error),
    /// Failed to retrieve file metadata
    UnableToRetrieveMetadata(io::Error),
    /// Failed to write bytes to file
    UnableToWriteFile(io::Error),
    /// Failed to obtain file path
    UnableToObtainFilePath,
    /// Failed to convert string to SID
    UnableToConvertSID(u32),
    /// Failed to retrieve ACL for file
    UnableToRetrieveACL(u32),
    /// Failed to enumerate ACL entries
    UnableToEnumerateACLEntries(u32),
    /// Failed to add new ACL entry
    UnableToAddACLEntry(String),
    /// Failed to remove ACL entry
    UnableToRemoveACLEntry(String),
}

/// Creates a file with `600 (-rw-------)` permissions and writes the specified bytes to file.
pub fn create_with_600_perms<P: AsRef<Path>>(path: P, bytes: &[u8]) -> Result<(), Error> {
    let path = path.as_ref();
    let mut file = File::create(&path).map_err(Error::UnableToCreateFile)?;

    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        let mut perm = file
            .metadata()
            .map_err(Error::UnableToRetrieveMetadata)?
            .permissions();
        perm.set_mode(0o600);
        file.set_permissions(perm)
            .map_err(Error::UnableToSetPermissions)?;
    }

    file.write_all(bytes).map_err(Error::UnableToWriteFile)?;
    #[cfg(windows)]
    {
        restrict_file_permissions(path)?;
    }

    Ok(())
}

pub fn restrict_file_permissions<P: AsRef<Path>>(path: P) -> Result<(), Error> {
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        let file = File::open(path.as_ref()).map_err(Error::UnableToOpenFile)?;
        let mut perm = file
            .metadata()
            .map_err(Error::UnableToRetrieveMetadata)?
            .permissions();
        perm.set_mode(0o600);
        file.set_permissions(perm)
            .map_err(Error::UnableToSetPermissions)?;
    }

    #[cfg(windows)]
    {
        use winapi::um::winnt::PSID;
        use windows_acl::acl::{AceType, ACL};
        use windows_acl::helper::sid_to_string;

        let path_str = path
            .as_ref()
            .to_str()
            .ok_or(Error::UnableToObtainFilePath)?;
        let mut acl = ACL::from_file_path(&path_str, false).map_err(Error::UnableToRetrieveACL)?;

        let owner_sid =
            windows_acl::helper::string_to_sid(OWNER_SID_STR).map_err(Error::UnableToConvertSID)?;

        let entries = acl.all().map_err(Error::UnableToEnumerateACLEntries)?;

        // add single entry for file owner
        acl.add_entry(
            owner_sid.as_ptr() as PSID,
            AceType::AccessAllow,
            OWNER_ACL_ENTRY_FLAGS,
            OWNER_ACL_ENTRY_MASK,
        )
        .map_err(|code| {
            Error::UnableToAddACLEntry(format!(
                "Failed to add ACL entry for SID {} error={}",
                OWNER_SID_STR, code
            ))
        })?;
        // remove all AccessAllow entries from the file that aren't the owner_sid
        for entry in &entries {
            if let Some(ref entry_sid) = entry.sid {
                let entry_sid_str = sid_to_string(entry_sid.as_ptr() as PSID)
                    .unwrap_or_else(|_| "BadFormat".to_string());
                if entry_sid_str != OWNER_SID_STR {
                    acl.remove(entry_sid.as_ptr() as PSID, Some(AceType::AccessAllow), None)
                        .map_err(|_| {
                            Error::UnableToRemoveACLEntry(format!(
                                "Failed to remove ACL entry for SID {}",
                                entry_sid_str
                            ))
                        })?;
                }
            }
        }
    }

    Ok(())
}
<commit_msg>Fix linting error on Windows (#2759)<commit_after>use std::fs::File;
use std::io;
use std::io::Write;
use std::path::Path;
#[cfg(windows)]
use winapi::um::winnt::{FILE_GENERIC_READ, FILE_GENERIC_WRITE, STANDARD_RIGHTS_ALL};

/// This is the security identifier in Windows for the owner of a file. See:
/// - https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/security-identifiers-in-windows#well-known-sids-all-versions-of-windows
#[cfg(windows)]
const OWNER_SID_STR: &str = "S-1-3-4";
/// We don't need any of the `AceFlags` listed here:
/// - https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
#[cfg(windows)]
const OWNER_ACL_ENTRY_FLAGS: u8 = 0;
/// Generic Rights:
///  - https://docs.microsoft.com/en-us/windows/win32/fileio/file-security-and-access-rights
/// Individual Read/Write/Execute Permissions (referenced in generic rights link):
///  - https://docs.microsoft.com/en-us/windows/win32/wmisdk/file-and-directory-access-rights-constants
/// STANDARD_RIGHTS_ALL
///  - https://docs.microsoft.com/en-us/windows/win32/secauthz/access-mask
#[cfg(windows)]
const OWNER_ACL_ENTRY_MASK: u32 = FILE_GENERIC_READ | FILE_GENERIC_WRITE | STANDARD_RIGHTS_ALL;

#[derive(Debug)]
pub enum Error {
    /// The file could not be created
    UnableToCreateFile(io::Error),
    /// The file could not be copied
    UnableToCopyFile(io::Error),
    /// The file could not be opened
    UnableToOpenFile(io::Error),
    /// The file could not be renamed
    UnableToRenameFile(io::Error),
    /// Failed to set permissions
    UnableToSetPermissions(io::Error),
    /// Failed to retrieve file metadata
    UnableToRetrieveMetadata(io::Error),
    /// Failed to write bytes to file
    UnableToWriteFile(io::Error),
    /// Failed to obtain file path
    UnableToObtainFilePath,
    /// Failed to convert string to SID
    UnableToConvertSID(u32),
    /// Failed to retrieve ACL for file
    UnableToRetrieveACL(u32),
    /// Failed to enumerate ACL entries
    UnableToEnumerateACLEntries(u32),
    /// Failed to add new ACL entry
    UnableToAddACLEntry(String),
    /// Failed to remove ACL entry
    UnableToRemoveACLEntry(String),
}

/// Creates a file with `600 (-rw-------)` permissions and writes the specified bytes to file.
pub fn create_with_600_perms<P: AsRef<Path>>(path: P, bytes: &[u8]) -> Result<(), Error> {
    let path = path.as_ref();
    let mut file = File::create(&path).map_err(Error::UnableToCreateFile)?;

    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        let mut perm = file
            .metadata()
            .map_err(Error::UnableToRetrieveMetadata)?
            .permissions();
        perm.set_mode(0o600);
        file.set_permissions(perm)
            .map_err(Error::UnableToSetPermissions)?;
    }

    file.write_all(bytes).map_err(Error::UnableToWriteFile)?;
    #[cfg(windows)]
    {
        restrict_file_permissions(path)?;
    }

    Ok(())
}

pub fn restrict_file_permissions<P: AsRef<Path>>(path: P) -> Result<(), Error> {
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        let file = File::open(path.as_ref()).map_err(Error::UnableToOpenFile)?;
        let mut perm = file
            .metadata()
            .map_err(Error::UnableToRetrieveMetadata)?
            .permissions();
        perm.set_mode(0o600);
        file.set_permissions(perm)
            .map_err(Error::UnableToSetPermissions)?;
    }

    #[cfg(windows)]
    {
        use winapi::um::winnt::PSID;
        use windows_acl::acl::{AceType, ACL};
        use windows_acl::helper::sid_to_string;

        let path_str = path
            .as_ref()
            .to_str()
            .ok_or(Error::UnableToObtainFilePath)?;
        let mut acl = ACL::from_file_path(path_str, false).map_err(Error::UnableToRetrieveACL)?;

        let owner_sid =
            windows_acl::helper::string_to_sid(OWNER_SID_STR).map_err(Error::UnableToConvertSID)?;

        let entries = acl.all().map_err(Error::UnableToEnumerateACLEntries)?;

        // add single entry for file owner
        acl.add_entry(
            owner_sid.as_ptr() as PSID,
            AceType::AccessAllow,
            OWNER_ACL_ENTRY_FLAGS,
            OWNER_ACL_ENTRY_MASK,
        )
        .map_err(|code| {
            Error::UnableToAddACLEntry(format!(
                "Failed to add ACL entry for SID {} error={}",
                OWNER_SID_STR, code
            ))
        })?;
        // remove all AccessAllow entries from the file that aren't the owner_sid
        for entry in &entries {
            if let Some(ref entry_sid) = entry.sid {
                let entry_sid_str = sid_to_string(entry_sid.as_ptr() as PSID)
                    .unwrap_or_else(|_| "BadFormat".to_string());
                if entry_sid_str != OWNER_SID_STR {
                    acl.remove(entry_sid.as_ptr() as PSID, Some(AceType::AccessAllow), None)
                        .map_err(|_| {
                            Error::UnableToRemoveACLEntry(format!(
                                "Failed to remove ACL entry for SID {}",
                                entry_sid_str
                            ))
                        })?;
                }
            }
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>extern crate piston_window;

fn main() {
    let window: piston_window::PistonWindow = piston_window::WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

    for _e in window {
    }
}
<commit_msg>use piston_window...<commit_after>extern crate piston_window;

use piston_window::{PistonWindow, WindowSettings};

fn main() {
    let window: PistonWindow = WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

    for _e in window {
    }
}
<|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.

//! Feature gating
//!
//! This modules implements the gating necessary for preventing certain compiler
//! features from being used by default. This module will crawl a pre-expanded
//! AST to ensure that there are no features which are used that are not
//! enabled.
//!
//! Features are enabled in programs via the crate-level attributes of
//! #[feature(...)] with a comma-separated list of features.

use syntax::ast;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::visit;
use syntax::visit::Visitor;
use syntax::parse::token;

use driver::session::Session;

/// This is a list of all known features since the beginning of time. This list
/// can never shrink, it may only be expanded (in order to prevent old programs
/// from failing to compile). The status of each feature may change, however.
static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
    ("globs", Active),
    ("macro_rules", Active),
    ("struct_variant", Active),
    ("once_fns", Active),
    ("asm", Active),
    ("managed_boxes", Active),
    ("non_ascii_idents", Active),

    // These are used to test this portion of the compiler, they don't actually
    // mean anything
    ("test_accepted_feature", Accepted),
    ("test_removed_feature", Removed),
];

enum Status {
    /// Represents an active feature that is currently being implemented or
    /// currently being considered for addition/removal.
    Active,

    /// Represents a feature which has since been removed (it was once Active)
    Removed,

    /// This language feature has since been Accepted (it was once Active)
    Accepted,
}

struct Context {
    features: ~[&'static str],
    sess: Session,
}

impl Context {
    fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
        if !self.has_feature(feature) {
            self.sess.span_err(span, explain);
            self.sess.span_note(span, format!("add \\#[feature({})] to the \
                                                  crate attributes to enable",
                                                 feature));
        }
    }

    fn has_feature(&self, feature: &str) -> bool {
        self.features.iter().any(|n| n.as_slice() == feature)
    }
}

impl Visitor<()> for Context {
    fn visit_ident(&mut self, sp: Span, id: ast::Ident, _: ()) {
        let s = token::ident_to_str(&id);

        if !s.is_ascii() {
            self.gate_feature("non_ascii_idents", sp,
                              "non-ascii idents are not fully supported.");
        }
    }

    fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
        match i.node {
            ast::view_item_use(ref paths) => {
                for path in paths.iter() {
                    match path.node {
                        ast::view_path_glob(*) => {
                            self.gate_feature("globs", path.span,
                                              "glob import statements are \
                                               experimental and possibly buggy");
                        }
                        _ => {}
                    }
                }
            }
            _ => {}
        }
        visit::walk_view_item(self, i, ())
    }

    fn visit_item(&mut self, i: @ast::item, _:()) {
        match i.node {
            ast::item_enum(ref def, _) => {
                for variant in def.variants.iter() {
                    match variant.node.kind {
                        ast::struct_variant_kind(*) => {
                            self.gate_feature("struct_variant", variant.span,
                                              "enum struct variants are \
                                               experimental and possibly buggy");
                        }
                        _ => {}
                    }
                }
            }

            _ => {}
        }

        visit::walk_item(self, i, ());
    }

    fn visit_mac(&mut self, macro: &ast::mac, _: ()) {
        let ast::mac_invoc_tt(ref path, _, _) = macro.node;

        if path.segments.last().identifier == self.sess.ident_of("macro_rules") {
            self.gate_feature("macro_rules", path.span, "macro definitions are \
                not stable enough for use and are subject to change");
        }

        else if path.segments.last().identifier == self.sess.ident_of("asm") {
            self.gate_feature("asm", path.span, "inline assembly is not \
                stable enough for use and is subject to change");
        }
    }

    fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
        match t.node {
            ast::ty_closure(closure) if closure.onceness == ast::Once &&
                    closure.sigil != ast::OwnedSigil => {
                self.gate_feature("once_fns", t.span,
                                  "once functions are \
                                   experimental and likely to be removed");

            },
            ast::ty_box(_) => {
                self.gate_feature("managed_boxes", t.span,
                                  "The managed box syntax is being replaced by the `std::gc::Gc`
                                  and `std::rc::Rc` types. Equivalent functionality to managed
                                  trait objects will be implemented but is currently missing.");
            }
            _ => {}
        }

        visit::walk_ty(self, t, ());
    }
}

pub fn check_crate(sess: Session, crate: &ast::Crate) {
    let mut cx = Context {
        features: ~[],
        sess: sess,
    };

    for attr in crate.attrs.iter() {
        if "feature" != attr.name() { continue }

        match attr.meta_item_list() {
            None => {
                sess.span_err(attr.span, "malformed feature attribute, \
                                          expected #[feature(...)]");
            }
            Some(list) => {
                for &mi in list.iter() {
                    let name = match mi.node {
                        ast::MetaWord(word) => word,
                        _ => {
                            sess.span_err(mi.span, "malformed feature, expected \
                                                    just one word");
                            continue
                        }
                    };
                    match KNOWN_FEATURES.iter().find(|& &(n, _)| n == name) {
                        Some(&(name, Active)) => { cx.features.push(name); }
                        Some(&(_, Removed)) => {
                            sess.span_err(mi.span, "feature has been removed");
                        }
                        Some(&(_, Accepted)) => {
                            sess.span_warn(mi.span, "feature has added to rust, \
                                                     directive not necessary");
                        }
                        None => {
                            sess.span_err(mi.span, "unknown feature");
                        }
                    }
                }
            }
        }
    }

    visit::walk_crate(&mut cx, crate, ());

    sess.abort_if_errors();
}
<commit_msg>add a thread_local feature gate<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.

//! Feature gating
//!
//! This modules implements the gating necessary for preventing certain compiler
//! features from being used by default. This module will crawl a pre-expanded
//! AST to ensure that there are no features which are used that are not
//! enabled.
//!
//! Features are enabled in programs via the crate-level attributes of
//! #[feature(...)] with a comma-separated list of features.

use syntax::ast;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::visit;
use syntax::visit::Visitor;
use syntax::parse::token;

use driver::session::Session;

/// This is a list of all known features since the beginning of time. This list
/// can never shrink, it may only be expanded (in order to prevent old programs
/// from failing to compile). The status of each feature may change, however.
static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
    ("globs", Active),
    ("macro_rules", Active),
    ("struct_variant", Active),
    ("once_fns", Active),
    ("asm", Active),
    ("managed_boxes", Active),
    ("non_ascii_idents", Active),
    ("thread_local", Active),

    // These are used to test this portion of the compiler, they don't actually
    // mean anything
    ("test_accepted_feature", Accepted),
    ("test_removed_feature", Removed),
];

enum Status {
    /// Represents an active feature that is currently being implemented or
    /// currently being considered for addition/removal.
    Active,

    /// Represents a feature which has since been removed (it was once Active)
    Removed,

    /// This language feature has since been Accepted (it was once Active)
    Accepted,
}

struct Context {
    features: ~[&'static str],
    sess: Session,
}

impl Context {
    fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
        if !self.has_feature(feature) {
            self.sess.span_err(span, explain);
            self.sess.span_note(span, format!("add \\#[feature({})] to the \
                                                  crate attributes to enable",
                                                 feature));
        }
    }

    fn has_feature(&self, feature: &str) -> bool {
        self.features.iter().any(|n| n.as_slice() == feature)
    }
}

impl Visitor<()> for Context {
    fn visit_ident(&mut self, sp: Span, id: ast::Ident, _: ()) {
        let s = token::ident_to_str(&id);

        if !s.is_ascii() {
            self.gate_feature("non_ascii_idents", sp,
                              "non-ascii idents are not fully supported.");
        }
    }

    fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
        match i.node {
            ast::view_item_use(ref paths) => {
                for path in paths.iter() {
                    match path.node {
                        ast::view_path_glob(*) => {
                            self.gate_feature("globs", path.span,
                                              "glob import statements are \
                                               experimental and possibly buggy");
                        }
                        _ => {}
                    }
                }
            }
            _ => {}
        }
        visit::walk_view_item(self, i, ())
    }

    fn visit_item(&mut self, i: @ast::item, _:()) {
        // NOTE: uncomment after snapshot
        /*
        for attr in i.attrs.iter() {
            if "thread_local" == attr.name() {
                self.gate_feature("thread_local", i.span,
                                  "`#[thread_local]` is an experimental feature, and does not \
                                  currently handle destructors. There is no corresponding \
                                  `#[task_local]` mapping to the task model");
            }
        }
        */
        match i.node {
            ast::item_enum(ref def, _) => {
                for variant in def.variants.iter() {
                    match variant.node.kind {
                        ast::struct_variant_kind(*) => {
                            self.gate_feature("struct_variant", variant.span,
                                              "enum struct variants are \
                                               experimental and possibly buggy");
                        }
                        _ => {}
                    }
                }
            }

            _ => {}
        }

        visit::walk_item(self, i, ());
    }

    fn visit_mac(&mut self, macro: &ast::mac, _: ()) {
        let ast::mac_invoc_tt(ref path, _, _) = macro.node;

        if path.segments.last().identifier == self.sess.ident_of("macro_rules") {
            self.gate_feature("macro_rules", path.span, "macro definitions are \
                not stable enough for use and are subject to change");
        }

        else if path.segments.last().identifier == self.sess.ident_of("asm") {
            self.gate_feature("asm", path.span, "inline assembly is not \
                stable enough for use and is subject to change");
        }
    }

    fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
        match t.node {
            ast::ty_closure(closure) if closure.onceness == ast::Once &&
                    closure.sigil != ast::OwnedSigil => {
                self.gate_feature("once_fns", t.span,
                                  "once functions are \
                                   experimental and likely to be removed");

            },
            ast::ty_box(_) => {
                self.gate_feature("managed_boxes", t.span,
                                  "The managed box syntax is being replaced by the `std::gc::Gc` \
                                  and `std::rc::Rc` types. Equivalent functionality to managed \
                                  trait objects will be implemented but is currently missing.");
            }
            _ => {}
        }

        visit::walk_ty(self, t, ());
    }
}

pub fn check_crate(sess: Session, crate: &ast::Crate) {
    let mut cx = Context {
        features: ~[],
        sess: sess,
    };

    for attr in crate.attrs.iter() {
        if "feature" != attr.name() { continue }

        match attr.meta_item_list() {
            None => {
                sess.span_err(attr.span, "malformed feature attribute, \
                                          expected #[feature(...)]");
            }
            Some(list) => {
                for &mi in list.iter() {
                    let name = match mi.node {
                        ast::MetaWord(word) => word,
                        _ => {
                            sess.span_err(mi.span, "malformed feature, expected \
                                                    just one word");
                            continue
                        }
                    };
                    match KNOWN_FEATURES.iter().find(|& &(n, _)| n == name) {
                        Some(&(name, Active)) => { cx.features.push(name); }
                        Some(&(_, Removed)) => {
                            sess.span_err(mi.span, "feature has been removed");
                        }
                        Some(&(_, Accepted)) => {
                            sess.span_warn(mi.span, "feature has added to rust, \
                                                     directive not necessary");
                        }
                        None => {
                            sess.span_err(mi.span, "unknown feature");
                        }
                    }
                }
            }
        }
    }

    visit::walk_crate(&mut cx, crate, ());

    sess.abort_if_errors();
}
<|endoftext|>


<commit_before>// 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.

use std::collections::HashMap;
use std::fmt;

use english_cardinal_classifier;
use {Args, Context, Message, MessagePart, PluralCategory, Value};

/// Format a value taking pluralization rules into account.
#[derive(Debug)]
pub struct PluralFormat {
    /// The name of the variable whose value should be formatted.
    variable_name: String,
    classifier: fn(i64) -> PluralCategory,
    literals: HashMap<i64, Message>,
    offset: i64,
    zero: Option<Message>,
    one: Option<Message>,
    two: Option<Message>,
    few: Option<Message>,
    many: Option<Message>,
    other: Message,
}

impl PluralFormat {
    /// Construct a `PluralFormat`.
    pub fn new(variable_name: &str, other: Message) -> Self {
        PluralFormat {
            variable_name: variable_name.to_string(),
            classifier: english_cardinal_classifier,
            literals: HashMap::new(),
            offset: 0,
            zero: None,
            one: None,
            two: None,
            few: None,
            many: None,
            other: other,
        }
    }

    /// Set the `message` to be used for a literal value.
    pub fn literal(&mut self, literal: i64, message: Message) {
        self.literals.insert(literal, message);
    }

    /// Apply an `offset`.
    pub fn offset(&mut self, offset: i64) {
        self.offset = offset;
    }

    /// Set the `message` for `PluralCategory::Zero`.
    pub fn zero(&mut self, message: Message) {
        self.zero = Some(message);
    }

    /// Set the `message` for `PluralCategory::One`.
    pub fn one(&mut self, message: Message) {
        self.one = Some(message);
    }

    /// Set the `message` for `PluralCategory::Two`.
    pub fn two(&mut self, message: Message) {
        self.two = Some(message);
    }

    /// Set the `message` for `PluralCategory::Few`.
    pub fn few(&mut self, message: Message) {
        self.few = Some(message);
    }

    /// Set the `message` for `PluralCategory::Many`.
    pub fn many(&mut self, message: Message) {
        self.many = Some(message);
    }

    /// Given a value adjusted by the `offset`, determine which `Message` to use.
    fn lookup_message(&self, offset_value: i64) -> &Message {
        if let Some(literal) = self.literals.get(&offset_value) {
            literal
        } else {
            let category = (self.classifier)(offset_value);
            match category {
                PluralCategory::Zero => self.zero.as_ref().unwrap_or(&self.other),
                PluralCategory::One => self.one.as_ref().unwrap_or(&self.other),
                PluralCategory::Two => self.two.as_ref().unwrap_or(&self.other),
                PluralCategory::Few => self.few.as_ref().unwrap_or(&self.other),
                PluralCategory::Many => self.many.as_ref().unwrap_or(&self.other),
                PluralCategory::Other => &self.other,
            }
        }
    }
}

impl MessagePart for PluralFormat {
    fn apply_format<'f>(&self,
                        ctx: &Context,
                        stream: &mut fmt::Write,
                        args: Option<&Args<'f>>)
                        -> fmt::Result {
        let arg = args.and_then(|args| args.get(&self.variable_name));
        if let Some(&Value::Number(value)) = arg.map(|a| a.value()) {
            let offset_value = value - self.offset;
            let message = self.lookup_message(offset_value);
            let ctx = Context { placeholder_value: Some(offset_value), ..ctx.clone() };
            try!(message.write_message(&ctx, stream, args));
            Ok(())
        } else {
            Err(fmt::Error {})
        }
    }
}

#[cfg(test)]
mod tests {
    use icu::parse;
    use super::PluralFormat;
    use {arg, Context, MessagePart};

    #[test]
    fn it_works() {
        let ctx = Context::default();
        let mut fmt = PluralFormat::new("count", parse("Other").unwrap());
        fmt.one(parse("One").unwrap());

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 0))).unwrap();
        assert_eq!("Other", output);

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 1))).unwrap();
        assert_eq!("One", output);

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 3))).unwrap();
        assert_eq!("Other", output);
    }
}
<commit_msg>Implement tests for literals in plural format.<commit_after>// 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.

use std::collections::HashMap;
use std::fmt;

use english_cardinal_classifier;
use {Args, Context, Message, MessagePart, PluralCategory, Value};

/// Format a value taking pluralization rules into account.
#[derive(Debug)]
pub struct PluralFormat {
    /// The name of the variable whose value should be formatted.
    variable_name: String,
    classifier: fn(i64) -> PluralCategory,
    literals: HashMap<i64, Message>,
    offset: i64,
    zero: Option<Message>,
    one: Option<Message>,
    two: Option<Message>,
    few: Option<Message>,
    many: Option<Message>,
    other: Message,
}

impl PluralFormat {
    /// Construct a `PluralFormat`.
    pub fn new(variable_name: &str, other: Message) -> Self {
        PluralFormat {
            variable_name: variable_name.to_string(),
            classifier: english_cardinal_classifier,
            literals: HashMap::new(),
            offset: 0,
            zero: None,
            one: None,
            two: None,
            few: None,
            many: None,
            other: other,
        }
    }

    /// Set the `message` to be used for a literal value.
    pub fn literal(&mut self, literal: i64, message: Message) {
        self.literals.insert(literal, message);
    }

    /// Apply an `offset`.
    pub fn offset(&mut self, offset: i64) {
        self.offset = offset;
    }

    /// Set the `message` for `PluralCategory::Zero`.
    pub fn zero(&mut self, message: Message) {
        self.zero = Some(message);
    }

    /// Set the `message` for `PluralCategory::One`.
    pub fn one(&mut self, message: Message) {
        self.one = Some(message);
    }

    /// Set the `message` for `PluralCategory::Two`.
    pub fn two(&mut self, message: Message) {
        self.two = Some(message);
    }

    /// Set the `message` for `PluralCategory::Few`.
    pub fn few(&mut self, message: Message) {
        self.few = Some(message);
    }

    /// Set the `message` for `PluralCategory::Many`.
    pub fn many(&mut self, message: Message) {
        self.many = Some(message);
    }

    /// Given a value adjusted by the `offset`, determine which `Message` to use.
    fn lookup_message(&self, offset_value: i64) -> &Message {
        if let Some(literal) = self.literals.get(&offset_value) {
            literal
        } else {
            let category = (self.classifier)(offset_value);
            match category {
                PluralCategory::Zero => self.zero.as_ref().unwrap_or(&self.other),
                PluralCategory::One => self.one.as_ref().unwrap_or(&self.other),
                PluralCategory::Two => self.two.as_ref().unwrap_or(&self.other),
                PluralCategory::Few => self.few.as_ref().unwrap_or(&self.other),
                PluralCategory::Many => self.many.as_ref().unwrap_or(&self.other),
                PluralCategory::Other => &self.other,
            }
        }
    }
}

impl MessagePart for PluralFormat {
    fn apply_format<'f>(&self,
                        ctx: &Context,
                        stream: &mut fmt::Write,
                        args: Option<&Args<'f>>)
                        -> fmt::Result {
        let arg = args.and_then(|args| args.get(&self.variable_name));
        if let Some(&Value::Number(value)) = arg.map(|a| a.value()) {
            let offset_value = value - self.offset;
            let message = self.lookup_message(offset_value);
            let ctx = Context { placeholder_value: Some(offset_value), ..ctx.clone() };
            try!(message.write_message(&ctx, stream, args));
            Ok(())
        } else {
            Err(fmt::Error {})
        }
    }
}

#[cfg(test)]
mod tests {
    use icu::parse;
    use super::PluralFormat;
    use {arg, Context, MessagePart};

    #[test]
    fn it_works() {
        let ctx = Context::default();
        let mut fmt = PluralFormat::new("count", parse("Other").unwrap());
        fmt.one(parse("One").unwrap());

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 0))).unwrap();
        assert_eq!("Other", output);

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 1))).unwrap();
        assert_eq!("One", output);

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 3))).unwrap();
        assert_eq!("Other", output);
    }

    #[test]
    fn literals_work() {
        let ctx = Context::default();

        let mut fmt = PluralFormat::new("count", parse("Other").unwrap());
        fmt.one(parse("One").unwrap());
        fmt.literal(3, parse("Three").unwrap());
        fmt.literal(6, parse("Six").unwrap());

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 1))).unwrap();
        assert_eq!("One", output);

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 3))).unwrap();
        assert_eq!("Three", output);

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 6))).unwrap();
        assert_eq!("Six", output);

        let mut output = String::new();
        fmt.apply_format(&ctx, &mut output, Some(&arg("count", 0))).unwrap();
        assert_eq!("Other", output);
    }
}
<|endoftext|>


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

//! Identities for binary operators

use std::ops::{Add, Mul};

/// A type that is equipped with an additive identity.
pub trait IdentityAdditive
    : Add<Self, Output=Self>
{
    /// The additive identity element, `0`.
    fn zero() -> Self;
}

impl IdentityAdditive for u8   { #[inline] fn zero() -> u8   { 0   } }
impl IdentityAdditive for u16  { #[inline] fn zero() -> u16  { 0   } }
impl IdentityAdditive for u32  { #[inline] fn zero() -> u32  { 0   } }
impl IdentityAdditive for u64  { #[inline] fn zero() -> u64  { 0   } }
impl IdentityAdditive for i8   { #[inline] fn zero() -> i8   { 0   } }
impl IdentityAdditive for i16  { #[inline] fn zero() -> i16  { 0   } }
impl IdentityAdditive for i32  { #[inline] fn zero() -> i32  { 0   } }
impl IdentityAdditive for i64  { #[inline] fn zero() -> i64  { 0   } }
impl IdentityAdditive for f32  { #[inline] fn zero() -> f32  { 0.0 } }
impl IdentityAdditive for f64  { #[inline] fn zero() -> f64  { 0.0 } }

/// The additive identity element, `0`.
pub fn zero<T: IdentityAdditive>() -> T {
    IdentityAdditive::zero()
}

/// A type that is equipped with a multiplicative identity.
pub trait IdentityMultiplicative
    : Mul<Self, Output=Self>
{
    /// The multiplicative identity element, `1`.
    fn unit() -> Self;
}

impl IdentityMultiplicative for u8   { #[inline] fn unit() -> u8   { 1   } }
impl IdentityMultiplicative for u16  { #[inline] fn unit() -> u16  { 1   } }
impl IdentityMultiplicative for u32  { #[inline] fn unit() -> u32  { 1   } }
impl IdentityMultiplicative for u64  { #[inline] fn unit() -> u64  { 1   } }
impl IdentityMultiplicative for i8   { #[inline] fn unit() -> i8   { 1   } }
impl IdentityMultiplicative for i16  { #[inline] fn unit() -> i16  { 1   } }
impl IdentityMultiplicative for i32  { #[inline] fn unit() -> i32  { 1   } }
impl IdentityMultiplicative for i64  { #[inline] fn unit() -> i64  { 1   } }
impl IdentityMultiplicative for f32  { #[inline] fn unit() -> f32  { 1.0 } }
impl IdentityMultiplicative for f64  { #[inline] fn unit() -> f64  { 1.0 } }

/// The multiplicative identity element, `1`.
pub fn unit<T: IdentityMultiplicative>() -> T {
    IdentityMultiplicative::unit()
}
<commit_msg>Added Sized bounds to traits.<commit_after>// Copyright 2013-2014 The Num-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Identities for binary operators

use std::ops::{Add, Mul};

/// A type that is equipped with an additive identity.
pub trait IdentityAdditive
    : Add<Self, Output=Self> + Sized
{
    /// The additive identity element, `0`.
    fn zero() -> Self;
}

impl IdentityAdditive for u8   { #[inline] fn zero() -> u8   { 0   } }
impl IdentityAdditive for u16  { #[inline] fn zero() -> u16  { 0   } }
impl IdentityAdditive for u32  { #[inline] fn zero() -> u32  { 0   } }
impl IdentityAdditive for u64  { #[inline] fn zero() -> u64  { 0   } }
impl IdentityAdditive for i8   { #[inline] fn zero() -> i8   { 0   } }
impl IdentityAdditive for i16  { #[inline] fn zero() -> i16  { 0   } }
impl IdentityAdditive for i32  { #[inline] fn zero() -> i32  { 0   } }
impl IdentityAdditive for i64  { #[inline] fn zero() -> i64  { 0   } }
impl IdentityAdditive for f32  { #[inline] fn zero() -> f32  { 0.0 } }
impl IdentityAdditive for f64  { #[inline] fn zero() -> f64  { 0.0 } }

/// The additive identity element, `0`.
pub fn zero<T: IdentityAdditive>() -> T {
    IdentityAdditive::zero()
}

/// A type that is equipped with a multiplicative identity.
pub trait IdentityMultiplicative
    : Mul<Self, Output=Self> + Sized
{
    /// The multiplicative identity element, `1`.
    fn unit() -> Self;
}

impl IdentityMultiplicative for u8   { #[inline] fn unit() -> u8   { 1   } }
impl IdentityMultiplicative for u16  { #[inline] fn unit() -> u16  { 1   } }
impl IdentityMultiplicative for u32  { #[inline] fn unit() -> u32  { 1   } }
impl IdentityMultiplicative for u64  { #[inline] fn unit() -> u64  { 1   } }
impl IdentityMultiplicative for i8   { #[inline] fn unit() -> i8   { 1   } }
impl IdentityMultiplicative for i16  { #[inline] fn unit() -> i16  { 1   } }
impl IdentityMultiplicative for i32  { #[inline] fn unit() -> i32  { 1   } }
impl IdentityMultiplicative for i64  { #[inline] fn unit() -> i64  { 1   } }
impl IdentityMultiplicative for f32  { #[inline] fn unit() -> f32  { 1.0 } }
impl IdentityMultiplicative for f64  { #[inline] fn unit() -> f64  { 1.0 } }

/// The multiplicative identity element, `1`.
pub fn unit<T: IdentityMultiplicative>() -> T {
    IdentityMultiplicative::unit()
}
<|endoftext|>