<commit_before>use snake;
use game_state;

pub static NUMBER_OF_LAYERS: uint = 4;
pub static WATER_COLOR: [f32, ..4] = [0.0, 0.0, 0.45, 1.0];
pub static WATER_FRICTION: f64 = 0.2;
pub static RADIUS: f64 = 0.1;
pub static SURFACE_Y: f64 = 0.8;
pub static INITIAL_GAME_STATE: game_state::GameState = game_state::Play;
pub static INITIAL_CAMERA_POS: [f64, ..2] = [0.0, 0.0];
pub static CAMERA_FOLLOW_PERCENTAGE: f64 = 0.2;

pub static YOU_WIN_TEXT: &'static str = "you win";
pub static YOU_WIN_TEXT_COLOR: [f32, ..4] = GREEN;
pub static YOU_WIN_POS: [f64, ..2] = [-0.42, 0.1];

pub static YOU_LOOSE_TEXT: &'static str = "you loose";
pub static YOU_LOOSE_TEXT_COLOR: [f32, ..4] = RED;
pub static YOU_LOOSE_POS: [f64, ..2] = [-0.55, 0.1];

pub static PLAYER_LOOSE_AIR_SPEED: f64 = 0.1;
pub static PLAYER_COLOR: [f32, ..4] = YELLOW;
pub static PLAYER_INITIAL_BLOOD: f64 = 1.0;
pub static PLAYER_INITIAL_AIR: f64 = 1.0;
pub static PLAYER_RADIUS: f64 = 0.1;
pub static PLAYER_ACCELERATION_RIGHT: f64 = 0.1;
pub static PLAYER_ACCELERATION_LEFT: f64 = 0.1;
pub static PLAYER_ACCELERATION_UP: f64 = 0.1;
pub static PLAYER_ACCELERATION_DOWN: f64 = 0.1;
pub static PLAYER_INITIAL_TWEEN_FACTOR: f64 = 0.0;
pub static PLAYER_TWEEN_SPEED: f64 = 1.0;

pub struct SnakeSettings {
    pub acceleration_left: f64,
    pub acceleration_right: f64,
    pub acceleration_up: f64,
    pub acceleration_down: f64,
    pub initial_state: snake::SnakeState,
    pub bite_damage: f64,
    pub sensor_distance: f64,
    pub attack_distance: f64,
    pub wait_seconds_before_initial_attack: f64,
    pub wait_seconds_before_repeat_attack: f64,
    pub test_color: [f32, ..4],
    pub radius: f64,
}

pub static SNAKE_TAIL_COLOR: [f32, ..4] = [0.8, 0.6, 0.6, 0.4];

pub static SNAKE_TAIL_DISTANCE: f64 = 0.01;
pub static SNAKE_OVERALL_ACCELERATION: f64 = 2.0;
pub static SNAKE_SETTINGS: SnakeSettings = SnakeSettings {
    acceleration_left: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_right: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_up: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_down: 0.1 * SNAKE_OVERALL_ACCELERATION,
    initial_state: snake::Ignorant,
    bite_damage: 0.1,
    sensor_distance: 2.0,
    attack_distance: 2.0 * PLAYER_RADIUS,
    wait_seconds_before_initial_attack: 1.0,
    wait_seconds_before_repeat_attack: 1.0,
    test_color: BLACK,
    radius: 0.03,
};

pub static SNAKE_SPEED_RIGHT: f64 = 0.1;
pub static SNAKE_SPEED_LEFT: f64 = 0.1;
pub static SNAKE_SPEED_UP: f64 = 0.1;
pub static SNAKE_SPEED_DOWN: f64 = 0.1;

// snake 1.
pub static SNAKE_1_SETTINGS: SnakeSettings = SNAKE_SETTINGS;
pub static SNAKE_1_POS: [f64, ..2] = [-0.8, 0.8];
pub static SNAKE_1_ADD: bool = true;

// snake 2.
pub static SNAKE_2_SETTINGS: SnakeSettings = SNAKE_SETTINGS;
pub static SNAKE_2_POS: [f64, ..2] = [0.8, 0.8];
pub static SNAKE_2_ADD: bool = true;

pub static BAR_RECTANGLE: [f64, ..4] = [0.3, -0.06, 1.5, 0.05];
pub static BAR_MARGIN: f64 = 0.01;
pub static BAR_TEXT_COLOR: [f32, ..4] = WHITE;

pub static AIR_BAR_INITIAL_VALUE: f64 = 0.5;
pub static AIR_BAR_POS: [f64, ..2] = [-0.9, 0.95];
pub static AIR_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static AIR_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_BLUE;
pub static AIR_BAR_BAR_COLOR: [f32, ..4] = LIGHT_BLUE;

pub static BLOOD_BAR_INITIAL_VALUE: f64 = 0.5;
pub static BLOOD_BAR_POS: [f64, ..2] = [-0.9, 0.85];
pub static BLOOD_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static BLOOD_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_RED;
pub static BLOOD_BAR_BAR_COLOR: [f32, ..4] = LIGHT_RED;

pub static BAR_BACKGROUND_HEIGHT: f64 = 0.275;
pub static BAR_BACKGROUND_COLOR: [f32, ..4] = [0.1, 0.1, 0.1, 0.9];
pub static BAR_BACKGROUND_COLOR_2: [f32, ..4] = [0.4, 0.4, 0.4, 0.8];
pub static BAR_BACKGROUND_MARGIN: f64 = 0.01;
pub static BAR_BACKGROUND_MARGIN_2: f64 = 0.02;

pub static BLACK: [f32, ..4] = [0.0, 0.0, 0.0, 1.0];
pub static WHITE: [f32, ..4] = [1.0, 1.0, 1.0, 1.0];
pub static GRAY: [f32, ..4] = [0.5, 0.5, 0.5, 1.0];
pub static DARK_GRAY: [f32, ..4] = [0.2, 0.2, 0.2, 1.0];

pub static RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];
pub static DARK_RED: [f32, ..4] = [0.5, 0.0, 0.0, 1.0];
pub static LIGHT_RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];

pub static GREEN: [f32, ..4] = [0.0, 1.0, 0.0, 1.0];

pub static BLUE: [f32, ..4] = [0.0, 0.0, 1.0, 1.0];
pub static DARK_BLUE: [f32, ..4] = [0.0, 0.0, 0.5, 1.0];
pub static LIGHT_BLUE: [f32, ..4] = [0.5, 0.5, 1.0, 1.0];

pub static YELLOW: [f32, ..4] = [0.0, 1.0, 1.0, 1.0];

pub static ORIGIN: [f64, ..2] = [0.0, 0.0];

<commit_msg>Set surface higher up<commit_after>use snake;
use game_state;

pub static NUMBER_OF_LAYERS: uint = 4;
pub static WATER_COLOR: [f32, ..4] = [0.0, 0.0, 0.45, 1.0];
pub static WATER_FRICTION: f64 = 0.2;
pub static RADIUS: f64 = 0.1;
pub static SURFACE_Y: f64 = 10.0;
pub static INITIAL_GAME_STATE: game_state::GameState = game_state::Play;
pub static INITIAL_CAMERA_POS: [f64, ..2] = [0.0, 0.0];
pub static CAMERA_FOLLOW_PERCENTAGE: f64 = 0.2;

pub static YOU_WIN_TEXT: &'static str = "you win";
pub static YOU_WIN_TEXT_COLOR: [f32, ..4] = GREEN;
pub static YOU_WIN_POS: [f64, ..2] = [-0.42, 0.1];

pub static YOU_LOOSE_TEXT: &'static str = "you loose";
pub static YOU_LOOSE_TEXT_COLOR: [f32, ..4] = RED;
pub static YOU_LOOSE_POS: [f64, ..2] = [-0.55, 0.1];

pub static PLAYER_LOOSE_AIR_SPEED: f64 = 0.1;
pub static PLAYER_COLOR: [f32, ..4] = YELLOW;
pub static PLAYER_INITIAL_BLOOD: f64 = 1.0;
pub static PLAYER_INITIAL_AIR: f64 = 1.0;
pub static PLAYER_RADIUS: f64 = 0.1;
pub static PLAYER_ACCELERATION_RIGHT: f64 = 0.1;
pub static PLAYER_ACCELERATION_LEFT: f64 = 0.1;
pub static PLAYER_ACCELERATION_UP: f64 = 0.1;
pub static PLAYER_ACCELERATION_DOWN: f64 = 0.1;
pub static PLAYER_INITIAL_TWEEN_FACTOR: f64 = 0.0;
pub static PLAYER_TWEEN_SPEED: f64 = 1.0;

pub struct SnakeSettings {
    pub acceleration_left: f64,
    pub acceleration_right: f64,
    pub acceleration_up: f64,
    pub acceleration_down: f64,
    pub initial_state: snake::SnakeState,
    pub bite_damage: f64,
    pub sensor_distance: f64,
    pub attack_distance: f64,
    pub wait_seconds_before_initial_attack: f64,
    pub wait_seconds_before_repeat_attack: f64,
    pub test_color: [f32, ..4],
    pub radius: f64,
}

pub static SNAKE_TAIL_COLOR: [f32, ..4] = [0.8, 0.6, 0.6, 0.4];

pub static SNAKE_TAIL_DISTANCE: f64 = 0.01;
pub static SNAKE_OVERALL_ACCELERATION: f64 = 2.0;
pub static SNAKE_SETTINGS: SnakeSettings = SnakeSettings {
    acceleration_left: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_right: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_up: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_down: 0.1 * SNAKE_OVERALL_ACCELERATION,
    initial_state: snake::Ignorant,
    bite_damage: 0.1,
    sensor_distance: 2.0,
    attack_distance: 2.0 * PLAYER_RADIUS,
    wait_seconds_before_initial_attack: 1.0,
    wait_seconds_before_repeat_attack: 1.0,
    test_color: BLACK,
    radius: 0.03,
};

pub static SNAKE_SPEED_RIGHT: f64 = 0.1;
pub static SNAKE_SPEED_LEFT: f64 = 0.1;
pub static SNAKE_SPEED_UP: f64 = 0.1;
pub static SNAKE_SPEED_DOWN: f64 = 0.1;

// snake 1.
pub static SNAKE_1_SETTINGS: SnakeSettings = SNAKE_SETTINGS;
pub static SNAKE_1_POS: [f64, ..2] = [-0.8, 0.8];
pub static SNAKE_1_ADD: bool = true;

// snake 2.
pub static SNAKE_2_SETTINGS: SnakeSettings = SNAKE_SETTINGS;
pub static SNAKE_2_POS: [f64, ..2] = [0.8, 0.8];
pub static SNAKE_2_ADD: bool = true;

pub static BAR_RECTANGLE: [f64, ..4] = [0.3, -0.06, 1.5, 0.05];
pub static BAR_MARGIN: f64 = 0.01;
pub static BAR_TEXT_COLOR: [f32, ..4] = WHITE;

pub static AIR_BAR_INITIAL_VALUE: f64 = 0.5;
pub static AIR_BAR_POS: [f64, ..2] = [-0.9, 0.95];
pub static AIR_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static AIR_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_BLUE;
pub static AIR_BAR_BAR_COLOR: [f32, ..4] = LIGHT_BLUE;

pub static BLOOD_BAR_INITIAL_VALUE: f64 = 0.5;
pub static BLOOD_BAR_POS: [f64, ..2] = [-0.9, 0.85];
pub static BLOOD_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static BLOOD_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_RED;
pub static BLOOD_BAR_BAR_COLOR: [f32, ..4] = LIGHT_RED;

pub static BAR_BACKGROUND_HEIGHT: f64 = 0.275;
pub static BAR_BACKGROUND_COLOR: [f32, ..4] = [0.1, 0.1, 0.1, 0.9];
pub static BAR_BACKGROUND_COLOR_2: [f32, ..4] = [0.4, 0.4, 0.4, 0.8];
pub static BAR_BACKGROUND_MARGIN: f64 = 0.01;
pub static BAR_BACKGROUND_MARGIN_2: f64 = 0.02;

pub static BLACK: [f32, ..4] = [0.0, 0.0, 0.0, 1.0];
pub static WHITE: [f32, ..4] = [1.0, 1.0, 1.0, 1.0];
pub static GRAY: [f32, ..4] = [0.5, 0.5, 0.5, 1.0];
pub static DARK_GRAY: [f32, ..4] = [0.2, 0.2, 0.2, 1.0];

pub static RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];
pub static DARK_RED: [f32, ..4] = [0.5, 0.0, 0.0, 1.0];
pub static LIGHT_RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];

pub static GREEN: [f32, ..4] = [0.0, 1.0, 0.0, 1.0];

pub static BLUE: [f32, ..4] = [0.0, 0.0, 1.0, 1.0];
pub static DARK_BLUE: [f32, ..4] = [0.0, 0.0, 0.5, 1.0];
pub static LIGHT_BLUE: [f32, ..4] = [0.5, 0.5, 1.0, 1.0];

pub static YELLOW: [f32, ..4] = [0.0, 1.0, 1.0, 1.0];

pub static ORIGIN: [f64, ..2] = [0.0, 0.0];

<|endoftext|>


<commit_before>//! Angle (dimensionless quantity).

#[cfg(feature = "std")]
use super::ratio::Ratio;

quantity! {
    /// Angle (dimensionless quantity).
    quantity: Angle; "angle";
    /// Dimension of angle, 1 (dimensionless).
    dimension: ISQ<
        Z0,     // length
        Z0,     // mass
        Z0,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    kind: dyn (::si::marker::AngleKind);
    units {
        /// SI derived unit of angle. It is the angle subtended at the center of a circle by an
        /// arc that is equal in length to the radius of the circle.
        @radian: 1.0_E0; "rad", "radian", "radians";
        @revolution: 6.283_185_307_179_586_E0; "r", "revolution", "revolutions";
        @degree: 1.745_329_251_994_329_5_E-2; "°", "degree", "degrees";
        @gon: 1.570_796_326_794_896_7_E-2; "gon", "gon", "gons";
        @mil: 9.817_477_E-4; "mil", "mil", "mils";
        @minute: 2.908_882_086_657_216_E-4; "′", "minute", "minutes";
        @second: 4.848_136_811_095_36_E-6; "″", "second", "seconds";
    }
}

/// Implementation of various stdlib trigonometric functions
#[cfg(feature = "std")]
impl<U, V> Angle<U, V>
where
    U: ::si::Units<V> + ?Sized,
    V: ::num::Float + ::Conversion<V>,
{
    /// Computes the value of the cosine of the angle.
    #[inline(always)]
    pub fn cos(self) -> Ratio<U, V> {
        self.value.cos().into()
    }

    /// Computes the value of the hyperbolic cosine of the angle.
    #[inline(always)]
    pub fn cosh(self) -> Ratio<U, V> {
        self.value.cosh().into()
    }

    /// Computes the value of the sine of the angle.
    #[inline(always)]
    pub fn sin(self) -> Ratio<U, V> {
        self.value.sin().into()
    }

    /// Computes the value of the hyperbolic sine of the angle.
    #[inline(always)]
    pub fn sinh(self) -> Ratio<U, V> {
        self.value.sinh().into()
    }

    /// Computes the value of both the sine and cosine of the angle.
    #[inline(always)]
    pub fn sin_cos(self) -> (Ratio<U, V>, Ratio<U, V>) {
        let (sin, cos) = self.value.sin_cos();
        (sin.into(), cos.into())
    }

    /// Computes the value of the tangent of the angle.
    #[inline(always)]
    pub fn tan(self) -> Ratio<U, V> {
        self.value.tan().into()
    }

    /// Computes the value of the hyperbolic tangent of the angle.
    #[inline(always)]
    pub fn tanh(self) -> Ratio<U, V> {
        self.value.tanh().into()
    }
}

#[cfg(feature = "std")]
impl<D, U, V> ::si::Quantity<D, U, V>
where
    D: ::si::Dimension + ?Sized,
    U: ::si::Units<V> + ?Sized,
    V: ::num::Float + ::Conversion<V>,
    radian: ::Conversion<V, T = V::T>,
{
    /// Computes the four quadrant arctangent of self (y) and other (x).
    #[inline(always)]
    pub fn atan2(self, other: Self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.atan2(other.value))
    }
}

mod convert {
    use super::*;

    impl<U, V> ::lib::convert::From<V> for Angle<U, V>
    where
        U: ::si::Units<V> + ?Sized,
        V: ::num::Num + ::Conversion<V>,
    {
        fn from(t: V) -> Self {
            Angle {
                dimension: ::lib::marker::PhantomData,
                units: ::lib::marker::PhantomData,
                value: t,
            }
        }
    }

    storage_types! {
        use super::*;

        impl<U> ::lib::convert::From<Angle<U, V>> for V
        where
            U: ::si::Units<V> + ?Sized,
            V: ::num::Num + ::Conversion<V>,
        {
            fn from(t: Angle<U, V>) -> Self {
                t.value
            }
        }
    }
}

#[cfg(test)]
mod tests {
    storage_types! {
        use ::lib::f64::consts::PI;
        use num::{FromPrimitive, One};
        use si::angle as a;
        use si::quantities::*;
        use tests::Test;

        #[test]
        fn from() {
            let r1: Angle<V> = Angle::<V>::from(V::one());
            let r2: Angle<V> = V::one().into();
            let _: V = V::from(r1);
            let _: V = r2.into();
        }

        #[test]
        fn check_units() {
            Test::assert_eq(&Angle::new::<a::radian>(V::from_f64(2.0 * PI).unwrap()),
                &Angle::new::<a::revolution>(V::one()));
            Test::assert_eq(&Angle::new::<a::degree>(V::from_f64(360.0).unwrap()),
                &Angle::new::<a::revolution>(V::one()));
            Test::assert_approx_eq(&Angle::new::<a::gon>(V::from_f64(400.0).unwrap()),
                &Angle::new::<a::revolution>(V::one()));
            Test::assert_eq(&Angle::new::<a::minute>(V::from_f64(60.0).unwrap()),
                &Angle::new::<a::degree>(V::one()));
            Test::assert_eq(&Angle::new::<a::second>(V::from_f64(60.0 * 60.0).unwrap()),
                &Angle::new::<a::degree>(V::one()));
        }
    }

    #[cfg(feature = "std")]
    mod trig {
        storage_types! {
            types: Float;

            use ::lib::f64::consts::PI;
            use num::{FromPrimitive, Zero};
            use si::angle as a;
            use si::length as l;
            use si::quantities::*;
            use tests::Test;

            #[test]
            fn sanity() {
                let zero: Angle<V> = Angle::zero();
                let nzero: Angle<V> = -Angle::zero();
                let pi: Angle<V> = Angle::new::<a::radian>(V::from_f64(PI).unwrap());
                let half: Angle<V> = Angle::new::<a::radian>(V::from_f64(PI / 2.0).unwrap());

                Test::assert_approx_eq(&zero.cos().into(), &1.0);
                Test::assert_approx_eq(&nzero.cos().into(), &1.0);

                Test::assert_approx_eq(&pi.cos().into(), &-1.0);
                Test::assert_approx_eq(&half.cos().into(), &0.0);

                Test::assert_approx_eq(&zero.sin().into(), &0.0);
                Test::assert_approx_eq(&nzero.sin().into(), &0.0);

                // Float inaccuracy does not guarantee approximate values
                // In these tests, it diverges slightly over the epsilon value
                //Test::assert_approx_eq(&pi.sin().into(), &0.0);
                //Test::assert_approx_eq(&half.sin().into(), &1.0);

                Test::assert_approx_eq(&zero.tan().into(), &0.0);
                Test::assert_approx_eq(&nzero.tan().into(), &0.0);

                //Test::assert_approx_eq(&pi.tan(), &0.0);
                // Cannot test for PI / 2 equality as it diverges to infinity
                // Float inaccuracy does not guarantee a NAN or INFINITY result
                //let result = half.tan().into();
                //assert!(result == V::nan() || result == V::infinity());

                Test::assert_approx_eq(&zero.cosh().into(), &1.0);
                Test::assert_approx_eq(&nzero.cosh().into(), &1.0);

                Test::assert_approx_eq(&zero.sinh().into(), &0.0);
                Test::assert_approx_eq(&nzero.sinh().into(), &0.0);

                Test::assert_approx_eq(&zero.tanh().into(), &0.0);
                Test::assert_approx_eq(&nzero.tanh().into(), &0.0);
            }

            quickcheck! {
                #[allow(trivial_casts)]
                fn atan2(y: V, x: V) -> bool {
                    Test::eq(&y.atan2(x),
                        &Length::new::<l::meter>(y).atan2(Length::new::<l::meter>(x)).get::<a::radian>())
                }
            }
        }
    }
}
<commit_msg>Add constants to Angle representing half and full turns<commit_after>//! Angle (dimensionless quantity).

#[cfg(feature = "std")]
use super::ratio::Ratio;

quantity! {
    /// Angle (dimensionless quantity).
    quantity: Angle; "angle";
    /// Dimension of angle, 1 (dimensionless).
    dimension: ISQ<
        Z0,     // length
        Z0,     // mass
        Z0,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    kind: dyn (::si::marker::AngleKind);
    units {
        /// SI derived unit of angle. It is the angle subtended at the center of a circle by an
        /// arc that is equal in length to the radius of the circle.
        @radian: 1.0_E0; "rad", "radian", "radians";
        @revolution: 6.283_185_307_179_586_E0; "r", "revolution", "revolutions";
        @degree: 1.745_329_251_994_329_5_E-2; "°", "degree", "degrees";
        @gon: 1.570_796_326_794_896_7_E-2; "gon", "gon", "gons";
        @mil: 9.817_477_E-4; "mil", "mil", "mils";
        @minute: 2.908_882_086_657_216_E-4; "′", "minute", "minutes";
        @second: 4.848_136_811_095_36_E-6; "″", "second", "seconds";
    }
}

#[cfg(all(feature = "std", feature = "f32"))]
impl Angle<::si::SI<f32>, f32> {
    /// A half turn, i.e. an angle with a value of π as measured in radians
    pub const HALF_TURN: Self = Self {
        dimension: std::marker::PhantomData,
        units: std::marker::PhantomData,
        value: std::f32::consts::PI,
    };

    /// A full turn, i.e. an angle with a value of 2π as measured in radians
    pub const FULL_TURN: Self = Self {
        dimension: std::marker::PhantomData,
        units: std::marker::PhantomData,
        value: 2. * std::f32::consts::PI,
    };
}

#[cfg(all(feature = "std", feature = "f64"))]
impl Angle<::si::SI<f64>, f64> {
    /// A half turn, i.e. an angle with a value of π as measured in radians
    pub const HALF_TURN: Self = Self {
        dimension: std::marker::PhantomData,
        units: std::marker::PhantomData,
        value: std::f64::consts::PI,
    };

    /// A full turn, i.e. an angle with a value of 2π as measured in radians
    pub const FULL_TURN: Self = Self {
        dimension: std::marker::PhantomData,
        units: std::marker::PhantomData,
        value: 2. * std::f64::consts::PI,
    };
}

/// Implementation of various stdlib trigonometric functions
#[cfg(feature = "std")]
impl<U, V> Angle<U, V>
where
    U: ::si::Units<V> + ?Sized,
    V: ::num::Float + ::Conversion<V>,
{
    /// Computes the value of the cosine of the angle.
    #[inline(always)]
    pub fn cos(self) -> Ratio<U, V> {
        self.value.cos().into()
    }

    /// Computes the value of the hyperbolic cosine of the angle.
    #[inline(always)]
    pub fn cosh(self) -> Ratio<U, V> {
        self.value.cosh().into()
    }

    /// Computes the value of the sine of the angle.
    #[inline(always)]
    pub fn sin(self) -> Ratio<U, V> {
        self.value.sin().into()
    }

    /// Computes the value of the hyperbolic sine of the angle.
    #[inline(always)]
    pub fn sinh(self) -> Ratio<U, V> {
        self.value.sinh().into()
    }

    /// Computes the value of both the sine and cosine of the angle.
    #[inline(always)]
    pub fn sin_cos(self) -> (Ratio<U, V>, Ratio<U, V>) {
        let (sin, cos) = self.value.sin_cos();
        (sin.into(), cos.into())
    }

    /// Computes the value of the tangent of the angle.
    #[inline(always)]
    pub fn tan(self) -> Ratio<U, V> {
        self.value.tan().into()
    }

    /// Computes the value of the hyperbolic tangent of the angle.
    #[inline(always)]
    pub fn tanh(self) -> Ratio<U, V> {
        self.value.tanh().into()
    }
}

#[cfg(feature = "std")]
impl<D, U, V> ::si::Quantity<D, U, V>
where
    D: ::si::Dimension + ?Sized,
    U: ::si::Units<V> + ?Sized,
    V: ::num::Float + ::Conversion<V>,
    radian: ::Conversion<V, T = V::T>,
{
    /// Computes the four quadrant arctangent of self (y) and other (x).
    #[inline(always)]
    pub fn atan2(self, other: Self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.atan2(other.value))
    }
}

mod convert {
    use super::*;

    impl<U, V> ::lib::convert::From<V> for Angle<U, V>
    where
        U: ::si::Units<V> + ?Sized,
        V: ::num::Num + ::Conversion<V>,
    {
        fn from(t: V) -> Self {
            Angle {
                dimension: ::lib::marker::PhantomData,
                units: ::lib::marker::PhantomData,
                value: t,
            }
        }
    }

    storage_types! {
        use super::*;

        impl<U> ::lib::convert::From<Angle<U, V>> for V
        where
            U: ::si::Units<V> + ?Sized,
            V: ::num::Num + ::Conversion<V>,
        {
            fn from(t: Angle<U, V>) -> Self {
                t.value
            }
        }
    }
}

#[cfg(test)]
mod tests {
    storage_types! {
        use ::lib::f64::consts::PI;
        use num::{FromPrimitive, One};
        use si::angle as a;
        use si::quantities::*;
        use tests::Test;

        #[test]
        fn from() {
            let r1: Angle<V> = Angle::<V>::from(V::one());
            let r2: Angle<V> = V::one().into();
            let _: V = V::from(r1);
            let _: V = r2.into();
        }

        #[test]
        fn check_units() {
            Test::assert_eq(&Angle::new::<a::radian>(V::from_f64(2.0 * PI).unwrap()),
                &Angle::new::<a::revolution>(V::one()));
            Test::assert_eq(&Angle::new::<a::degree>(V::from_f64(360.0).unwrap()),
                &Angle::new::<a::revolution>(V::one()));
            Test::assert_approx_eq(&Angle::new::<a::gon>(V::from_f64(400.0).unwrap()),
                &Angle::new::<a::revolution>(V::one()));
            Test::assert_eq(&Angle::new::<a::minute>(V::from_f64(60.0).unwrap()),
                &Angle::new::<a::degree>(V::one()));
            Test::assert_eq(&Angle::new::<a::second>(V::from_f64(60.0 * 60.0).unwrap()),
                &Angle::new::<a::degree>(V::one()));
        }
    }

    #[cfg(feature = "std")]
    mod trig {
        storage_types! {
            types: Float;

            use ::lib::f64::consts::PI;
            use num::{FromPrimitive, Zero};
            use si::angle as a;
            use si::length as l;
            use si::quantities::*;
            use tests::Test;

            #[test]
            fn sanity() {
                let zero: Angle<V> = Angle::zero();
                let nzero: Angle<V> = -Angle::zero();
                let pi: Angle<V> = Angle::new::<a::radian>(V::from_f64(PI).unwrap());
                let half: Angle<V> = Angle::new::<a::radian>(V::from_f64(PI / 2.0).unwrap());

                Test::assert_approx_eq(&zero.cos().into(), &1.0);
                Test::assert_approx_eq(&nzero.cos().into(), &1.0);

                Test::assert_approx_eq(&pi.cos().into(), &-1.0);
                Test::assert_approx_eq(&half.cos().into(), &0.0);

                Test::assert_approx_eq(&zero.sin().into(), &0.0);
                Test::assert_approx_eq(&nzero.sin().into(), &0.0);

                // Float inaccuracy does not guarantee approximate values
                // In these tests, it diverges slightly over the epsilon value
                //Test::assert_approx_eq(&pi.sin().into(), &0.0);
                //Test::assert_approx_eq(&half.sin().into(), &1.0);

                Test::assert_approx_eq(&zero.tan().into(), &0.0);
                Test::assert_approx_eq(&nzero.tan().into(), &0.0);

                //Test::assert_approx_eq(&pi.tan(), &0.0);
                // Cannot test for PI / 2 equality as it diverges to infinity
                // Float inaccuracy does not guarantee a NAN or INFINITY result
                //let result = half.tan().into();
                //assert!(result == V::nan() || result == V::infinity());

                Test::assert_approx_eq(&zero.cosh().into(), &1.0);
                Test::assert_approx_eq(&nzero.cosh().into(), &1.0);

                Test::assert_approx_eq(&zero.sinh().into(), &0.0);
                Test::assert_approx_eq(&nzero.sinh().into(), &0.0);

                Test::assert_approx_eq(&zero.tanh().into(), &0.0);
                Test::assert_approx_eq(&nzero.tanh().into(), &0.0);
            }

            quickcheck! {
                #[allow(trivial_casts)]
                fn atan2(y: V, x: V) -> bool {
                    Test::eq(&y.atan2(x),
                        &Length::new::<l::meter>(y).atan2(Length::new::<l::meter>(x)).get::<a::radian>())
                }
            }

            #[test]
            fn turns() {
                Test::assert_approx_eq(&Angle::<V>::HALF_TURN.cos().into(), &-1.0);
                Test::assert_approx_eq(&Angle::<V>::FULL_TURN.cos().into(), &1.0);
            }
        }
    }
}
<|endoftext|>


<commit_before>use libc::{self, pid_t, c_int};
use {Errno, Result};

use sys::signal::Signal;

mod ffi {
    use libc::{pid_t, c_int};

    extern {
        pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
    }
}

#[cfg(not(any(target_os = "linux",
              target_os = "android")))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
        const WEXITED     = libc::WEXITED,
        const WCONTINUED  = libc::WCONTINUED,
        const WNOWAIT     = libc::WNOWAIT, // Don't reap, just poll status.
        const __WNOTHREAD = libc::__WNOTHREAD, // Don't wait on children of other threads in this group
        const __WALL      = libc::__WALL, // Wait on all children, regardless of type
        const __WCLONE    = libc::__WCLONE,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
const WSTOPPED: WaitPidFlag = WUNTRACED;

#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum WaitStatus {
    Exited(pid_t, i8),
    Signaled(pid_t, Signal, bool),
    Stopped(pid_t, Signal),
    #[cfg(any(target_os = "linux", target_os = "android"))]
    PtraceEvent(pid_t, Signal, c_int),
    Continued(pid_t),
    StillAlive
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
mod status {
    use sys::signal::Signal;
    use libc::c_int;

    pub fn exited(status: i32) -> bool {
        (status & 0x7F) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status & 0xFF00) >> 8) as i8
    }

    pub fn signaled(status: i32) -> bool {
        ((((status & 0x7f) + 1) as i8) >> 1) > 0
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(status & 0x7f).unwrap()
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & 0x80) != 0
    }

    pub fn stopped(status: i32) -> bool {
        (status & 0xff) == 0x7f
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int((status & 0xFF00) >> 8).unwrap()
    }

    pub fn stop_additional(status: i32) -> c_int {
        (status >> 16) as c_int
    }

    pub fn continued(status: i32) -> bool {
        status == 0xFFFF
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod status {
    use sys::signal::{Signal,SIGCONT};

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status >> 8) & 0xFF) as i8
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int(status >> 8).unwrap()
    }

    pub fn continued(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) == SIGCONT
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) != SIGCONT
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(wstatus(status)).unwrap()
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

#[cfg(any(target_os = "freebsd",
          target_os = "openbsd",
          target_os = "dragonfly",
          target_os = "netbsd"))]
mod status {
    use sys::signal::Signal;

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int(status >> 8).unwrap()
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0 && status != 0x13
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(wstatus(status)).unwrap()
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        (status >> 8) as i8
    }

    pub fn continued(status: i32) -> bool {
        status == 0x13
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

fn decode(pid : pid_t, status: i32) -> WaitStatus {
    if status::exited(status) {
        WaitStatus::Exited(pid, status::exit_status(status))
    } else if status::signaled(status) {
        WaitStatus::Signaled(pid, status::term_signal(status), status::dumped_core(status))
    } else if status::stopped(status) {
        #[cfg(any(target_os = "linux", target_os = "android"))] {
            let status_additional = status::stop_additional(status);
            if status_additional != 0 {
                return WaitStatus::PtraceEvent(pid, status::stop_signal(status), status::stop_additional(status))
            }
        }
        WaitStatus::Stopped(pid, status::stop_signal(status))
    } else {
        assert!(status::continued(status));
        WaitStatus::Continued(pid)
    }
}

pub fn waitpid(pid: pid_t, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
    use self::WaitStatus::*;

    let mut status: i32 = 0;

    let option_bits = match options {
        Some(bits) => bits.bits(),
        None => 0
    };

    let res = unsafe { ffi::waitpid(pid as pid_t, &mut status as *mut c_int, option_bits) };

    Ok(match try!(Errno::result(res)) {
        0 => StillAlive,
        res => decode(res, status),
    })
}

pub fn wait() -> Result<WaitStatus> {
    waitpid(-1, None)
}
<commit_msg>Use cfg_if to branch code in WaitStatus decode<commit_after>use libc::{self, pid_t, c_int};
use {Errno, Result};

use sys::signal::Signal;

mod ffi {
    use libc::{pid_t, c_int};

    extern {
        pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
    }
}

#[cfg(not(any(target_os = "linux",
              target_os = "android")))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
        const WEXITED     = libc::WEXITED,
        const WCONTINUED  = libc::WCONTINUED,
        const WNOWAIT     = libc::WNOWAIT, // Don't reap, just poll status.
        const __WNOTHREAD = libc::__WNOTHREAD, // Don't wait on children of other threads in this group
        const __WALL      = libc::__WALL, // Wait on all children, regardless of type
        const __WCLONE    = libc::__WCLONE,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
const WSTOPPED: WaitPidFlag = WUNTRACED;

#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum WaitStatus {
    Exited(pid_t, i8),
    Signaled(pid_t, Signal, bool),
    Stopped(pid_t, Signal),
    #[cfg(any(target_os = "linux", target_os = "android"))]
    PtraceEvent(pid_t, Signal, c_int),
    Continued(pid_t),
    StillAlive
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
mod status {
    use sys::signal::Signal;
    use libc::c_int;

    pub fn exited(status: i32) -> bool {
        (status & 0x7F) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status & 0xFF00) >> 8) as i8
    }

    pub fn signaled(status: i32) -> bool {
        ((((status & 0x7f) + 1) as i8) >> 1) > 0
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(status & 0x7f).unwrap()
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & 0x80) != 0
    }

    pub fn stopped(status: i32) -> bool {
        (status & 0xff) == 0x7f
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int((status & 0xFF00) >> 8).unwrap()
    }

    pub fn stop_additional(status: i32) -> c_int {
        (status >> 16) as c_int
    }

    pub fn continued(status: i32) -> bool {
        status == 0xFFFF
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod status {
    use sys::signal::{Signal,SIGCONT};

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status >> 8) & 0xFF) as i8
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int(status >> 8).unwrap()
    }

    pub fn continued(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) == SIGCONT
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) != SIGCONT
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(wstatus(status)).unwrap()
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

#[cfg(any(target_os = "freebsd",
          target_os = "openbsd",
          target_os = "dragonfly",
          target_os = "netbsd"))]
mod status {
    use sys::signal::Signal;

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int(status >> 8).unwrap()
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0 && status != 0x13
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(wstatus(status)).unwrap()
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        (status >> 8) as i8
    }

    pub fn continued(status: i32) -> bool {
        status == 0x13
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

fn decode(pid : pid_t, status: i32) -> WaitStatus {
    if status::exited(status) {
        WaitStatus::Exited(pid, status::exit_status(status))
    } else if status::signaled(status) {
        WaitStatus::Signaled(pid, status::term_signal(status), status::dumped_core(status))
    } else if status::stopped(status) {
        cfg_if! {
            if #[cfg(any(target_os = "linux", target_os = "android"))] {
                fn decode_stopped(pid: pid_t, status: i32) -> WaitStatus {
                    let status_additional = status::stop_additional(status);
                    if status_additional == 0 {
                        WaitStatus::Stopped(pid, status::stop_signal(status))
                    } else {
                        WaitStatus::PtraceEvent(pid, status::stop_signal(status), status::stop_additional(status))
                    }
                }
            } else {
                fn decode_stopped(pid: pid_t, status: i32) -> WaitStatus {
                    WaitStatus::Stopped(pid, status::stop_signal(status))
                }
            }
        }
        decode_stopped(pid, status)
    } else {
        assert!(status::continued(status));
        WaitStatus::Continued(pid)
    }
}

pub fn waitpid(pid: pid_t, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
    use self::WaitStatus::*;

    let mut status: i32 = 0;

    let option_bits = match options {
        Some(bits) => bits.bits(),
        None => 0
    };

    let res = unsafe { ffi::waitpid(pid as pid_t, &mut status as *mut c_int, option_bits) };

    Ok(match try!(Errno::result(res)) {
        0 => StillAlive,
        res => decode(res, status),
    })
}

pub fn wait() -> Result<WaitStatus> {
    waitpid(-1, None)
}
<|endoftext|>


<commit_before>use errors::{Result, ResultExt};

use case::CaseExt;
use difference;

use super::defaults;
use difference::{Changeset, Difference};
use handlebars::{Handlebars, Helper, RenderContext, RenderError};
use std::collections::BTreeMap;
use std::env;
use std::fs::{self, File, OpenOptions, create_dir_all};
use std::io::{self, Read, Write};
use std::path::{MAIN_SEPARATOR, Path, PathBuf};
use walkdir::WalkDir;
extern crate term;

/// file to clone template to
// const TMP_PREFIX: &'static str = "porteurbars";
/// subdirectory containing template source
const TEMPLATE_DIR: &'static str = "template";

/// name of file containing key/value pairs representing template defaults
const DEFAULTS: &'static str = "default.env";

/// A template holds a path to template source and a
/// file describing the default values associated with
/// names used in the template
#[derive(Debug)]
pub struct Template {
    /// path to template source
    pub path: PathBuf,
}

impl Template {
    pub fn new<P>(path: P) -> Template
    where
        P: AsRef<Path>,
    {
        Template { path: path.as_ref().to_path_buf() }
    }

    /// resolve context
    fn context<R>(
        &self,
        root: &Option<R>,
        yes: bool,
    ) -> Result<BTreeMap<String, String>>
    where
        R: AsRef<Path>,
    {
        let path = &self.path;
        let defaults_file = root.as_ref()
            .map(|r| path.join(r))
            .unwrap_or(path.to_path_buf())
            .join(DEFAULTS);
        let defaults = defaults::from_file(defaults_file.clone()).chain_err(
            move || {
                format!(
                    "failed to parse defaults from file {}",
                    defaults_file.to_string_lossy()
                )
            },
        )?;
        let resolved = if yes {
            defaults.iter().fold(BTreeMap::new(), |mut a, e| {
                let &(ref k, ref v) = e;
                a.insert(k.clone(), v.clone());
                a
            })
        } else {
            interact(&defaults).chain_err(|| "failed to parse defaults")?
        };
        Ok(resolved)
    }

    /// Apply template
    pub fn apply<P, R>(
        &self,
        target: P,
        root: Option<R>,
        yes: bool,
        keep: bool,
    ) -> Result<()>
    where
        P: AsRef<Path>,
        R: AsRef<Path>,
    {
        let ctx = self.context(&root, yes)?;
        let adjusted_path = root.as_ref()
            .map(|r| self.path.join(r))
            .unwrap_or(self.path.to_path_buf());

        // apply handlebars processing
        let apply = |path: &Path, hbs: &mut Handlebars| -> Result<()> {

            // /tmp/download_dir/templates
            let scratchpath =
                &format!(
                    "{}{}",
                    adjusted_path.join(TEMPLATE_DIR).to_str().unwrap(),
                    MAIN_SEPARATOR
                )
                    [..];

            // path relatived based on scratch dir
            let localpath =
                path.to_str().unwrap().trim_left_matches(scratchpath);

            // eval path as template
            let evalpath =
                hbs.template_render(&localpath, &ctx).chain_err(|| {
                    format!("failed to render template {}", localpath)
                })?;

            // rewritten path, based on target dir and eval path
            let targetpath = target.as_ref().join(evalpath);

            if path.is_dir() {
                fs::create_dir_all(targetpath).chain_err(|| {
                    format!(
                        "failed to create directory {}",
                        path.to_string_lossy()
                    )
                })?
            } else {
                let mut file = File::open(path)?;
                let mut s = String::new();
                file.read_to_string(&mut s)?;
                if targetpath.exists() {
                    // open file for reading and writing
                    let mut file = OpenOptions::new()
                        .write(true)
                        .read(true)
                        .open(&targetpath)?;

                    // get the current content
                    let mut current_content = String::new();
                    file.read_to_string(&mut current_content)?;

                    // get the target content
                    let template_eval = hbs.template_render(&s, &ctx)?;

                    // if there's a diff prompt for change
                    if template_eval != current_content {
                        let kept = keep ||
                            keep_current_content(
                                current_content.as_ref(),
                                template_eval.as_ref(),
                                &targetpath,
                            )?;
                        if !kept {
                            // force truncation of current content
                            let mut file = OpenOptions::new()
                                .write(true)
                                .truncate(true)
                                .open(targetpath)?;
                            file.write_all(template_eval.as_bytes())?;
                        }
                    }
                } else {
                    let mut file = File::create(targetpath)?;
                    hbs.template_renderw(&s, &ctx, &mut file)?;
                }
            }
            Ok(())
        };

        create_dir_all(target.as_ref())?;
        let mut hbs = bars();
        for entry in WalkDir::new(&adjusted_path.join(TEMPLATE_DIR))
            .into_iter()
            .skip(1)
            .filter_map(|e| e.ok())
        {
            debug!("applying {:?}", entry.path().display());
            apply(entry.path(), &mut hbs)?
        }
        Ok(())
    }
}

pub fn bars() -> Handlebars {
    let mut hbs = Handlebars::new();
    fn transform<F>(bars: &mut Handlebars, name: &str, f: F)
    where
        F: 'static + Fn(&str) -> String + Sync + Send,
    {
        bars.register_helper(
            name,
            Box::new(move |h: &Helper,
                  _: &Handlebars,
                  rc: &mut RenderContext|
                  -> ::std::result::Result<(), RenderError> {
                let value = h.params().get(0).unwrap().value();
                rc.writer.write(f(value.as_str().unwrap()).as_bytes())?;
                Ok(())
            }),
        );
    }

    transform(&mut hbs, "upper", str::to_uppercase);
    transform(&mut hbs, "lower", str::to_lowercase);
    transform(&mut hbs, "capitalize", CaseExt::to_capitalized);
    transform(&mut hbs, "camel", CaseExt::to_camel);
    transform(&mut hbs, "snake", CaseExt::to_snake);
    transform(&mut hbs, "dashed", CaseExt::to_dashed);

    hbs
}

fn keep_current_content<P>(
    current: &str,
    new: &str,
    file: P,
) -> io::Result<bool>
where
    P: AsRef<Path>,
{
    let mut answer = String::new();
    println!(
        "\n⚠ Warning: Conflicts exist with the previous version of {}\n",
        file.as_ref().display()
    );
    diff(difference::Changeset::new(current, new, "\n"))?;
    print!("Type `r` to replace it: ");
    io::stdout().flush()?;
    io::stdin().read_line(&mut answer)?;
    let trimmed = answer.trim().to_lowercase();
    Ok(trimmed.is_empty() || trimmed != String::from("r"))
}

fn diff(changes: difference::Changeset) -> io::Result<()> {
    let Changeset { diffs, .. } = changes;
    let mut t = term::stdout().unwrap();

    for i in 0..diffs.len() {
        match diffs[i] {
            Difference::Same(ref x) => {
                t.reset()?;
                writeln!(t, " {}", x)?;
            }
            Difference::Add(ref x) => {
                match diffs[i - 1] {
                    Difference::Rem(ref y) => {
                        t.fg(term::color::GREEN)?;
                        write!(t, "+")?;
                        let Changeset { diffs, .. } = Changeset::new(y, x, "");
                        for c in diffs {
                            match c {
                                Difference::Same(ref z) => {
                                    t.fg(term::color::GREEN)?;
                                    write!(t, "{}", z)?;
                                    write!(t, "")?;
                                }
                                Difference::Add(ref z) => {
                                    t.fg(term::color::WHITE)?;
                                    t.bg(term::color::GREEN)?;
                                    write!(t, "{}", z)?;
                                    t.reset()?;
                                    write!(t, "")?;
                                }
                                _ => (),
                            }
                        }
                        writeln!(t, "")?;
                    }
                    _ => {
                        t.fg(term::color::BRIGHT_GREEN)?;
                        writeln!(t, "+{}", x)?;
                    }
                };
            }
            Difference::Rem(ref x) => {
                t.fg(term::color::RED)?;
                writeln!(t, "-{}", x)?;
            }
        }
    }
    t.reset()?;
    t.flush()?;
    Ok(())
}

/// prompt for a value defaulting to a given string when an answer is not available
fn prompt(name: &str, default: &str) -> io::Result<String> {
    let mut answer = String::new();
    print!("{} [{}]: ", name, default);
    io::stdout().flush()?;
    io::stdin().read_line(&mut answer)?;
    let trimmed = answer.trim();
    if trimmed.trim().is_empty() {
        Ok(default.to_owned())
    } else {
        Ok(trimmed.to_owned())
    }
}

/// given a set of defaults, attempt to interact with a user
/// to resolve the parameters that can not be inferred from env
fn interact(defaults: &defaults::Defaults) -> Result<BTreeMap<String, String>> {
    let mut resolved = BTreeMap::new();
    for pair in defaults.iter() {
        let &(ref k, ref v) = pair;
        let answer = match env::var(k) {
            Ok(v) => v,
            _ => prompt(k.as_ref(), v.as_ref())?,
        };
        resolved.insert(k.clone(), answer);
    }
    Ok(resolved)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::BTreeMap;

    #[test]
    fn bars_respects_escapes_tags() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurbars".to_owned());
        assert_eq!(
            "Hello, {{upper name}}",
            bars()
                .template_render(r"Hello, \\{{upper name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_upper() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurbars".to_owned());
        assert_eq!(
            "Hello, PORTEURBARS",
            bars()
                .template_render("Hello, {{upper name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_capitalize() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurbars".to_owned());
        assert_eq!(
            "Hello, Porteurbars",
            bars()
                .template_render("Hello, {{capitalize name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_camel() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteur_bars".to_owned());
        assert_eq!(
            "Hello, PorteurBars",
            bars()
                .template_render("Hello, {{camel name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_dashed() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteur_bars".to_owned());
        assert_eq!(
            "Hello, porteur-bars",
            bars()
                .template_render("Hello, {{dashed name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_snake() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurBars".to_owned());
        assert_eq!(
            "Hello, porteur_bars",
            bars()
                .template_render("Hello, {{snake name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_lower() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "PORTEURBARS".to_owned());
        assert_eq!(
            "Hello, porteurbars",
            bars()
                .template_render("Hello, {{lower name}}", &map)
                .unwrap()
        );
    }
}
<commit_msg>eq helper<commit_after>use errors::{Result, ResultExt};

use case::CaseExt;
use difference;

use super::defaults;
use difference::{Changeset, Difference};
use handlebars::{Handlebars, Helper, RenderContext, RenderError, Renderable};
use std::collections::BTreeMap;
use std::env;
use std::fs::{self, File, OpenOptions, create_dir_all};
use std::io::{self, Read, Write};
use std::path::{MAIN_SEPARATOR, Path, PathBuf};
use walkdir::WalkDir;
extern crate term;

/// file to clone template to
// const TMP_PREFIX: &'static str = "porteurbars";
/// subdirectory containing template source
const TEMPLATE_DIR: &'static str = "template";

/// name of file containing key/value pairs representing template defaults
const DEFAULTS: &'static str = "default.env";

/// A template holds a path to template source and a
/// file describing the default values associated with
/// names used in the template
#[derive(Debug)]
pub struct Template {
    /// path to template source
    pub path: PathBuf,
}

impl Template {
    pub fn new<P>(path: P) -> Template
    where
        P: AsRef<Path>,
    {
        Template { path: path.as_ref().to_path_buf() }
    }

    /// resolve context
    fn context<R>(
        &self,
        root: &Option<R>,
        yes: bool,
    ) -> Result<BTreeMap<String, String>>
    where
        R: AsRef<Path>,
    {
        let path = &self.path;
        let defaults_file = root.as_ref()
            .map(|r| path.join(r))
            .unwrap_or(path.to_path_buf())
            .join(DEFAULTS);
        let defaults = defaults::from_file(defaults_file.clone()).chain_err(
            move || {
                format!(
                    "failed to parse defaults from file {}",
                    defaults_file.to_string_lossy()
                )
            },
        )?;
        let resolved = if yes {
            defaults.iter().fold(BTreeMap::new(), |mut a, e| {
                let &(ref k, ref v) = e;
                a.insert(k.clone(), v.clone());
                a
            })
        } else {
            interact(&defaults).chain_err(|| "failed to parse defaults")?
        };
        Ok(resolved)
    }

    /// Apply template
    pub fn apply<P, R>(
        &self,
        target: P,
        root: Option<R>,
        yes: bool,
        keep: bool,
    ) -> Result<()>
    where
        P: AsRef<Path>,
        R: AsRef<Path>,
    {
        let ctx = self.context(&root, yes)?;
        let adjusted_path = root.as_ref()
            .map(|r| self.path.join(r))
            .unwrap_or(self.path.to_path_buf());

        // apply handlebars processing
        let apply = |path: &Path, hbs: &mut Handlebars| -> Result<()> {

            // /tmp/download_dir/templates
            let scratchpath =
                &format!(
                    "{}{}",
                    adjusted_path.join(TEMPLATE_DIR).to_str().unwrap(),
                    MAIN_SEPARATOR
                )
                    [..];

            // path relatived based on scratch dir
            let localpath =
                path.to_str().unwrap().trim_left_matches(scratchpath);

            // eval path as template
            let evalpath =
                hbs.template_render(&localpath, &ctx).chain_err(|| {
                    format!("failed to render template {}", localpath)
                })?;

            // rewritten path, based on target dir and eval path
            let targetpath = target.as_ref().join(evalpath);

            if path.is_dir() {
                fs::create_dir_all(targetpath).chain_err(|| {
                    format!(
                        "failed to create directory {}",
                        path.to_string_lossy()
                    )
                })?
            } else {
                let mut file = File::open(path)?;
                let mut s = String::new();
                file.read_to_string(&mut s)?;
                if targetpath.exists() {
                    // open file for reading and writing
                    let mut file = OpenOptions::new()
                        .write(true)
                        .read(true)
                        .open(&targetpath)?;

                    // get the current content
                    let mut current_content = String::new();
                    file.read_to_string(&mut current_content)?;

                    // get the target content
                    let template_eval = hbs.template_render(&s, &ctx)?;

                    // if there's a diff prompt for change
                    if template_eval != current_content {
                        let kept = keep ||
                            keep_current_content(
                                current_content.as_ref(),
                                template_eval.as_ref(),
                                &targetpath,
                            )?;
                        if !kept {
                            // force truncation of current content
                            let mut file = OpenOptions::new()
                                .write(true)
                                .truncate(true)
                                .open(targetpath)?;
                            file.write_all(template_eval.as_bytes())?;
                        }
                    }
                } else {
                    let mut file = File::create(targetpath)?;
                    hbs.template_renderw(&s, &ctx, &mut file)?;
                }
            }
            Ok(())
        };

        create_dir_all(target.as_ref())?;
        let mut hbs = bars();
        for entry in WalkDir::new(&adjusted_path.join(TEMPLATE_DIR))
            .into_iter()
            .skip(1)
            .filter_map(|e| e.ok())
        {
            debug!("applying {:?}", entry.path().display());
            apply(entry.path(), &mut hbs)?
        }
        Ok(())
    }
}

pub fn bars() -> Handlebars {
    let mut hbs = Handlebars::new();
    fn transform<F>(bars: &mut Handlebars, name: &str, f: F)
    where
        F: 'static + Fn(&str) -> String + Sync + Send,
    {
        let helper_name = name.to_owned();
        bars.register_helper(
            name,
            Box::new(move |h: &Helper,
                  _: &Handlebars,
                  rc: &mut RenderContext|
                  -> ::std::result::Result<(), RenderError> {
                let value = h.param(0)
                    .and_then(|v| v.value().as_str().to_owned())
                    .ok_or(RenderError::new(format!(
                        "Parameter 0 with str type is required for {} helper.",
                        helper_name
                    )))?;
                rc.writer.write(f(value).as_bytes())?;
                Ok(())
            }),
        );
    }

    transform(&mut hbs, "upper", str::to_uppercase);
    transform(&mut hbs, "lower", str::to_lowercase);
    transform(&mut hbs, "capitalize", CaseExt::to_capitalized);
    transform(&mut hbs, "camel", CaseExt::to_camel);
    transform(&mut hbs, "snake", CaseExt::to_snake);
    transform(&mut hbs, "dashed", CaseExt::to_dashed);
    // helper for eq(quality)
    hbs.register_helper(
        "eq",
        Box::new(|h: &Helper,
         r: &Handlebars,
         rc: &mut RenderContext|
         -> ::std::result::Result<(), RenderError> {
            let a = h.param(0).and_then(|v| v.value().as_str()).ok_or(
                RenderError::new(
                    "Parameter 0 with str type is required for eq helper.",
                ),
            )?;
            let b = h.param(1).and_then(|v| v.value().as_str()).ok_or(
                RenderError::new(
                    "Parameter 1 with str type is required for eq helper.",
                ),
            )?;
            let tmpl = if a == b { h.template() } else { h.inverse() };
            match tmpl {
                Some(ref t) => t.render(r, rc),
                None => Ok(()),
            }
        }),
    );

    hbs
}

fn keep_current_content<P>(
    current: &str,
    new: &str,
    file: P,
) -> io::Result<bool>
where
    P: AsRef<Path>,
{
    let mut answer = String::new();
    println!(
        "\n⚠ Warning: Conflicts exist with the previous version of {}\n",
        file.as_ref().display()
    );
    diff(difference::Changeset::new(current, new, "\n"))?;
    print!("Type `r` to replace it: ");
    io::stdout().flush()?;
    io::stdin().read_line(&mut answer)?;
    let trimmed = answer.trim().to_lowercase();
    Ok(trimmed.is_empty() || trimmed != String::from("r"))
}

fn diff(changes: difference::Changeset) -> io::Result<()> {
    let Changeset { diffs, .. } = changes;
    let mut t = term::stdout().unwrap();

    for i in 0..diffs.len() {
        match diffs[i] {
            Difference::Same(ref x) => {
                t.reset()?;
                writeln!(t, " {}", x)?;
            }
            Difference::Add(ref x) => {
                match diffs[i - 1] {
                    Difference::Rem(ref y) => {
                        t.fg(term::color::GREEN)?;
                        write!(t, "+")?;
                        let Changeset { diffs, .. } = Changeset::new(y, x, "");
                        for c in diffs {
                            match c {
                                Difference::Same(ref z) => {
                                    t.fg(term::color::GREEN)?;
                                    write!(t, "{}", z)?;
                                    write!(t, "")?;
                                }
                                Difference::Add(ref z) => {
                                    t.fg(term::color::WHITE)?;
                                    t.bg(term::color::GREEN)?;
                                    write!(t, "{}", z)?;
                                    t.reset()?;
                                    write!(t, "")?;
                                }
                                _ => (),
                            }
                        }
                        writeln!(t, "")?;
                    }
                    _ => {
                        t.fg(term::color::BRIGHT_GREEN)?;
                        writeln!(t, "+{}", x)?;
                    }
                };
            }
            Difference::Rem(ref x) => {
                t.fg(term::color::RED)?;
                writeln!(t, "-{}", x)?;
            }
        }
    }
    t.reset()?;
    t.flush()?;
    Ok(())
}

/// prompt for a value defaulting to a given string when an answer is not available
fn prompt(name: &str, default: &str) -> io::Result<String> {
    let mut answer = String::new();
    print!("{} [{}]: ", name, default);
    io::stdout().flush()?;
    io::stdin().read_line(&mut answer)?;
    let trimmed = answer.trim();
    if trimmed.trim().is_empty() {
        Ok(default.to_owned())
    } else {
        Ok(trimmed.to_owned())
    }
}

/// given a set of defaults, attempt to interact with a user
/// to resolve the parameters that can not be inferred from env
fn interact(defaults: &defaults::Defaults) -> Result<BTreeMap<String, String>> {
    let mut resolved = BTreeMap::new();
    for pair in defaults.iter() {
        let &(ref k, ref v) = pair;
        let answer = match env::var(k) {
            Ok(v) => v,
            _ => prompt(k.as_ref(), v.as_ref())?,
        };
        resolved.insert(k.clone(), answer);
    }
    Ok(resolved)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::BTreeMap;

    #[test]
    fn bars_respects_escapes_tags() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurbars".to_owned());
        assert_eq!(
            "Hello, {{upper name}}",
            bars()
                .template_render(r"Hello, \\{{upper name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_upper() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurbars".to_owned());
        assert_eq!(
            "Hello, PORTEURBARS",
            bars()
                .template_render("Hello, {{upper name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_capitalize() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurbars".to_owned());
        assert_eq!(
            "Hello, Porteurbars",
            bars()
                .template_render("Hello, {{capitalize name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_camel() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteur_bars".to_owned());
        assert_eq!(
            "Hello, PorteurBars",
            bars()
                .template_render("Hello, {{camel name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_dashed() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteur_bars".to_owned());
        assert_eq!(
            "Hello, porteur-bars",
            bars()
                .template_render("Hello, {{dashed name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_snake() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurBars".to_owned());
        assert_eq!(
            "Hello, porteur_bars",
            bars()
                .template_render("Hello, {{snake name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_lower() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "PORTEURBARS".to_owned());
        assert_eq!(
            "Hello, porteurbars",
            bars()
                .template_render("Hello, {{lower name}}", &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_eq() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "foo".to_owned());
        assert_eq!(
            "Hello, you",
            bars()
                .template_render(r#"Hello, {{#eq name "foo"}}you{{/eq}}"#, &map)
                .unwrap()
        );
    }

    #[test]
    fn bars_neq() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "bar".to_owned());
        assert_eq!(
            "Hello, bar",
            bars()
                .template_render(
                    r#"Hello, {{#eq name "foo"}}you{{else}}bar{{/eq}}"#,
                    &map,
                )
                .unwrap()
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub fn get_trigrams_with_positions(text : &String) -> HashMap<String, u32> {
    let counter_hash = count(text);

    let mut count_vec: Vec<_> = counter_hash.iter().collect();
    count_vec.sort_by_key(|key| key.1 );
    count_vec.reverse();

    let mut result: HashMap<String, u32> = HashMap::new();

    // TODO: extract 600 as LANG_PROFILE_LENGTH * 2
    for (i, trigram) in count_vec.iter().take(600).map(|x| x.0).enumerate() {
        // TODO: find a way not to clone it
        result.insert((*trigram).clone(), i as u32);
    }

    result
}

#[inline(always)]
fn count(text : &String) -> HashMap<String, u32> {
    let mut s = text.to_lowercase();
    s.push(' '); // add space to the end

    let mut counter_hash : HashMap<String, u32> = HashMap::new();

    // iterate through the string and count trigrams
    let mut chars_iter = s.chars();
    let mut c1 = ' ';
    let mut c2 = to_trigram_char(chars_iter.next().unwrap());
    for cur_char in chars_iter {
        let c3 = to_trigram_char(cur_char);
        if !((c1 == ' ' && c2 == ' ') || (c2 == ' ' && c3 == ' ')) {
            let mut trigram = String::with_capacity(3);
            trigram.push(c1);
            trigram.push(c2);
            trigram.push(c3);
            let count = counter_hash.entry(trigram).or_insert(0);
            *count += 1;
        }
        c1 = c2;
        c2 = c3;
    }

    counter_hash
}

// Convert punctuations and digits to a space.
#[inline(always)]
fn to_trigram_char(ch : char) -> char {
    match ch {
        '\u{0000}'...'\u{0040}' | '\u{005B}'...'\u{0060}' | '\u{007B}'...'\u{007E}' => ' ',
        _ => ch
    }
}

#[cfg(test)]
mod tests {
    use super::to_trigram_char;
    use super::count;
    use super::get_trigrams_with_positions;

    fn assert_valuable_trigram_chars(chars : &[char]) {
        for &ch in chars.iter() {
            assert_eq!(to_trigram_char(ch), ch);
        }
    }

    fn assert_not_valuable_trigram_chars(chars : &[char]) {
        for &ch in chars.iter() {
            assert_eq!(to_trigram_char(ch), ' ');
        }
    }

    #[test]
    fn test_to_trigram_char() {
        // valuable chars, that metters
        assert_valuable_trigram_chars(&['a', 'z', 'A', 'Z', 'Ж', 'ß']);

        // punctuations, digits, etc..
        //
        // 0x00 - 0x40
        assert_not_valuable_trigram_chars(&['\t', '\n', ' ', '.', '0', '9', ',', '@']);
        // 0x5B - 0x60
        assert_not_valuable_trigram_chars(&['[', ']', '^', '\\', '`']);
        // 0x7B - 0x7E
        assert_not_valuable_trigram_chars(&['[', '|', '{', '}', '~']);
    }

    fn assert_count(text : &str, pairs : &[(&str, u32)]) {
        let result = count(&text.to_string());
        for &(k, v) in pairs.iter() {
            let &actual_val = result.get(k).unwrap_or(&0);
            assert_eq!(actual_val, v, "trigram '{}' expected to occur {} times, got {}", k, v, actual_val);
        }
        assert_eq!(result.len(), pairs.len());
    }

    #[test]
    fn test_count() {
        assert_count("", &[]);
        assert_count(",", &[]);
        assert_count("a", &[(" a ", 1)]);
        assert_count("-a-", &[(" a ", 1)]);
        assert_count("yes", &[(" ye", 1), ("yes", 1), ("es ", 1)]);
        assert_count("Give - IT...", &[(" gi", 1), ("giv", 1), ("ive", 1), ("ve ", 1), (" it", 1), ("it ", 1)]);
    }

    #[test]
    fn test_get_trigrams_with_positions() {
        let res = get_trigrams_with_positions(&"xaaaaabbbbd".to_string());
        assert_eq!(*res.get("aaa").unwrap(), 0);
        assert_eq!(*res.get("bbb").unwrap(), 1);
    }
}
<commit_msg>Improve boolean expression<commit_after>use std::collections::HashMap;

pub fn get_trigrams_with_positions(text : &String) -> HashMap<String, u32> {
    let counter_hash = count(text);

    let mut count_vec: Vec<_> = counter_hash.iter().collect();
    count_vec.sort_by_key(|key| key.1 );
    count_vec.reverse();

    let mut result: HashMap<String, u32> = HashMap::new();

    // TODO: extract 600 as LANG_PROFILE_LENGTH * 2
    for (i, trigram) in count_vec.iter().take(600).map(|x| x.0).enumerate() {
        // TODO: find a way not to clone it
        result.insert((*trigram).clone(), i as u32);
    }

    result
}

#[inline(always)]
fn count(text : &String) -> HashMap<String, u32> {
    let mut s = text.to_lowercase();
    s.push(' '); // add space to the end

    let mut counter_hash : HashMap<String, u32> = HashMap::new();

    // iterate through the string and count trigrams
    let mut chars_iter = s.chars();
    let mut c1 = ' ';
    let mut c2 = to_trigram_char(chars_iter.next().unwrap());
    for cur_char in chars_iter {
        let c3 = to_trigram_char(cur_char);
        if !(c2 == ' ' && (c1 == ' ' || c3 == ' ')) {
            let mut trigram = String::with_capacity(3);
            trigram.push(c1);
            trigram.push(c2);
            trigram.push(c3);
            let count = counter_hash.entry(trigram).or_insert(0);
            *count += 1;
        }
        c1 = c2;
        c2 = c3;
    }

    counter_hash
}

// Convert punctuations and digits to a space.
#[inline(always)]
fn to_trigram_char(ch : char) -> char {
    match ch {
        '\u{0000}'...'\u{0040}' | '\u{005B}'...'\u{0060}' | '\u{007B}'...'\u{007E}' => ' ',
        _ => ch
    }
}

#[cfg(test)]
mod tests {
    use super::to_trigram_char;
    use super::count;
    use super::get_trigrams_with_positions;

    fn assert_valuable_trigram_chars(chars : &[char]) {
        for &ch in chars.iter() {
            assert_eq!(to_trigram_char(ch), ch);
        }
    }

    fn assert_not_valuable_trigram_chars(chars : &[char]) {
        for &ch in chars.iter() {
            assert_eq!(to_trigram_char(ch), ' ');
        }
    }

    #[test]
    fn test_to_trigram_char() {
        // valuable chars, that metters
        assert_valuable_trigram_chars(&['a', 'z', 'A', 'Z', 'Ж', 'ß']);

        // punctuations, digits, etc..
        //
        // 0x00 - 0x40
        assert_not_valuable_trigram_chars(&['\t', '\n', ' ', '.', '0', '9', ',', '@']);
        // 0x5B - 0x60
        assert_not_valuable_trigram_chars(&['[', ']', '^', '\\', '`']);
        // 0x7B - 0x7E
        assert_not_valuable_trigram_chars(&['[', '|', '{', '}', '~']);
    }

    fn assert_count(text : &str, pairs : &[(&str, u32)]) {
        let result = count(&text.to_string());
        for &(k, v) in pairs.iter() {
            let &actual_val = result.get(k).unwrap_or(&0);
            assert_eq!(actual_val, v, "trigram '{}' expected to occur {} times, got {}", k, v, actual_val);
        }
        assert_eq!(result.len(), pairs.len());
    }

    #[test]
    fn test_count() {
        assert_count("", &[]);
        assert_count(",", &[]);
        assert_count("a", &[(" a ", 1)]);
        assert_count("-a-", &[(" a ", 1)]);
        assert_count("yes", &[(" ye", 1), ("yes", 1), ("es ", 1)]);
        assert_count("Give - IT...", &[(" gi", 1), ("giv", 1), ("ive", 1), ("ve ", 1), (" it", 1), ("it ", 1)]);
    }

    #[test]
    fn test_get_trigrams_with_positions() {
        let res = get_trigrams_with_positions(&"xaaaaabbbbd".to_string());
        assert_eq!(*res.get("aaa").unwrap(), 0);
        assert_eq!(*res.get("bbb").unwrap(), 1);
    }
}
<|endoftext|>


<commit_before>///! Utilities not directly related to parsing, lexing, or
///! language-manipulation.

/// Panic with a given message unless an expression evaluates to true.
///
/// ## Examples
/// ```should_fail
/// panic_unless!(1 + 1 == 2, "Math is broken.");
/// ```
#[macro_export]
macro_rules! panic_unless {
    ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
}

#[macro_use]
pub mod intrusive;

#[doc(hidden)]
macro_rules! impl_methods {
    ($body_macro:ident; $(,)*) => {};
    /* args: (&mut self) */
    ($body_macro:ident; $method:ident(&mut self) -> $ret:ty, $($rest: tt)*)
    => (fn $method(&mut self) -> $ret { $body_macro!($method; mut, self, ) }
        impl_methods!($body_macro; $($rest)*););

    /* args: (&mut self, ...) */
    ($body_macro:ident; $method:ident(&mut self, $($arg:ident: $typ:ty),+) -> $ret:ty, $($rest: tt)*)
        => (fn $method(&mut self, $($arg: $typ),+) -> $ret { $body_macro!($method; mut, self, $($arg),+) }
            impl_methods!($body_macro; $($rest)*););

    /* args: (&self) */
    ($body_macro:ident; $method:ident(&self) -> $ret:ty, $($rest: tt)*)
        => (fn $method(&self) -> $ret { $body_macro!($method; , self, ) }
            impl_methods!($body_macro; $($rest)*););

    /* args: (&self, ...) */
    ($body_macro:ident; $method:ident(&self, $($arg:ident: $typ:ty),+) -> $ret:ty, $($rest: tt)*)
        => (fn $method(&mut self, $($arg: $typ),+) -> $ret { $body_macro!($method; , self, $($arg),+) }
            impl_methods!($body_macro; $($rest)*););
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_for {
    ($tr:path, $what:path, $body_macro:ident, $($rest: tt)*) => (impl $tr for $what { impl_methods!($body_macro; $($rest)*); });
}
<commit_msg>util: remove extraneous `mut` on `impl_methods` macro<commit_after>///! Utilities not directly related to parsing, lexing, or
///! language-manipulation.

/// Panic with a given message unless an expression evaluates to true.
///
/// ## Examples
/// ```should_fail
/// panic_unless!(1 + 1 == 2, "Math is broken.");
/// ```
#[macro_export]
macro_rules! panic_unless {
    ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
}

#[macro_use]
pub mod intrusive;

#[doc(hidden)]
macro_rules! impl_methods {
    ($body_macro:ident; $(,)*) => {};
    /* args: (&mut self) */
    ($body_macro:ident; $method:ident(&mut self) -> $ret:ty, $($rest: tt)*)
    => (fn $method(&mut self) -> $ret { $body_macro!($method; mut, self, ) }
        impl_methods!($body_macro; $($rest)*););

    /* args: (&mut self, ...) */
    ($body_macro:ident; $method:ident(&mut self, $($arg:ident: $typ:ty),+) -> $ret:ty, $($rest: tt)*)
        => (fn $method(&mut self, $($arg: $typ),+) -> $ret { $body_macro!($method; mut, self, $($arg),+) }
            impl_methods!($body_macro; $($rest)*););

    /* args: (&self) */
    ($body_macro:ident; $method:ident(&self) -> $ret:ty, $($rest: tt)*)
        => (fn $method(&self) -> $ret { $body_macro!($method; , self, ) }
            impl_methods!($body_macro; $($rest)*););

    /* args: (&self, ...) */
    ($body_macro:ident; $method:ident(&self, $($arg:ident: $typ:ty),+) -> $ret:ty, $($rest: tt)*)
        => (fn $method(&self, $($arg: $typ),+) -> $ret { $body_macro!($method; , self, $($arg),+) }
            impl_methods!($body_macro; $($rest)*););
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_for {
    ($tr:path, $what:path, $body_macro:ident, $($rest: tt)*) => (impl $tr for $what { impl_methods!($body_macro; $($rest)*); });
}
<|endoftext|>


<commit_before>use state::{Selectable, Editable, Named};
use std::cmp;
use std::io::{stdout, Stdout, BufWriter, Write, Result};
use std::iter;
use termion::terminal_size;
use termion::input::MouseTerminal;
use termion::screen::AlternateScreen;
use termion::raw::{IntoRawMode, RawTerminal};
use termion::{clear, style, cursor, color};

pub struct View {
    stdout: BufWriter<MouseTerminal<AlternateScreen<RawTerminal<Stdout>>>>,
    message: Option<String>,
    is_prompt: bool,
    line_offset: u16,
}

const TAB_LENGTH: usize = 4;

impl View {
    pub fn new() -> Result<View> {
        Ok(View {
            stdout: BufWriter::new(MouseTerminal::from(AlternateScreen::from(stdout()
                                                                         .into_raw_mode()
                                                                         .unwrap()))),
               message: None,
               is_prompt: false,
               line_offset: 0,
           })
    }

    pub fn message(&mut self, message: &str) {
        self.is_prompt = false;
        self.message = Some(String::from(message));
    }

    pub fn prompt(&mut self, prompt: &str, message: &str) {
        self.is_prompt = true;
        let msg = String::from(prompt) + message;
        self.message = Some(msg);
    }

    pub fn quiet(&mut self) {
        self.is_prompt = false;
        self.message = None;
    }

    pub fn center_view(&mut self, line: usize) {
        self.line_offset = match line.checked_sub(self.lines_height() as usize / 2) {
            None => 0,
            Some(val) => val as u16,
        }
    }

    pub fn adjust_view(&mut self, line: usize) {
        let line = line as u16;
        if line < self.line_offset {
            self.line_offset = line;
        } else if line + 1 >= self.line_offset + self.lines_height() {
            self.line_offset = 1 + line - self.lines_height();
        }
    }

    pub fn scroll_view<T: Editable>(&mut self, offset: isize, content: &T) {
        self.line_offset = cmp::min(cmp::max((self.line_offset as isize) + offset, 0),
                                    (content.line_count() as isize) - 1) as
                           u16;
    }

    pub fn render<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Named + Selectable
    {
        write!(self.stdout, "{}", clear::All)?;
        self.paint_lines(content)?;
        self.paint_status(content)?;
        self.paint_message()?;
        self.paint_cursor(content)?;
        self.stdout.flush()?;
        Ok(())
    }

    pub fn translate_coordinates<T>(&self, content: &T, x: u16, y: u16) -> (usize, usize)
        where T: Editable
    {
        let line = cmp::min((y as isize + self.line_offset as isize - 1) as usize,
                            content.line_count() - 1);
        let visual_col = (cmp::max(0,
                                   x as isize -
                                   self.line_number_width(content.line_count()) as isize -
                                   2)) as usize;
        // find out if we clicked through a tab
        let col = content.iter_line(line)
            .scan(0, |state, x| {
                *state += if x == '\t' { TAB_LENGTH } else { 1 };
                Some(*state)
            })
            .take_while(|&x| x <= visual_col)
            .count();
        (line, col)
    }

    fn paint_message(&mut self) -> Result<()> {
        if let Some(ref message) = self.message {
            let y = self.lines_height() + 1;
            write!(self.stdout, "{}{}", cursor::Goto(1, 1 + y as u16), message)?;
            self.stdout.flush()?;
        }
        Ok(())
    }

    fn paint_cursor<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Selectable
    {
        // FIXME: don't print the cursor if off screen, though we should in the future for long
        // lines
        if (content.line() as u16) < self.line_offset ||
           content.line() as u16 >= self.line_offset + self.lines_height() ||
           content.col() as u16 >= self.lines_width(content.line_count()) ||
           content.sel().is_some() {
            write!(self.stdout, "{}", cursor::Hide)?;
            return Ok(());
        }

        // in the case of a prompt, the cursor should be drawn in the message line
        let (x, y) = if self.is_prompt {
            (self.message
                 .clone()
                 .unwrap()
                 .chars()
                 .count() as u16,
             self.lines_height() + 1)
        } else {
            let (a, b) = self.cursor_pos(content);
            (a as u16, b as u16)
        };
        try!(write!(self.stdout,
                    "{}{}",
                    cursor::Show,
                    cursor::Goto(1 + x, 1 + y)));
        Ok(())
    }

    fn paint_status<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Named
    {
        let line = content.line();
        let column = content.col();
        let line_count = content.line_count();
        let advance = ((line + 1) as f64 / line_count as f64 * 100.0).floor();

        let (screen_width, _) = terminal_size().unwrap();
        let empty_line = (0..screen_width).map(|_| ' ').collect::<String>();
        let y = self.lines_height() as u16;

        try!(write!(self.stdout,
                    "{}{}{}{}{}{}",
                    color::Fg(color::White),
                    style::Invert,
                    cursor::Goto(1, 1 + y),
                    empty_line,
                    cursor::Goto(1, 1 + y),
                    content.name()));

        let position_info = format!("{}% {}/{}: {}", advance, line + 1, line_count, column);
        let x = screen_width - position_info.len() as u16;
        try!(write!(self.stdout,
                    "{}{}{}",
                    cursor::Goto(1 + x, 1 + y),
                    position_info,
                    style::Reset));
        Ok(())
    }

    fn paint_lines<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Selectable
    {
        let line_offset = self.line_offset as usize;
        let lines_height = self.lines_height() as usize;
        let lines_width = self.lines_width(content.line_count()) as usize;
        let line_count = content.line_count();

        let line_start = self.line_number_width(line_count) + 1;

        let mut chars = content.line_index_to_char_index(line_offset);
        for y in 0..cmp::min(lines_height, line_count - line_offset) {
            let line = y + line_offset;
            try!(write!(self.stdout,
                        "{}{}{}{}{}",
                        color::Fg(color::White),
                        cursor::Goto(1, 1 + y as u16),
                        1 + line,
                        style::Reset,
                        cursor::Goto(1 + line_start, 1 + y as u16)));

            let mut line_len: usize = 0;
            for c in content.iter_line(line).take_while(|&x| x != '\n') {
                if line_len > lines_width - 1 {
                    // do nothing but count
                    chars += 1;
                    line_len += 1;
                } else {
                    if content.in_sel(chars) {
                        write!(self.stdout, "{}", style::Invert)?;
                    }
                    if c == '\t' {
                        try!(write!(self.stdout,
                                    "{}",
                                    iter::repeat(" ").take(TAB_LENGTH).collect::<String>()));
                        line_len += TAB_LENGTH;
                    } else {
                        write!(self.stdout, "{}", c)?;
                        line_len += 1;
                    }
                    write!(self.stdout, "{}", style::Reset)?;
                    chars += 1;
                }
            }
            if line_len <= 1 && content.in_sel(chars) {
                write!(self.stdout, "{} {}", style::Invert, style::Reset)?;
            }
            chars += 1;
        }
        Ok(())
    }

    fn cursor_pos<T: Editable>(&self, content: &T) -> (usize, usize) {
        // TODO: column offsetting for long lines
        let line = content.line();
        let first_line = self.line_offset;
        let y = line - first_line as usize;
        // we can't trust the actual column because tabs have variable length
        let visual_col = content.col();
        let column = content.iter_line(line)
            .map(|x| if x == '\t' { TAB_LENGTH } else { 1 })
            .take(visual_col)
            .fold(0, |acc, x| acc + x);
        ((self.line_number_width(content.line_count()) as usize + 1 + column), y)
    }

    fn line_number_width(&self, line_count: usize) -> u16 {
        line_count.to_string().len() as u16
    }

    fn status_height(&self) -> u16 {
        2
    }

    pub fn lines_height(&self) -> u16 {
        let (_, screen_height) = terminal_size().unwrap();
        let incompressible = self.status_height();
        cmp::max(screen_height, incompressible) - incompressible
    }

    pub fn lines_width(&self, line_count: usize) -> u16 {
        let (screen_width, _) = terminal_size().unwrap();
        let incompressible = self.line_number_width(line_count) + 1;
        cmp::max(screen_width, incompressible) - incompressible
    }
}
<commit_msg>use ? instead of try!<commit_after>use state::{Selectable, Editable, Named};
use std::cmp;
use std::io::{stdout, Stdout, BufWriter, Write, Result};
use std::iter;
use termion::terminal_size;
use termion::input::MouseTerminal;
use termion::screen::AlternateScreen;
use termion::raw::{IntoRawMode, RawTerminal};
use termion::{clear, style, cursor, color};

pub struct View {
    stdout: BufWriter<MouseTerminal<AlternateScreen<RawTerminal<Stdout>>>>,
    message: Option<String>,
    is_prompt: bool,
    line_offset: u16,
}

const TAB_LENGTH: usize = 4;

impl View {
    pub fn new() -> Result<View> {
        Ok(View {
            stdout: BufWriter::new(MouseTerminal::from(AlternateScreen::from(stdout()
                                                                         .into_raw_mode()
                                                                         .unwrap()))),
               message: None,
               is_prompt: false,
               line_offset: 0,
           })
    }

    pub fn message(&mut self, message: &str) {
        self.is_prompt = false;
        self.message = Some(String::from(message));
    }

    pub fn prompt(&mut self, prompt: &str, message: &str) {
        self.is_prompt = true;
        let msg = String::from(prompt) + message;
        self.message = Some(msg);
    }

    pub fn quiet(&mut self) {
        self.is_prompt = false;
        self.message = None;
    }

    pub fn center_view(&mut self, line: usize) {
        self.line_offset = match line.checked_sub(self.lines_height() as usize / 2) {
            None => 0,
            Some(val) => val as u16,
        }
    }

    pub fn adjust_view(&mut self, line: usize) {
        let line = line as u16;
        if line < self.line_offset {
            self.line_offset = line;
        } else if line + 1 >= self.line_offset + self.lines_height() {
            self.line_offset = 1 + line - self.lines_height();
        }
    }

    pub fn scroll_view<T: Editable>(&mut self, offset: isize, content: &T) {
        self.line_offset = cmp::min(cmp::max((self.line_offset as isize) + offset, 0),
                                    (content.line_count() as isize) - 1) as
                           u16;
    }

    pub fn render<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Named + Selectable
    {
        write!(self.stdout, "{}", clear::All)?;
        self.paint_lines(content)?;
        self.paint_status(content)?;
        self.paint_message()?;
        self.paint_cursor(content)?;
        self.stdout.flush()?;
        Ok(())
    }

    pub fn translate_coordinates<T>(&self, content: &T, x: u16, y: u16) -> (usize, usize)
        where T: Editable
    {
        let line = cmp::min((y as isize + self.line_offset as isize - 1) as usize,
                            content.line_count() - 1);
        let visual_col = (cmp::max(0,
                                   x as isize -
                                   self.line_number_width(content.line_count()) as isize -
                                   2)) as usize;
        // find out if we clicked through a tab
        let col = content.iter_line(line)
            .scan(0, |state, x| {
                *state += if x == '\t' { TAB_LENGTH } else { 1 };
                Some(*state)
            })
            .take_while(|&x| x <= visual_col)
            .count();
        (line, col)
    }

    fn paint_message(&mut self) -> Result<()> {
        if let Some(ref message) = self.message {
            let y = self.lines_height() + 1;
            write!(self.stdout, "{}{}", cursor::Goto(1, 1 + y as u16), message)?;
            self.stdout.flush()?;
        }
        Ok(())
    }

    fn paint_cursor<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Selectable
    {
        // FIXME: don't print the cursor if off screen, though we should in the future for long
        // lines
        if (content.line() as u16) < self.line_offset ||
           content.line() as u16 >= self.line_offset + self.lines_height() ||
           content.col() as u16 >= self.lines_width(content.line_count()) ||
           content.sel().is_some() {
            write!(self.stdout, "{}", cursor::Hide)?;
            return Ok(());
        }

        // in the case of a prompt, the cursor should be drawn in the message line
        let (x, y) = if self.is_prompt {
            (self.message
                 .clone()
                 .unwrap()
                 .chars()
                 .count() as u16,
             self.lines_height() + 1)
        } else {
            let (a, b) = self.cursor_pos(content);
            (a as u16, b as u16)
        };
        write!(self.stdout,
               "{}{}",
               cursor::Show,
               cursor::Goto(1 + x, 1 + y))?;
        Ok(())
    }

    fn paint_status<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Named
    {
        let line = content.line();
        let column = content.col();
        let line_count = content.line_count();
        let advance = ((line + 1) as f64 / line_count as f64 * 100.0).floor();

        let (screen_width, _) = terminal_size().unwrap();
        let empty_line = (0..screen_width).map(|_| ' ').collect::<String>();
        let y = self.lines_height() as u16;

        write!(self.stdout,
               "{}{}{}{}{}{}",
               color::Fg(color::White),
               style::Invert,
               cursor::Goto(1, 1 + y),
               empty_line,
               cursor::Goto(1, 1 + y),
               content.name())?;

        let position_info = format!("{}% {}/{}: {}", advance, line + 1, line_count, column);
        let x = screen_width - position_info.len() as u16;
        write!(self.stdout,
               "{}{}{}",
               cursor::Goto(1 + x, 1 + y),
               position_info,
               style::Reset)?;
        Ok(())
    }

    fn paint_lines<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Selectable
    {
        let line_offset = self.line_offset as usize;
        let lines_height = self.lines_height() as usize;
        let lines_width = self.lines_width(content.line_count()) as usize;
        let line_count = content.line_count();

        let line_start = self.line_number_width(line_count) + 1;

        let mut chars = content.line_index_to_char_index(line_offset);
        for y in 0..cmp::min(lines_height, line_count - line_offset) {
            let line = y + line_offset;
            write!(self.stdout,
                   "{}{}{}{}{}",
                   color::Fg(color::White),
                   cursor::Goto(1, 1 + y as u16),
                   1 + line,
                   style::Reset,
                   cursor::Goto(1 + line_start, 1 + y as u16))?;

            let mut line_len: usize = 0;
            for c in content.iter_line(line).take_while(|&x| x != '\n') {
                if line_len > lines_width - 1 {
                    // do nothing but count
                    chars += 1;
                    line_len += 1;
                } else {
                    if content.in_sel(chars) {
                        write!(self.stdout, "{}", style::Invert)?;
                    }
                    if c == '\t' {
                        write!(self.stdout,
                               "{}",
                               iter::repeat(" ").take(TAB_LENGTH).collect::<String>())?;
                        line_len += TAB_LENGTH;
                    } else {
                        write!(self.stdout, "{}", c)?;
                        line_len += 1;
                    }
                    write!(self.stdout, "{}", style::Reset)?;
                    chars += 1;
                }
            }
            if line_len <= 1 && content.in_sel(chars) {
                write!(self.stdout, "{} {}", style::Invert, style::Reset)?;
            }
            chars += 1;
        }
        Ok(())
    }

    fn cursor_pos<T: Editable>(&self, content: &T) -> (usize, usize) {
        // TODO: column offsetting for long lines
        let line = content.line();
        let first_line = self.line_offset;
        let y = line - first_line as usize;
        // we can't trust the actual column because tabs have variable length
        let visual_col = content.col();
        let column = content.iter_line(line)
            .map(|x| if x == '\t' { TAB_LENGTH } else { 1 })
            .take(visual_col)
            .fold(0, |acc, x| acc + x);
        ((self.line_number_width(content.line_count()) as usize + 1 + column), y)
    }

    fn line_number_width(&self, line_count: usize) -> u16 {
        line_count.to_string().len() as u16
    }

    fn status_height(&self) -> u16 {
        2
    }

    pub fn lines_height(&self) -> u16 {
        let (_, screen_height) = terminal_size().unwrap();
        let incompressible = self.status_height();
        cmp::max(screen_height, incompressible) - incompressible
    }

    pub fn lines_width(&self, line_count: usize) -> u16 {
        let (screen_width, _) = terminal_size().unwrap();
        let incompressible = self.line_number_width(line_count) + 1;
        cmp::max(screen_width, incompressible) - incompressible
    }
}
<|endoftext|>