<commit_before>//! Data types and utility function for units:
//! Implemet a poor man's unit type system for now...
//!
//! Maybe we can have s.th. like this (F#) for Rust: https://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure
//! Alternatively, see here:
//! https://www.reddit.com/r/rust/comments/37qut9/typesafe_userdefined_units_of_measure_for_rust/
//! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

macro_rules! init_unit {
    ($i:ident) => {
        #[derive(Debug,Clone,Copy)]
        pub struct $i(pub f64);

        impl PartialEq for $i {
            fn eq(self: &$i, &$i(rhs): &$i) -> bool {
                let $i(lhs) = *self;
                lhs == rhs
            }
        }

        impl Add for $i {
            type Output = $i;

            fn add(self: $i, $i(rhs): $i) -> $i {
                let $i(lhs) = self;
                $i(lhs + rhs)
            }
        }

        impl Sub for $i {
            type Output = $i;

            fn sub(self: $i, $i(rhs): $i) -> $i {
                let $i(lhs) = self;
                $i(lhs - rhs)
            }
        }

        impl Mul<f64> for $i {
            type Output = $i;

            fn mul(self: $i, rhs: f64) -> $i {
                let $i(lhs) = self;
                $i(lhs * rhs)
            }
        }

        impl Mul<$i> for f64 {
            type Output = $i;

            fn mul(self: f64, $i(rhs): $i) -> $i {
                $i(self * rhs)
            }
        }

        impl Div<f64> for $i {
            type Output = $i;

            fn div(self: $i, rhs: f64) -> $i {
                let $i(lhs) = self;
                $i(lhs / rhs)
            }
        }

        impl Div<$i> for $i {
            type Output = f64;

            fn div(self: $i, $i(rhs): $i) -> f64 {
                let $i(lhs) = self;
                lhs / rhs
            }
        }
    }
}

macro_rules! mul_div_unit {
    // $i1 * $i2 = $i3
    // $i2 * $i1 = $i3
    // $i1 = $i3 / $i2
    // $i2 = $i3 / $i1
    ($i1:ident, $i2:ident, $i3:ident) => {
        impl Mul<$i2> for $i1 {
            type Output = $i3;

            fn mul(self: $i1, $i2(rhs): $i2) -> $i3 {
                let $i1(lhs) = self;
                $i3(lhs * rhs)
            }
        }

        impl Mul<$i1> for $i2 {
            type Output = $i3;

            fn mul(self: $i2, $i1(rhs): $i1) -> $i3 {
                let $i2(lhs) = self;
                $i3(lhs * rhs)
            }
        }

        impl Div<$i2> for $i3 {
            type Output = $i1;

            fn div(self: $i3, $i2(rhs): $i2) -> $i1 {
                let $i3(lhs) = self;
                $i1(lhs / rhs)
            }
        }

        impl Div<$i1> for $i3 {
            type Output = $i2;

            fn div(self: $i3, $i1(rhs): $i1) -> $i2 {
                let $i3(lhs) = self;
                $i2(lhs / rhs)
            }
        }
    };

    // $i1 * $i1 = $i2
    // $i1 = $i2 / $i1
    ($i1:ident, $i2:ident) => {
        impl Mul<$i1> for $i1 {
            type Output = $i2;

            fn mul(self: $i1, $i1(rhs): $i1) -> $i2 {
                let $i1(lhs) = self;
                $i2(lhs * rhs)
            }
        }

        impl Div<$i1> for $i2 {
            type Output = $i1;

            fn div(self: $i2, $i1(rhs): $i1) -> $i1 {
                let $i2(lhs) = self;
                $i1(lhs / rhs)
            }
        }
    }
}

macro_rules! inverse_unit {
    ($i1:ident, $i2:ident) => {
        // A * B = 1
        impl Mul<$i2> for $i1 {
            type Output = f64;

            fn mul(self: $i1, $i2(rhs): $i2) -> f64 {
                let $i1(lhs) = self;
                lhs * rhs
            }
        }

        // B * A = 1
        impl Mul<$i1> for $i2 {
            type Output = f64;

            fn mul(self: $i2, $i1(rhs): $i1) -> f64 {
                let $i2(lhs) = self;
                lhs * rhs
            }
        }

        // 1 / A = B
        impl Div<$i1> for f64 {
            type Output = $i2;

            fn div(self: f64, $i1(rhs): $i1) -> $i2 {
                $i2(self / rhs)
            }
        }

        // 1 / B = A
        impl Div<$i2> for f64 {
            type Output = $i1;

            fn div(self: f64, $i2(rhs): $i2) -> $i1 {
                $i1(self / rhs)
            }
        }
    }
}

init_unit!(Meter);
init_unit!(PerMeter);
inverse_unit!(Meter, PerMeter);

init_unit!(Meter2);
init_unit!(PerMeter2);
inverse_unit!(Meter2, PerMeter2);

init_unit!(Meter3);
init_unit!(PerMeter3);
inverse_unit!(Meter3, PerMeter3);

mul_div_unit!(Meter, Meter2);
mul_div_unit!(Meter, Meter2, Meter3);

mul_div_unit!(PerMeter, PerMeter2);
mul_div_unit!(PerMeter, PerMeter2, PerMeter3);

init_unit!(Second);
init_unit!(PerSecond);
inverse_unit!(Second, PerSecond);

init_unit!(Second2);
init_unit!(PerSecond2);
inverse_unit!(Second2, PerSecond2);

init_unit!(Second3);
init_unit!(PerSecond3);
inverse_unit!(Second3, PerSecond3);

mul_div_unit!(Second, Second2);
mul_div_unit!(Second, Second2, Second3);

mul_div_unit!(PerSecond, PerSecond2);
mul_div_unit!(PerSecond, PerSecond2, PerSecond3);

mul_div_unit!(Second, PerSecond2, PerSecond);

init_unit!(MeterPerSecond);
init_unit!(SecondPerMeter);
inverse_unit!(MeterPerSecond, SecondPerMeter);

mul_div_unit!(MeterPerSecond, Second, Meter);
mul_div_unit!(Meter, PerSecond, MeterPerSecond);
mul_div_unit!(MeterPerSecond, PerMeter, PerSecond);

mul_div_unit!(SecondPerMeter, Meter, Second);
mul_div_unit!(Second, PerMeter, SecondPerMeter);

init_unit!(MeterPerSecond2);
init_unit!(Second2PerMeter);
inverse_unit!(MeterPerSecond2, Second2PerMeter);

mul_div_unit!(MeterPerSecond2, Second, MeterPerSecond);
mul_div_unit!(MeterPerSecond2, Second2, Meter);
mul_div_unit!(MeterPerSecond, PerSecond, MeterPerSecond2);

init_unit!(Meter2PerSecond);
init_unit!(SecondPerMeter2);
inverse_unit!(Meter2PerSecond, SecondPerMeter2);

mul_div_unit!(MeterPerSecond, Meter, Meter2PerSecond);
mul_div_unit!(Meter2, PerSecond, Meter2PerSecond);
mul_div_unit!(Meter2PerSecond, PerMeter, MeterPerSecond);

init_unit!(Meter2PerSecond2);
init_unit!(Second2PerMeter2);
inverse_unit!(Meter2PerSecond2, Second2PerMeter2);

mul_div_unit!(Meter2PerSecond2, Second, Meter2PerSecond);
mul_div_unit!(Meter2PerSecond2, Second2, Meter2);
mul_div_unit!(MeterPerSecond, Meter2PerSecond2);

init_unit!(Meter2Second);
init_unit!(PerMeter2Second);
inverse_unit!(Meter2Second, PerMeter2Second);

mul_div_unit!(Meter2, Second, Meter2Second);
mul_div_unit!(PerSecond2, Meter2Second, Meter2PerSecond);

init_unit!(Kilogram);
init_unit!(PerKilogram);
inverse_unit!(Kilogram, PerKilogram);

init_unit!(KilogramMeterPerSecond); // momentum, impulse
init_unit!(SecondPerKilogramMeter);
inverse_unit!(KilogramMeterPerSecond, SecondPerKilogramMeter);

mul_div_unit!(Kilogram, MeterPerSecond, KilogramMeterPerSecond);

init_unit!(Newton);
init_unit!(PerNewton);
inverse_unit!(Newton, PerNewton);

mul_div_unit!(Kilogram, MeterPerSecond2, Newton);
mul_div_unit!(Newton, Second, KilogramMeterPerSecond);

init_unit!(Pascal);
init_unit!(PerPascal);
inverse_unit!(Pascal, PerPascal);

mul_div_unit!(Pascal, Meter2, Newton);

init_unit!(Joule);
init_unit!(PerJoule);
inverse_unit!(Joule, PerJoule);

mul_div_unit!(Joule, Meter, Newton);

init_unit!(Watt);
init_unit!(PerWatt);
inverse_unit!(Watt, PerWatt);

mul_div_unit!(Watt, Second, Joule);

init_unit!(DegC);
init_unit!(PerDegC);
inverse_unit!(DegC, PerDegC);

init_unit!(Kelvin);
init_unit!(PerKelvin);
inverse_unit!(Kelvin, PerKelvin);

init_unit!(Kelvin2);
init_unit!(PerKelvin2);
inverse_unit!(Kelvin2, PerKelvin2);

mul_div_unit!(Kelvin, Kelvin2);

init_unit!(KelvinPerSecond);
init_unit!(SecondPerKelvin);
inverse_unit!(KelvinPerSecond, SecondPerKelvin);

mul_div_unit!(KelvinPerSecond, Second, Kelvin);

init_unit!(DegCPerSecond);
init_unit!(SecondPerDegC);
inverse_unit!(DegCPerSecond, SecondPerDegC);

mul_div_unit!(DegCPerSecond, Second, DegC);

init_unit!(JouleDegCPerSecond);

mul_div_unit!(DegCPerSecond, Joule, JouleDegCPerSecond);

init_unit!(JouleKelvinPerSecond);

mul_div_unit!(KelvinPerSecond, Joule, JouleKelvinPerSecond);

init_unit!(Mol);
init_unit!(PerMol);
inverse_unit!(Mol, PerMol);

init_unit!(JoulePerKelvin);
init_unit!(KelvinPerJoule);
inverse_unit!(JoulePerKelvin, KelvinPerJoule);

init_unit!(JoulePerMol);
init_unit!(MolPerJoule);
inverse_unit!(JoulePerMol, MolPerJoule);

init_unit!(JoulePerKelvinMol);
init_unit!(KelvinMolPerJoule);
inverse_unit!(JoulePerKelvinMol, KelvinMolPerJoule);

init_unit!(JouleKelvinPerMol);
init_unit!(MolPerJouleKelvin);
inverse_unit!(JouleKelvinPerMol, MolPerJouleKelvin);

mul_div_unit!(JoulePerKelvinMol, Kelvin2, JouleKelvinPerMol);

init_unit!(SecondPerMol);
init_unit!(MolPerSecond);
inverse_unit!(SecondPerMol, MolPerSecond);

mul_div_unit!(SecondPerMol, JouleKelvinPerSecond, JouleKelvinPerMol);

mul_div_unit!(Mol, SecondPerMol, Second);

mul_div_unit!(Mol, JoulePerKelvinMol, JoulePerKelvin);

mul_div_unit!(Kelvin, JoulePerKelvin, Joule);
<commit_msg>refactoring, use helper macro<commit_after>//! Data types and utility function for units:
//! Implemet a poor man's unit type system for now...
//!
//! Maybe we can have s.th. like this (F#) for Rust: https://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure
//! Alternatively, see here:
//! https://www.reddit.com/r/rust/comments/37qut9/typesafe_userdefined_units_of_measure_for_rust/
//! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

macro_rules! init_unit {
    ($unit:ident) => {
        #[derive(Debug,Clone,Copy)]
        pub struct $unit(pub f64);

        impl PartialEq for $unit {
            fn eq(self: &$unit, &$unit(rhs): &$unit) -> bool {
                let $unit(lhs) = *self;
                lhs == rhs
            }
        }

        impl Add for $unit {
            type Output = $unit;

            fn add(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs + rhs)
            }
        }

        impl Sub for $unit {
            type Output = $unit;

            fn sub(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs - rhs)
            }
        }

        impl Mul<f64> for $unit {
            type Output = $unit;

            fn mul(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs * rhs)
            }
        }

        impl Mul<$unit> for f64 {
            type Output = $unit;

            fn mul(self: f64, $unit(rhs): $unit) -> $unit {
                $unit(self * rhs)
            }
        }

        impl Div<f64> for $unit {
            type Output = $unit;

            fn div(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs / rhs)
            }
        }

        impl Div<$unit> for $unit {
            type Output = f64;

            fn div(self: $unit, $unit(rhs): $unit) -> f64 {
                let $unit(lhs) = self;
                lhs / rhs
            }
        }
    }
}

macro_rules! mul_div_unit {
    // $unit1 * $unit2 = $unit3
    // $unit2 * $unit1 = $unit3
    // $unit1 = $unit3 / $unit2
    // $unit2 = $unit3 / $unit1
    ($unit1:ident, $unit2:ident, $unit3:ident) => {
        impl Mul<$unit2> for $unit1 {
            type Output = $unit3;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> $unit3 {
                let $unit1(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Mul<$unit1> for $unit2 {
            type Output = $unit3;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> $unit3 {
                let $unit2(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Div<$unit2> for $unit3 {
            type Output = $unit1;

            fn div(self: $unit3, $unit2(rhs): $unit2) -> $unit1 {
                let $unit3(lhs) = self;
                $unit1(lhs / rhs)
            }
        }

        impl Div<$unit1> for $unit3 {
            type Output = $unit2;

            fn div(self: $unit3, $unit1(rhs): $unit1) -> $unit2 {
                let $unit3(lhs) = self;
                $unit2(lhs / rhs)
            }
        }
    };

    // $unit1 * $unit1 = $unit2
    // $unit1 = $unit2 / $unit1
    ($unit1:ident, $unit2:ident) => {
        impl Mul<$unit1> for $unit1 {
            type Output = $unit2;

            fn mul(self: $unit1, $unit1(rhs): $unit1) -> $unit2 {
                let $unit1(lhs) = self;
                $unit2(lhs * rhs)
            }
        }

        impl Div<$unit1> for $unit2 {
            type Output = $unit1;

            fn div(self: $unit2, $unit1(rhs): $unit1) -> $unit1 {
                let $unit2(lhs) = self;
                $unit1(lhs / rhs)
            }
        }
    }
}

macro_rules! inverse_unit {
    ($unit1:ident, $unit2:ident) => {
        // A * B = 1
        impl Mul<$unit2> for $unit1 {
            type Output = f64;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> f64 {
                let $unit1(lhs) = self;
                lhs * rhs
            }
        }

        // B * A = 1
        impl Mul<$unit1> for $unit2 {
            type Output = f64;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> f64 {
                let $unit2(lhs) = self;
                lhs * rhs
            }
        }

        // 1 / A = B
        impl Div<$unit1> for f64 {
            type Output = $unit2;

            fn div(self: f64, $unit1(rhs): $unit1) -> $unit2 {
                $unit2(self / rhs)
            }
        }

        // 1 / B = A
        impl Div<$unit2> for f64 {
            type Output = $unit1;

            fn div(self: f64, $unit2(rhs): $unit2) -> $unit1 {
                $unit1(self / rhs)
            }
        }
    }
}

macro_rules! init_unit_and_inverse {
    ($unit1:ident, $per_unit1:ident) => {
        init_unit!($unit1);
        init_unit!($per_unit1);
        inverse_unit!($unit1, $per_unit1);
    }
}

init_unit_and_inverse!(Meter, PerMeter);

init_unit_and_inverse!(Meter2, PerMeter2);

init_unit_and_inverse!(Meter3, PerMeter3);

mul_div_unit!(Meter, Meter2);
mul_div_unit!(Meter, Meter2, Meter3);

mul_div_unit!(PerMeter, PerMeter2);
mul_div_unit!(PerMeter, PerMeter2, PerMeter3);

init_unit_and_inverse!(Second, PerSecond);

init_unit_and_inverse!(Second2, PerSecond2);

init_unit_and_inverse!(Second3, PerSecond3);

mul_div_unit!(Second, Second2);
mul_div_unit!(Second, Second2, Second3);

mul_div_unit!(PerSecond, PerSecond2);
mul_div_unit!(PerSecond, PerSecond2, PerSecond3);

mul_div_unit!(Second, PerSecond2, PerSecond);

init_unit_and_inverse!(MeterPerSecond, SecondPerMeter);

mul_div_unit!(MeterPerSecond, Second, Meter);
mul_div_unit!(Meter, PerSecond, MeterPerSecond);
mul_div_unit!(MeterPerSecond, PerMeter, PerSecond);

mul_div_unit!(SecondPerMeter, Meter, Second);
mul_div_unit!(Second, PerMeter, SecondPerMeter);

init_unit_and_inverse!(MeterPerSecond2, Second2PerMeter);

mul_div_unit!(MeterPerSecond2, Second, MeterPerSecond);
mul_div_unit!(MeterPerSecond2, Second2, Meter);
mul_div_unit!(MeterPerSecond, PerSecond, MeterPerSecond2);

init_unit_and_inverse!(Meter2PerSecond, SecondPerMeter2);

mul_div_unit!(MeterPerSecond, Meter, Meter2PerSecond);
mul_div_unit!(Meter2, PerSecond, Meter2PerSecond);
mul_div_unit!(Meter2PerSecond, PerMeter, MeterPerSecond);

init_unit_and_inverse!(Meter2PerSecond2, Second2PerMeter2);

mul_div_unit!(Meter2PerSecond2, Second, Meter2PerSecond);
mul_div_unit!(Meter2PerSecond2, Second2, Meter2);
mul_div_unit!(MeterPerSecond, Meter2PerSecond2);

init_unit_and_inverse!(Meter2Second, PerMeter2Second);

mul_div_unit!(Meter2, Second, Meter2Second);
mul_div_unit!(PerSecond2, Meter2Second, Meter2PerSecond);

init_unit_and_inverse!(Kilogram, PerKilogram);

 // momentum, impulse
init_unit_and_inverse!(KilogramMeterPerSecond, SecondPerKilogramMeter);

mul_div_unit!(Kilogram, MeterPerSecond, KilogramMeterPerSecond);

init_unit_and_inverse!(Newton, PerNewton);

mul_div_unit!(Kilogram, MeterPerSecond2, Newton);
mul_div_unit!(Newton, Second, KilogramMeterPerSecond);

init_unit_and_inverse!(Pascal, PerPascal);

mul_div_unit!(Pascal, Meter2, Newton);

init_unit_and_inverse!(Joule, PerJoule);

mul_div_unit!(Joule, Meter, Newton);

init_unit_and_inverse!(Watt, PerWatt);

mul_div_unit!(Watt, Second, Joule);

init_unit_and_inverse!(DegC, PerDegC);

init_unit_and_inverse!(Kelvin, PerKelvin);

init_unit_and_inverse!(Kelvin2, PerKelvin2);

mul_div_unit!(Kelvin, Kelvin2);

init_unit_and_inverse!(KelvinPerSecond, SecondPerKelvin);

mul_div_unit!(KelvinPerSecond, Second, Kelvin);

init_unit_and_inverse!(DegCPerSecond, SecondPerDegC);

mul_div_unit!(DegCPerSecond, Second, DegC);

init_unit!(JouleDegCPerSecond);

mul_div_unit!(DegCPerSecond, Joule, JouleDegCPerSecond);

init_unit!(JouleKelvinPerSecond);

mul_div_unit!(KelvinPerSecond, Joule, JouleKelvinPerSecond);

init_unit_and_inverse!(Mol, PerMol);

init_unit_and_inverse!(JoulePerKelvin, KelvinPerJoule);

init_unit_and_inverse!(JoulePerMol, MolPerJoule);

init_unit_and_inverse!(JoulePerKelvinMol, KelvinMolPerJoule);

init_unit_and_inverse!(JouleKelvinPerMol, MolPerJouleKelvin);

mul_div_unit!(JoulePerKelvinMol, Kelvin2, JouleKelvinPerMol);

init_unit_and_inverse!(SecondPerMol, MolPerSecond);

mul_div_unit!(SecondPerMol, JouleKelvinPerSecond, JouleKelvinPerMol);

mul_div_unit!(Mol, SecondPerMol, Second);

mul_div_unit!(Mol, JoulePerKelvinMol, JoulePerKelvin);

mul_div_unit!(Kelvin, JoulePerKelvin, Joule);
<|endoftext|>


<commit_before>use action;
use settings;
use glfw;
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use piston::gl::Gl;
use graphics;
use graphics::*;
use object;
use Object = object::Object;
use text;

pub struct SnakeApp {
    settings: Settings,
    // Tells where the surface is.
    surface_y: Option<f64>,
    player_index: Option<uint>,
    blood_bar_index: Option<uint>,
    // Contains the game objects.
    objects: Vec<Object>,
}

impl Game for SnakeApp {
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }

    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        for obj in self.objects.iter() {
            obj.render(c, gl);
        }
    }

    fn update(&mut self, dt: f64) {
        if self.player_index == None { return; }

        // Update states of objects.
        let player_index = self.player_index.unwrap();
        let player_pos = self.objects.get(player_index).pos;
        let mut attack_damage: f64 = 0.0;
        for obj in self.objects.mut_iter() {
            match obj.update(dt, player_pos) {
                action::Passive => {},
                action::Attack(attack) => { attack_damage += attack; },
            }
        }

        // Decrease the players life with attacks.
        *self.objects.get_mut(player_index).blood_mut().unwrap() -= attack_damage;

        if self.blood_bar_index == None { return; }

        // Show blood.
        let player_blood = self.objects.get(player_index).blood().unwrap();
        let blood_bar_index = self.blood_bar_index.unwrap();
        let blood_bar = self.objects.get_mut(blood_bar_index);
        match blood_bar.data {
            object::BarData(ref mut bar) => {
                bar.value = player_blood;
            },
            _ => {},
        }
    }

    fn load(&mut self) {
        self.surface_y = Some(settings::SURFACE_Y);

        // Add player.
        self.objects.push(Object::player(
            settings::ORIGIN,
            settings::BLUE,
            settings::PLAYER_INITIAL_BLOOD,
            [settings::PLAYER_SPEED_LEFT, settings::PLAYER_SPEED_RIGHT],
            [settings::PLAYER_SPEED_UP, settings::PLAYER_SPEED_DOWN]
        ));
        self.player_index = Some(0);

        // Add blood and air bar.
        self.add_bars();

        // Add sharks.
        self.add_sharks();
    }

    fn key_press(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key pressed {}", key);

        match (key, self.player_index) {
            (glfw::KeyRight, Some(player_index)) => {
                self.objects.get_mut(player_index).move_right();
            },
            (glfw::KeyUp, Some(player_index)) => {
                self.objects.get_mut(player_index).move_up();
            },
            (glfw::KeyLeft, Some(player_index)) => {
                self.objects.get_mut(player_index).move_left();
            },
            (glfw::KeyDown, Some(player_index)) => {
                self.objects.get_mut(player_index).move_down();
            },
            _ => {},
        }
    }

    fn key_release(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key released {}", key);
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            settings: Settings::new(exit_on_esc, background_color),
            surface_y: None,
            objects: Vec::new(),
            player_index: None,
            blood_bar_index: None,
        }
    }

    pub fn add_bars(&mut self) {
        self.objects.push(Object::bar(
            settings::AIR_BAR_POS,
            "air",
            settings::AIR_BAR_TEXT_COLOR,
            settings::AIR_BAR_BACKGROUND_COLOR,
            settings::AIR_BAR_BAR_COLOR,
            settings::AIR_BAR_INITIAL_VALUE
        ));
        self.objects.push(Object::bar(
            settings::BLOOD_BAR_POS,
            "blood",
            settings::BLOOD_BAR_TEXT_COLOR,
            settings::BLOOD_BAR_BACKGROUND_COLOR,
            settings::BLOOD_BAR_BAR_COLOR,
            settings::BLOOD_BAR_INITIAL_VALUE
        ));
        self.blood_bar_index = Some(self.objects.len() - 1);
    }

    pub fn add_sharks(&mut self) {
        self.objects.push(Object::shark(settings::SHARK_1_POS, settings::SHARK_1_SETTINGS));
    }
}

<commit_msg>Added `game_state` field<commit_after>use action;
use settings;
use glfw;
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use piston::gl::Gl;
use graphics;
use graphics::*;
use object;
use Object = object::Object;
use text;
use game_state;

pub struct SnakeApp {
    settings: Settings,
    // Tells where the surface is.
    surface_y: Option<f64>,
    game_state: Option<game_state::GameState>,
    player_index: Option<uint>,
    blood_bar_index: Option<uint>,
    // Contains the game objects.
    objects: Vec<Object>,
}

impl Game for SnakeApp {
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }

    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        for obj in self.objects.iter() {
            obj.render(c, gl);
        }
    }

    fn update(&mut self, dt: f64) {
        if self.player_index == None { return; }

        // Update states of objects.
        let player_index = self.player_index.unwrap();
        let player_pos = self.objects.get(player_index).pos;
        let mut attack_damage: f64 = 0.0;
        for obj in self.objects.mut_iter() {
            match obj.update(dt, player_pos) {
                action::Passive => {},
                action::Attack(attack) => { attack_damage += attack; },
            }
        }

        // Decrease the players life with attacks.
        *self.objects.get_mut(player_index).blood_mut().unwrap() -= attack_damage;

        if self.blood_bar_index == None { return; }

        // Show blood.
        let player_blood = self.objects.get(player_index).blood().unwrap();
        let blood_bar_index = self.blood_bar_index.unwrap();
        let blood_bar = self.objects.get_mut(blood_bar_index);
        match blood_bar.data {
            object::BarData(ref mut bar) => {
                bar.value = player_blood;
            },
            _ => {},
        }
    }

    fn load(&mut self) {
        self.surface_y = Some(settings::SURFACE_Y);
        self.game_state = Some(game_state::Play);

        // Add player.
        self.objects.push(Object::player(
            settings::ORIGIN,
            settings::BLUE,
            settings::PLAYER_INITIAL_BLOOD,
            [settings::PLAYER_SPEED_LEFT, settings::PLAYER_SPEED_RIGHT],
            [settings::PLAYER_SPEED_UP, settings::PLAYER_SPEED_DOWN]
        ));
        self.player_index = Some(0);

        // Add blood and air bar.
        self.add_bars();

        // Add sharks.
        self.add_sharks();
    }

    fn key_press(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key pressed {}", key);

        match (key, self.player_index) {
            (glfw::KeyRight, Some(player_index)) => {
                self.objects.get_mut(player_index).move_right();
            },
            (glfw::KeyUp, Some(player_index)) => {
                self.objects.get_mut(player_index).move_up();
            },
            (glfw::KeyLeft, Some(player_index)) => {
                self.objects.get_mut(player_index).move_left();
            },
            (glfw::KeyDown, Some(player_index)) => {
                self.objects.get_mut(player_index).move_down();
            },
            _ => {},
        }
    }

    fn key_release(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key released {}", key);
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            settings: Settings::new(exit_on_esc, background_color),
            game_state: None,
            surface_y: None,
            objects: Vec::new(),
            player_index: None,
            blood_bar_index: None,
        }
    }

    pub fn add_bars(&mut self) {
        self.objects.push(Object::bar(
            settings::AIR_BAR_POS,
            "air",
            settings::AIR_BAR_TEXT_COLOR,
            settings::AIR_BAR_BACKGROUND_COLOR,
            settings::AIR_BAR_BAR_COLOR,
            settings::AIR_BAR_INITIAL_VALUE
        ));
        self.objects.push(Object::bar(
            settings::BLOOD_BAR_POS,
            "blood",
            settings::BLOOD_BAR_TEXT_COLOR,
            settings::BLOOD_BAR_BACKGROUND_COLOR,
            settings::BLOOD_BAR_BAR_COLOR,
            settings::BLOOD_BAR_INITIAL_VALUE
        ));
        self.blood_bar_index = Some(self.objects.len() - 1);
    }

    pub fn add_sharks(&mut self) {
        self.objects.push(Object::shark(settings::SHARK_1_POS, settings::SHARK_1_SETTINGS));
    }
}

<|endoftext|>


<commit_before>use syntax::ast::*;
use rustc::lint::{Context, LintPass, LintArray, Lint};
use syntax::codemap::Span;
use syntax::visit::{Visitor, FnKind, walk_ty};
use utils::{in_macro, span_lint};
use std::collections::HashSet;
use std::iter::FromIterator;

declare_lint!(pub NEEDLESS_LIFETIMES, Warn,
              "Warn on explicit lifetimes when elision rules would apply");

#[derive(Copy,Clone)]
pub struct LifetimePass;

impl LintPass for LifetimePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_LIFETIMES)
    }

    fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl,
                _: &Block, span: Span, _: NodeId) {
        if cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro(cx, info)) {
            return;
        }
        if could_use_elision(kind, decl) {
            span_lint(cx, NEEDLESS_LIFETIMES, span,
                      "explicit lifetimes given where they could be inferred");
        }
    }
}

#[derive(PartialEq, Eq, Hash, Debug)]
enum RefLt {
    Unnamed,
    Static,
    Named(Name),
}
use self::RefLt::*;

fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool {
    // There are two scenarios where elision works:
    // * no output references, all input references have different LT
    // * output references, exactly one input reference with same LT

    let mut input_visitor = RefVisitor(Vec::new());
    let mut output_visitor = RefVisitor(Vec::new());

    // extract lifetimes of input argument types
    for arg in &func.inputs {
        walk_ty(&mut input_visitor, &*arg.ty);
    }
    // extract lifetime of "self" argument for methods
    if let FnKind::FkMethod(_, sig, _) = kind {
        match sig.explicit_self.node {
            SelfRegion(ref lt_opt, _, _) =>
                input_visitor.visit_opt_lifetime_ref(sig.explicit_self.span, lt_opt),
            SelfExplicit(ref ty, _) =>
                walk_ty(&mut input_visitor, ty),
            _ => { }
        }
    }
    // extract lifetimes of output type
    if let Return(ref ty) = func.output {
        walk_ty(&mut output_visitor, ty);
    }

    let input_lts = input_visitor.into_vec();
    let output_lts = output_visitor.into_vec();

    // no input lifetimes? easy case!
    if input_lts.is_empty() {
        return false;
    } else if output_lts.is_empty() {
        // no output lifetimes, check distinctness of input lifetimes

        // only one reference with unnamed lifetime, ok
        if input_lts.len() == 1 && input_lts[0] == Unnamed {
            return false;
        }
        // we have no output reference, so we only need all distinct lifetimes
        if input_lts.len() == unique_lifetimes(&input_lts) {
            return true;
        }
    } else {
        // we have output references, so we need one input reference,
        // and all output lifetimes must be the same
        if unique_lifetimes(&output_lts) > 1 {
            return false;
        }
        if input_lts.len() == 1 {
            match (&input_lts[0], &output_lts[0]) {
                (&Named(n1), &Named(n2)) if n1 == n2 => { return true; }
                (&Named(_), &Unnamed) => { return true; }
                (&Unnamed, &Named(_)) => { return true; }
                _ => { } // already elided, different named lifetimes
                         // or something static going on
            }
        }
    }
    false
}

fn unique_lifetimes(lts: &Vec<RefLt>) -> usize {
    let set: HashSet<&RefLt> = HashSet::from_iter(lts.iter());
    set.len()
}

struct RefVisitor(Vec<RefLt>);

impl RefVisitor {
    fn into_vec(self) -> Vec<RefLt> { self.0 }
}

impl<'v> Visitor<'v> for RefVisitor {
    fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) {
        if let &Some(ref lt) = lifetime {
            if lt.name.as_str() == "'static" {
                self.0.push(Static);
            } else {
                self.0.push(Named(lt.name));
            }
        } else {
            self.0.push(Unnamed);
        }
    }
}
<commit_msg>lifetimes lint: straighten some code, add a few comments<commit_after>use syntax::ast::*;
use rustc::lint::{Context, LintPass, LintArray, Lint};
use syntax::codemap::Span;
use syntax::visit::{Visitor, FnKind, walk_ty};
use utils::{in_external_macro, span_lint};
use std::collections::HashSet;
use std::iter::FromIterator;

declare_lint!(pub NEEDLESS_LIFETIMES, Warn,
              "Warn on explicit lifetimes when elision rules would apply");

#[derive(Copy,Clone)]
pub struct LifetimePass;

impl LintPass for LifetimePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_LIFETIMES)
    }

    fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl,
                _: &Block, span: Span, _: NodeId) {
        if in_external_macro(cx, span) {
            return;
        }
        if could_use_elision(kind, decl) {
            span_lint(cx, NEEDLESS_LIFETIMES, span,
                      "explicit lifetimes given in parameter types where they could be elided");
        }
    }
}

/// The lifetime of a &-reference.
#[derive(PartialEq, Eq, Hash, Debug)]
enum RefLt {
    Unnamed,
    Static,
    Named(Name),
}
use self::RefLt::*;

fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool {
    // There are two scenarios where elision works:
    // * no output references, all input references have different LT
    // * output references, exactly one input reference with same LT

    // these will collect all the lifetimes for references in arg/return types
    let mut input_visitor = RefVisitor(Vec::new());
    let mut output_visitor = RefVisitor(Vec::new());

    // extract lifetime in "self" argument for methods (there is a "self" argument
    // in func.inputs, but its type is TyInfer)
    if let FnKind::FkMethod(_, sig, _) = kind {
        match sig.explicit_self.node {
            SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt),
            SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty),
            _ => { }
        }
    }
    // extract lifetimes in input argument types
    for arg in &func.inputs {
        walk_ty(&mut input_visitor, &*arg.ty);
    }
    // extract lifetimes in output type
    if let Return(ref ty) = func.output {
        walk_ty(&mut output_visitor, ty);
    }

    let input_lts = input_visitor.into_vec();
    let output_lts = output_visitor.into_vec();

    // no input lifetimes? easy case!
    if input_lts.is_empty() {
        return false;
    } else if output_lts.is_empty() {
        // no output lifetimes, check distinctness of input lifetimes

        // only one reference with unnamed lifetime, ok
        if input_lts.len() == 1 && input_lts[0] == Unnamed {
            return false;
        }
        // we have no output reference, so we only need all distinct lifetimes
        if input_lts.len() == unique_lifetimes(&input_lts) {
            return true;
        }
    } else {
        // we have output references, so we need one input reference,
        // and all output lifetimes must be the same
        if unique_lifetimes(&output_lts) > 1 {
            return false;
        }
        if input_lts.len() == 1 {
            match (&input_lts[0], &output_lts[0]) {
                (&Named(n1), &Named(n2)) if n1 == n2 => { return true; }
                (&Named(_), &Unnamed) => { return true; }
                (&Unnamed, &Named(_)) => { return true; }
                _ => { } // already elided, different named lifetimes
                         // or something static going on
            }
        }
    }
    false
}

/// Number of unique lifetimes in the given vector.
fn unique_lifetimes(lts: &Vec<RefLt>) -> usize {
    lts.iter().collect::<HashSet<_>>().len()
}

/// A visitor usable for syntax::visit::walk_ty().
struct RefVisitor(Vec<RefLt>);

impl RefVisitor {
    fn record(&mut self, lifetime: &Option<Lifetime>) {
        if let &Some(ref lt) = lifetime {
            if lt.name.as_str() == "'static" {
                self.0.push(Static);
            } else {
                self.0.push(Named(lt.name));
            }
        } else {
            self.0.push(Unnamed);
        }
    }

    fn into_vec(self) -> Vec<RefLt> {
        self.0
    }
}

impl<'v> Visitor<'v> for RefVisitor {
    fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) {
        self.record(lifetime);
    }
}
<|endoftext|>


<commit_before>//! A single pod in a project.

use docker_compose::v2 as dc;
use docker_compose::v2::MergeOverride;
use std::collections::BTreeMap;
use std::collections::btree_map;
use std::ffi::OsString;
use std::path::{Path, PathBuf};

use ovr::Override;
use project::Project;
use util::Error;

/// Information about a `docker-compose.yml` file, including its path
/// relative to `base_dir` (`base_dir` is normally `$PROJECT/pods`), and
/// the normalized version of its contents:
///
/// 1. Any missing services will be explicitly added to an override file.
/// 2. The `env_file` list will be updated to contain the appropriate
///    `common.yml` file.
///
/// If this file doesn't actually exist on disk, we'll still fill in the
/// default contents as above.
///
/// If you need to process this further, clone the `File` and work on the
/// clone.  This is the master copy.
#[derive(Debug)]
struct FileInfo {
    rel_path: PathBuf,
    file: dc::File,
}

impl FileInfo {
    /// Create a `FileInfo` by either loading `base_dir.join(rel_path)` or
    /// by creating an empty `dc::File` in its place.  Do not perform
    /// normalization.
    fn unnormalized(base_dir: &Path, rel_path: &Path) -> Result<FileInfo, Error> {
        let path = base_dir.join(rel_path);
        Ok(FileInfo {
            rel_path: rel_path.to_owned(),
            file: if path.exists() {
                try!(dc::File::read_from_path(&path))
            } else {
                Default::default()
            },
        })
    }

    /// Make sure that all services from `base` are also present in this
    /// file.  If you're going tp call this, it must be called after
    /// `finish_normalization`
    fn ensure_all_services_from(&mut self, base: &dc::File) {
        for (name, _service) in base.services.iter() {
            self.file.services.entry(name.to_owned())
                .or_insert_with(Default::default);
        }
    }

    /// Finish normalizing this file by inserting things like `env_file`
    /// entries.
    fn finish_normalization(&mut self) {
        // It's safe to call `unwrap` here because we know `rel_path` should
        // have a parent directory.
        let env_path = self.rel_path.parent().unwrap().join("common.env");
        for (_name, service) in self.file.services.iter_mut() {
            service.env_files.insert(0, dc::value(env_path.clone()));
        }
    }
}

/// A pod, specified by `pods/$NAME.yml` and zero or more
/// `pods/overrides/*/*.yml` overrides that we can apply to it.
#[derive(Debug)]
pub struct Pod {
    /// All paths in any associated `dc::File` should be intepreted
    /// relative to this base, including paths in overlay files.
    base_dir: PathBuf,

    /// The name of this pod, based on the file `pods/$NAME.yml`.
    name: String,

    /// The top-level file defining this pod.
    file_info: FileInfo,

    /// The individual override files for this pod.  There will always be a
    /// sensible value here for each pod, even if the file doesn't exist on
    /// disk.
    override_file_infos: BTreeMap<Override, FileInfo>,
}

impl Pod {
    /// Create a new pod, specifying the base directory from which we'll load
    /// pod definitions and the name of the pod.
    #[doc(hidden)]
    pub fn new<P, S>(base_dir: P, name: S, overrides: &[Override]) ->
        Result<Pod, Error>
        where P: Into<PathBuf>, S: Into<String>
    {
        let base_dir = base_dir.into();
        let name = name.into();

        // Load our main `*.yml` file.
        let rel_path = Path::new(&format!("{}.yml", &name)).to_owned();
        let mut file_info = try!(FileInfo::unnormalized(&base_dir, &rel_path));
        file_info.finish_normalization();

        // Load our override `*.yml` files.
        let mut ovr_infos = BTreeMap::new();
        for ovr in overrides {
            let ovr_rel_path =
                Path::new(&format!("overrides/{}/{}.yml", ovr.name(), &name))
                    .to_owned();
            let mut ovr_info =
                try!(FileInfo::unnormalized(&base_dir, &ovr_rel_path));
            ovr_info.ensure_all_services_from(&file_info.file);
            ovr_info.finish_normalization();
            ovr_infos.insert(ovr.to_owned(), ovr_info);
        }

        Ok(Pod {
            base_dir: base_dir,
            name: name,
            file_info: file_info,
            override_file_infos: ovr_infos,
        })
    }

    /// Get the name of this pod.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// The base directory for our relative paths.
    pub fn base_dir(&self) -> &Path {
        &self.base_dir
    }

    /// The path to the top-level file defining this pod, relative to the
    /// `base_dir` specified at creation time.
    pub fn rel_path(&self) -> &Path {
        &self.file_info.rel_path
    }

    /// The top-level file defining this pod.  This is normalized to
    /// include the appropriate `env_file` entries, but if you want to do
    /// more complicated transformations, you'll need to clone it with
    /// `to_owned()` first.
    pub fn file(&self) -> &dc::File {
        &self.file_info.file
    }

    /// Look up the file info associated with an override, or return an
    /// error if this override was not specified for this `Pod` at creation
    /// time.
    fn override_file_info(&self, ovr: &Override) -> Result<&FileInfo, Error> {
        self.override_file_infos.get(ovr).ok_or_else(|| {
            err!("The override {} is not defined", ovr.name())
        })
    }

    /// The path to the specificied override file for this pod.
    pub fn override_rel_path(&self, ovr: &Override) -> Result<&Path, Error> {
        Ok(&(try!(self.override_file_info(ovr)).rel_path))
    }

    /// The `dc::File` for this override.
    pub fn override_file(&self, ovr: &Override) -> Result<&dc::File, Error> {
        Ok(&(try!(self.override_file_info(ovr)).file))
    }

    /// Return the base file and the override file merged into a single
    /// `docker-compose.yml` file.
    pub fn merged_file(&self, ovr: &Override) -> Result<dc::File, Error> {
        // This is expensive so log it.
        debug!("Merging pod {} with override {}", self.name(), ovr.name());
        Ok(self.file().merge_override(try!(self.override_file(ovr))))
    }

    /// All the overrides associated with this pod.
    pub fn override_files(&self) -> OverrideFiles {
        OverrideFiles { iter: self.override_file_infos.iter() }
    }

    /// Iterate over all `dc::File` objects associated with this pod, including
    /// both the main `file()` and all the files in `override_files()`.
    pub fn all_files(&self) -> AllFiles {
        // Defer all the hard work to our iterator type.
        AllFiles {
            pod: self,
            state: AllFilesState::TopLevelFile,
        }
    }

    /// Command-line `-p` and `-f` arguments that we'll pass to
    /// `docker-compose` to describe this file.
    pub fn compose_args(&self, proj: &Project, ovr: &Override) ->
        Result<Vec<OsString>, Error>
    {
        let ovr_rel_path = try!(self.override_rel_path(ovr));
        let compose_project_name = ovr.compose_project_name(proj);
        Ok(vec!("-p".into(), compose_project_name.into(),
                "-f".into(), proj.output_pods_dir().join(self.rel_path()).into(),
                "-f".into(), proj.output_pods_dir().join(ovr_rel_path).into()))
    }
}

/// An iterator over this pods overrides and their associated files.
pub struct OverrideFiles<'a> {
    iter: btree_map::Iter<'a, Override, FileInfo>,
}

impl<'a> Iterator for OverrideFiles<'a> {
    type Item = (&'a Override, &'a dc::File);

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(ovr, file_info)| (ovr, &file_info.file))
    }
}

/// What should we yield next from our AllFiles iterator?
enum AllFilesState<'a> {
    /// Yield the top-level `file()` next.
    TopLevelFile,
    /// Yield an item from this iterator next.
    OverrideFiles(OverrideFiles<'a>),
}

/// An iterator over all the `dc::File` objects associated with a pod, in
/// all overlays.
pub struct AllFiles<'a> {
    /// The pod whose files we're iterating over.
    pod: &'a Pod,
    /// Our current iteration state.
    state: AllFilesState<'a>,
}

impl<'a> Iterator for AllFiles<'a> {
    type Item = &'a dc::File;

    fn next(&mut self) -> Option<Self::Item> {
        // We could try to implement this by calling:
        //
        // ```
        // iter::once(pod.file())
        //     .chain(pod.override_files().map(|(_, file)| file))
        // ```
        //
        // ...and storing the result in our object, but the type of that
        // expression is exquisitely hideous and we'd go mad.
        match self.state {
            AllFilesState::TopLevelFile => {
                self.state = AllFilesState::OverrideFiles(self.pod.override_files());
                Some(self.pod.file())
            }
            AllFilesState::OverrideFiles(ref mut iter) => {
                iter.next().map(|(_, file)|  file)
            }
        }
    }
}

#[test]
fn pods_are_normalized_on_load() {
    use env_logger;
    use project::Project;
    let _ = env_logger::init();

    let proj = Project::from_example("hello").unwrap();
    let frontend = proj.pod("frontend").unwrap();

    let web = frontend.file().services.get("web").unwrap();
    assert_eq!(web.env_files.len(), 1);
    assert_eq!(web.env_files[0].value().unwrap(),
               Path::new("common.env"));

    // This test assumes that there's no `web` entry in the `production`
    // override, so we have to create everything from scratch.
    let production = proj.ovr("production").unwrap();
    let web_ovr = frontend.override_file(production).unwrap()
        .services.get("web").unwrap();
    assert_eq!(web_ovr.env_files.len(), 1);
    assert_eq!(web_ovr.env_files[0].value().unwrap(),
               Path::new("overrides/production/common.env"));
}

#[test]
fn can_merge_base_file_and_override() {
    use env_logger;
    let _ = env_logger::init();
    let proj: Project = Project::from_example("hello").unwrap();
    let ovr = proj.ovr("development").unwrap();
    let frontend = proj.pod("frontend").unwrap();
    let merged = frontend.merged_file(&ovr).unwrap();
    let proxy = merged.services.get("proxy").unwrap();
    assert_eq!(proxy.env_files.len(), 2);
}
<commit_msg>Calculate pod types from per-pod config<commit_after>//! A single pod in a project.

use docker_compose::v2 as dc;
use docker_compose::v2::MergeOverride;
use std::collections::BTreeMap;
use std::collections::btree_map;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use ext::file::FileExt;
use ovr::Override;
use project::Project;
use util::Error;

/// Information about a `docker-compose.yml` file, including its path
/// relative to `base_dir` (`base_dir` is normally `$PROJECT/pods`), and
/// the normalized version of its contents:
///
/// 1. Any missing services will be explicitly added to an override file.
/// 2. The `env_file` list will be updated to contain the appropriate
///    `common.yml` file.
///
/// If this file doesn't actually exist on disk, we'll still fill in the
/// default contents as above.
///
/// If you need to process this further, clone the `File` and work on the
/// clone.  This is the master copy.
#[derive(Debug)]
struct FileInfo {
    rel_path: PathBuf,
    file: dc::File,
}

impl FileInfo {
    /// Create a `FileInfo` by either loading `base_dir.join(rel_path)` or
    /// by creating an empty `dc::File` in its place.  Do not perform
    /// normalization.
    fn unnormalized(base_dir: &Path, rel_path: &Path) -> Result<FileInfo, Error> {
        let path = base_dir.join(rel_path);
        Ok(FileInfo {
            rel_path: rel_path.to_owned(),
            file: if path.exists() {
                try!(dc::File::read_from_path(&path))
            } else {
                Default::default()
            },
        })
    }

    /// Make sure that all services from `base` are also present in this
    /// file.  If you're going tp call this, it must be called after
    /// `finish_normalization`
    fn ensure_all_services_from(&mut self, base: &dc::File) {
        for (name, _service) in base.services.iter() {
            self.file.services.entry(name.to_owned())
                .or_insert_with(Default::default);
        }
    }

    /// Finish normalizing this file by inserting things like `env_file`
    /// entries.
    fn finish_normalization(&mut self) {
        // It's safe to call `unwrap` here because we know `rel_path` should
        // have a parent directory.
        let env_path = self.rel_path.parent().unwrap().join("common.env");
        for (_name, service) in self.file.services.iter_mut() {
            service.env_files.insert(0, dc::value(env_path.clone()));
        }
    }
}

/// Indicates whether a pod is a regular service or a one-shot task.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PodType {
    /// A service is normally started up and left running.
    Service,
    /// A task is run once and expected to exit.
    Task,
}

impl FromStr for PodType {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "service" => Ok(PodType::Service),
            "task" => Ok(PodType::Task),
            _ => Err(err!("Unknown pod type: <{}>", s)),
        }
    }
}

/// A pod, specified by `pods/$NAME.yml` and zero or more
/// `pods/overrides/*/*.yml` overrides that we can apply to it.
#[derive(Debug)]
pub struct Pod {
    /// All paths in any associated `dc::File` should be intepreted
    /// relative to this base, including paths in overlay files.
    base_dir: PathBuf,

    /// The name of this pod, based on the file `pods/$NAME.yml`.
    name: String,

    /// The top-level file defining this pod.
    file_info: FileInfo,

    /// The individual override files for this pod.  There will always be a
    /// sensible value here for each pod, even if the file doesn't exist on
    /// disk.
    override_file_infos: BTreeMap<Override, FileInfo>,
}

impl Pod {
    /// Create a new pod, specifying the base directory from which we'll load
    /// pod definitions and the name of the pod.
    #[doc(hidden)]
    pub fn new<P, S>(base_dir: P, name: S, overrides: &[Override]) ->
        Result<Pod, Error>
        where P: Into<PathBuf>, S: Into<String>
    {
        let base_dir = base_dir.into();
        let name = name.into();

        // Load our main `*.yml` file.
        let rel_path = Path::new(&format!("{}.yml", &name)).to_owned();
        let mut file_info = try!(FileInfo::unnormalized(&base_dir, &rel_path));
        file_info.finish_normalization();

        // Load our override `*.yml` files.
        let mut ovr_infos = BTreeMap::new();
        for ovr in overrides {
            let ovr_rel_path =
                Path::new(&format!("overrides/{}/{}.yml", ovr.name(), &name))
                    .to_owned();
            let mut ovr_info =
                try!(FileInfo::unnormalized(&base_dir, &ovr_rel_path));
            ovr_info.ensure_all_services_from(&file_info.file);
            ovr_info.finish_normalization();
            ovr_infos.insert(ovr.to_owned(), ovr_info);
        }

        Ok(Pod {
            base_dir: base_dir,
            name: name,
            file_info: file_info,
            override_file_infos: ovr_infos,
        })
    }

    /// Get the name of this pod.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Get the type of this pod.
    pub fn pod_type(&self, ovr: &Override) -> Result<PodType, Error> {
        let file = try!(self.merged_file(ovr));
        match try!(file.pod_label("io.fdy.conductor.type")) {
            None => Ok(PodType::Service),
            Some(ref pod_type_str) => pod_type_str.parse(),
        }
    }

    /// The base directory for our relative paths.
    pub fn base_dir(&self) -> &Path {
        &self.base_dir
    }

    /// The path to the top-level file defining this pod, relative to the
    /// `base_dir` specified at creation time.
    pub fn rel_path(&self) -> &Path {
        &self.file_info.rel_path
    }

    /// The top-level file defining this pod.  This is normalized to
    /// include the appropriate `env_file` entries, but if you want to do
    /// more complicated transformations, you'll need to clone it with
    /// `to_owned()` first.
    pub fn file(&self) -> &dc::File {
        &self.file_info.file
    }

    /// Look up the file info associated with an override, or return an
    /// error if this override was not specified for this `Pod` at creation
    /// time.
    fn override_file_info(&self, ovr: &Override) -> Result<&FileInfo, Error> {
        self.override_file_infos.get(ovr).ok_or_else(|| {
            err!("The override {} is not defined", ovr.name())
        })
    }

    /// The path to the specificied override file for this pod.
    pub fn override_rel_path(&self, ovr: &Override) -> Result<&Path, Error> {
        Ok(&(try!(self.override_file_info(ovr)).rel_path))
    }

    /// The `dc::File` for this override.
    pub fn override_file(&self, ovr: &Override) -> Result<&dc::File, Error> {
        Ok(&(try!(self.override_file_info(ovr)).file))
    }

    /// Return the base file and the override file merged into a single
    /// `docker-compose.yml` file.
    pub fn merged_file(&self, ovr: &Override) -> Result<dc::File, Error> {
        // This is expensive so log it.
        debug!("Merging pod {} with override {}", self.name(), ovr.name());
        Ok(self.file().merge_override(try!(self.override_file(ovr))))
    }

    /// All the overrides associated with this pod.
    pub fn override_files(&self) -> OverrideFiles {
        OverrideFiles { iter: self.override_file_infos.iter() }
    }

    /// Iterate over all `dc::File` objects associated with this pod, including
    /// both the main `file()` and all the files in `override_files()`.
    pub fn all_files(&self) -> AllFiles {
        // Defer all the hard work to our iterator type.
        AllFiles {
            pod: self,
            state: AllFilesState::TopLevelFile,
        }
    }

    /// Command-line `-p` and `-f` arguments that we'll pass to
    /// `docker-compose` to describe this file.
    pub fn compose_args(&self, proj: &Project, ovr: &Override) ->
        Result<Vec<OsString>, Error>
    {
        let ovr_rel_path = try!(self.override_rel_path(ovr));
        let compose_project_name = ovr.compose_project_name(proj);
        Ok(vec!("-p".into(), compose_project_name.into(),
                "-f".into(), proj.output_pods_dir().join(self.rel_path()).into(),
                "-f".into(), proj.output_pods_dir().join(ovr_rel_path).into()))
    }
}

/// An iterator over this pods overrides and their associated files.
pub struct OverrideFiles<'a> {
    iter: btree_map::Iter<'a, Override, FileInfo>,
}

impl<'a> Iterator for OverrideFiles<'a> {
    type Item = (&'a Override, &'a dc::File);

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(ovr, file_info)| (ovr, &file_info.file))
    }
}

/// What should we yield next from our AllFiles iterator?
enum AllFilesState<'a> {
    /// Yield the top-level `file()` next.
    TopLevelFile,
    /// Yield an item from this iterator next.
    OverrideFiles(OverrideFiles<'a>),
}

/// An iterator over all the `dc::File` objects associated with a pod, in
/// all overlays.
pub struct AllFiles<'a> {
    /// The pod whose files we're iterating over.
    pod: &'a Pod,
    /// Our current iteration state.
    state: AllFilesState<'a>,
}

impl<'a> Iterator for AllFiles<'a> {
    type Item = &'a dc::File;

    fn next(&mut self) -> Option<Self::Item> {
        // We could try to implement this by calling:
        //
        // ```
        // iter::once(pod.file())
        //     .chain(pod.override_files().map(|(_, file)| file))
        // ```
        //
        // ...and storing the result in our object, but the type of that
        // expression is exquisitely hideous and we'd go mad.
        match self.state {
            AllFilesState::TopLevelFile => {
                self.state = AllFilesState::OverrideFiles(self.pod.override_files());
                Some(self.pod.file())
            }
            AllFilesState::OverrideFiles(ref mut iter) => {
                iter.next().map(|(_, file)|  file)
            }
        }
    }
}

#[test]
fn pods_are_normalized_on_load() {
    use env_logger;
    use project::Project;
    let _ = env_logger::init();

    let proj = Project::from_example("hello").unwrap();
    let frontend = proj.pod("frontend").unwrap();

    let web = frontend.file().services.get("web").unwrap();
    assert_eq!(web.env_files.len(), 1);
    assert_eq!(web.env_files[0].value().unwrap(),
               Path::new("common.env"));

    // This test assumes that there's no `web` entry in the `production`
    // override, so we have to create everything from scratch.
    let production = proj.ovr("production").unwrap();
    let web_ovr = frontend.override_file(production).unwrap()
        .services.get("web").unwrap();
    assert_eq!(web_ovr.env_files.len(), 1);
    assert_eq!(web_ovr.env_files[0].value().unwrap(),
               Path::new("overrides/production/common.env"));
}

#[test]
fn can_merge_base_file_and_override() {
    use env_logger;
    let _ = env_logger::init();
    let proj: Project = Project::from_example("hello").unwrap();
    let ovr = proj.ovr("development").unwrap();
    let frontend = proj.pod("frontend").unwrap();
    let merged = frontend.merged_file(&ovr).unwrap();
    let proxy = merged.services.get("proxy").unwrap();
    assert_eq!(proxy.env_files.len(), 2);
}

#[test]
fn pod_type_returns_type_of_pod() {
    use env_logger;
    let _ = env_logger::init();
    let proj: Project = Project::from_example("rails_hello").unwrap();
    let ovr = proj.ovr("development").unwrap();
    let frontend = proj.pod("frontend").unwrap();
    assert_eq!(frontend.pod_type(&ovr).unwrap(), PodType::Service);
    let migrate = proj.pod("migrate").unwrap();
    assert_eq!(migrate.pod_type(&ovr).unwrap(), PodType::Task);
}
<|endoftext|>


<commit_before>use cli::{clear_screen, Args};
use env_logger;
use error::Result;
use gitignore;
use log;
use notification_filter::NotificationFilter;
#[cfg(target_os = "linux")]
use notify;
use pathop::PathOp;
use process::{self, Process};
use signal::{self, Signal};
use std::{
    collections::HashMap,
    io::Write,
    sync::{
        mpsc::{channel, Receiver},
        Arc, RwLock,
    },
    time::Duration,
};
use watcher::{Event, Watcher};

fn init_logger(debug: bool) {
    let mut log_builder = env_logger::Builder::new();
    let level = if debug {
        log::LevelFilter::Debug
    } else {
        log::LevelFilter::Warn
    };

    log_builder
        .format(|buf, r| writeln!(buf, "*** {}", r.args()))
        .filter(None, level)
        .init();
}

pub trait Handler {
    /// Initialises the `Handler` with a copy of the arguments.
    fn new(args: Args) -> Result<Self>
    where
        Self: Sized;

    /// Called through a manual request, such as an initial run.
    ///
    /// # Returns
    ///
    /// A `Result` which means:
    ///
    /// - `Err`: an error has occurred while processing, quit.
    /// - `Ok(true)`: everything is fine and the loop can continue.
    /// - `Ok(false)`: everything is fine but we should gracefully stop.
    fn on_manual(&mut self) -> Result<bool>;

    /// Called through a file-update request.
    ///
    /// # Parameters
    ///
    /// - `ops`: The list of events that triggered this update.
    ///
    /// # Returns
    ///
    /// A `Result` which means:
    ///
    /// - `Err`: an error has occurred while processing, quit.
    /// - `Ok(true)`: everything is fine and the loop can continue.
    /// - `Ok(false)`: everything is fine but we should gracefully stop.
    fn on_update(&mut self, ops: &[PathOp]) -> Result<bool>;
}

/// Starts watching, and calls a handler when something happens.
///
/// Given an argument structure and a `Handler` type, starts the watcher
/// loop (blocking until done).
pub fn watch<H>(args: Args) -> Result<()>
where
    H: Handler,
{
    init_logger(args.debug);
    let mut handler = H::new(args.clone())?;

    let gitignore = gitignore::load(if args.no_vcs_ignore { &[] } else { &args.paths });
    let filter = NotificationFilter::new(&args.filters, &args.ignores, gitignore)?;

    let (tx, rx) = channel();
    let poll = args.poll.clone();
    #[cfg(target_os = "linux")]
    let poll_interval = args.poll_interval.clone();
    let watcher = Watcher::new(tx.clone(), &args.paths, args.poll, args.poll_interval).or_else(|err| {
        if poll {
            return Err(err);
        }

        #[cfg(target_os = "linux")]
        {
            use nix::libc;
            let mut fallback = false;
            if let notify::Error::Io(ref e) = err {
                if e.raw_os_error() == Some(libc::ENOSPC) {
                    warn!("System notification limit is too small, falling back to polling mode. For better performance increase system limit:\n\tsysctl fs.inotify.max_user_watches=524288");
                    fallback = true;
                }
            }

            if fallback {
                return Watcher::new(tx, &args.paths, true, poll_interval);
            }
        }

        Err(err)
    })?;

    if watcher.is_polling() {
        warn!("Polling for changes every {} ms", args.poll_interval);
    }

    // Call handler initially, if necessary
    if args.run_initially {
        if !handler.on_manual()? {
            return Ok(());
        }
    }

    loop {
        debug!("Waiting for filesystem activity");
        let paths = wait_fs(&rx, &filter, args.debounce);
        debug!("Paths updated: {:?}", paths);

        if !handler.on_update(&paths)? {
            break;
        }
    }

    Ok(())
}

pub struct ExecHandler {
    args: Args,
    signal: Option<Signal>,
    child_process: Arc<RwLock<Option<Process>>>,
}

impl ExecHandler {
    fn spawn(&mut self, ops: &[PathOp]) -> Result<()> {
        if self.args.clear_screen {
            clear_screen();
        }

        debug!("Launching child process");
        let mut guard = self.child_process.write()?;
        *guard = Some(process::spawn(&self.args.cmd, ops, self.args.no_shell)?);

        Ok(())
    }
}

impl Handler for ExecHandler {
    fn new(args: Args) -> Result<Self> {
        let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None));
        let weak_child = Arc::downgrade(&child_process);

        // Convert signal string to the corresponding integer
        let signal = signal::new(args.signal.clone());

        signal::install_handler(move |sig: Signal| {
            if let Some(lock) = weak_child.upgrade() {
                let strong = lock.read().unwrap();
                if let Some(ref child) = *strong {
                    match sig {
                        Signal::SIGCHLD => child.reap(), // SIGCHLD is special, initiate reap()
                        _ => child.signal(sig),
                    }
                }
            }
        });

        Ok(Self {
            args,
            signal,
            child_process,
        })
    }

    // Only returns Err() on lock poisoning.
    fn on_manual(&mut self) -> Result<bool> {
        if self.args.once {
            return Ok(true);
        }

        let cls = self.args.clear_screen;
        self.args.clear_screen = false;
        self.spawn(&[])?;
        self.args.clear_screen = cls;
        Ok(true)
    }

    // Only returns Err() on lock poisoning.
    fn on_update(&mut self, ops: &[PathOp]) -> Result<bool> {
        // We have four scenarios here:
        //
        // 1. Send a specified signal to the child, wait for it to exit, then run the command again
        // 2. Send SIGTERM to the child, wait for it to exit, then run the command again
        // 3. Just send a specified signal to the child, do nothing more
        // 4. Make sure the previous run was ended, then run the command again
        //
        let scenario = (self.args.restart, self.signal.is_some());

        match scenario {
            // Custom restart behaviour (--restart was given, and --signal specified):
            // Send specified signal to the child, wait for it to exit, then run the command again
            (true, true) => {
                signal_process(&self.child_process, self.signal, true);
                self.spawn(ops)?;
            }

            // Default restart behaviour (--restart was given, but --signal wasn't specified):
            // Send SIGTERM to the child, wait for it to exit, then run the command again
            (true, false) => {
                let sigterm = signal::new(Some("SIGTERM".into()));
                signal_process(&self.child_process, sigterm, true);
                self.spawn(ops)?;
            }

            // SIGHUP scenario: --signal was given, but --restart was not
            // Just send a signal (e.g. SIGHUP) to the child, do nothing more
            (false, true) => signal_process(&self.child_process, self.signal, false),

            // Default behaviour (neither --signal nor --restart specified):
            // Make sure the previous run was ended, then run the command again
            (false, false) => {
                signal_process(&self.child_process, None, true);
                self.spawn(ops)?;
            }
        }

        // Handle once option for integration testing
        if self.args.once {
            signal_process(&self.child_process, self.signal, false);
            return Ok(false);
        }

        Ok(true)
    }
}

pub fn run(args: Args) -> Result<()> {
    watch::<ExecHandler>(args)
}

fn wait_fs(rx: &Receiver<Event>, filter: &NotificationFilter, debounce: u64) -> Vec<PathOp> {
    let mut paths = Vec::new();
    let mut cache = HashMap::new();

    loop {
        let e = rx.recv().expect("error when reading event");

        if let Some(ref path) = e.path {
            let pathop = PathOp::new(path, e.op.ok(), e.cookie);
            // Ignore cache for the initial file. Otherwise, in
            // debug mode it's hard to track what's going on
            let excluded = filter.is_excluded(path);
            if !cache.contains_key(&pathop) {
                cache.insert(pathop.clone(), excluded);
            }

            if !excluded {
                paths.push(pathop);
                break;
            }
        }
    }

    // Wait for filesystem activity to cool off
    let timeout = Duration::from_millis(debounce);
    while let Ok(e) = rx.recv_timeout(timeout) {
        if let Some(ref path) = e.path {
            let pathop = PathOp::new(path, e.op.ok(), e.cookie);
            if cache.contains_key(&pathop) {
                continue;
            }

            let excluded = filter.is_excluded(path);

            cache.insert(pathop.clone(), excluded);

            if !excluded {
                paths.push(pathop);
            }
        }
    }

    paths
}

// signal_process sends signal to process. It waits for the process to exit if wait is true
fn signal_process(process: &RwLock<Option<Process>>, signal: Option<Signal>, wait: bool) {
    let guard = process.read().unwrap();

    if let Some(ref child) = *guard {
        if let Some(s) = signal {
            child.signal(s);
        }

        if wait {
            debug!("Waiting for process to exit...");
            child.wait();
        }
    }
}
<commit_msg>[run] Restore clearing of the screen on initial run<commit_after>use cli::{clear_screen, Args};
use env_logger;
use error::Result;
use gitignore;
use log;
use notification_filter::NotificationFilter;
#[cfg(target_os = "linux")]
use notify;
use pathop::PathOp;
use process::{self, Process};
use signal::{self, Signal};
use std::{
    collections::HashMap,
    io::Write,
    sync::{
        mpsc::{channel, Receiver},
        Arc, RwLock,
    },
    time::Duration,
};
use watcher::{Event, Watcher};

fn init_logger(debug: bool) {
    let mut log_builder = env_logger::Builder::new();
    let level = if debug {
        log::LevelFilter::Debug
    } else {
        log::LevelFilter::Warn
    };

    log_builder
        .format(|buf, r| writeln!(buf, "*** {}", r.args()))
        .filter(None, level)
        .init();
}

pub trait Handler {
    /// Initialises the `Handler` with a copy of the arguments.
    fn new(args: Args) -> Result<Self>
    where
        Self: Sized;

    /// Called through a manual request, such as an initial run.
    ///
    /// # Returns
    ///
    /// A `Result` which means:
    ///
    /// - `Err`: an error has occurred while processing, quit.
    /// - `Ok(true)`: everything is fine and the loop can continue.
    /// - `Ok(false)`: everything is fine but we should gracefully stop.
    fn on_manual(&mut self) -> Result<bool>;

    /// Called through a file-update request.
    ///
    /// # Parameters
    ///
    /// - `ops`: The list of events that triggered this update.
    ///
    /// # Returns
    ///
    /// A `Result` which means:
    ///
    /// - `Err`: an error has occurred while processing, quit.
    /// - `Ok(true)`: everything is fine and the loop can continue.
    /// - `Ok(false)`: everything is fine but we should gracefully stop.
    fn on_update(&mut self, ops: &[PathOp]) -> Result<bool>;
}

/// Starts watching, and calls a handler when something happens.
///
/// Given an argument structure and a `Handler` type, starts the watcher
/// loop (blocking until done).
pub fn watch<H>(args: Args) -> Result<()>
where
    H: Handler,
{
    init_logger(args.debug);
    let mut handler = H::new(args.clone())?;

    let gitignore = gitignore::load(if args.no_vcs_ignore { &[] } else { &args.paths });
    let filter = NotificationFilter::new(&args.filters, &args.ignores, gitignore)?;

    let (tx, rx) = channel();
    let poll = args.poll.clone();
    #[cfg(target_os = "linux")]
    let poll_interval = args.poll_interval.clone();
    let watcher = Watcher::new(tx.clone(), &args.paths, args.poll, args.poll_interval).or_else(|err| {
        if poll {
            return Err(err);
        }

        #[cfg(target_os = "linux")]
        {
            use nix::libc;
            let mut fallback = false;
            if let notify::Error::Io(ref e) = err {
                if e.raw_os_error() == Some(libc::ENOSPC) {
                    warn!("System notification limit is too small, falling back to polling mode. For better performance increase system limit:\n\tsysctl fs.inotify.max_user_watches=524288");
                    fallback = true;
                }
            }

            if fallback {
                return Watcher::new(tx, &args.paths, true, poll_interval);
            }
        }

        Err(err)
    })?;

    if watcher.is_polling() {
        warn!("Polling for changes every {} ms", args.poll_interval);
    }

    // Call handler initially, if necessary
    if args.run_initially {
        if !handler.on_manual()? {
            return Ok(());
        }
    }

    loop {
        debug!("Waiting for filesystem activity");
        let paths = wait_fs(&rx, &filter, args.debounce);
        debug!("Paths updated: {:?}", paths);

        if !handler.on_update(&paths)? {
            break;
        }
    }

    Ok(())
}

pub struct ExecHandler {
    args: Args,
    signal: Option<Signal>,
    child_process: Arc<RwLock<Option<Process>>>,
}

impl ExecHandler {
    fn spawn(&mut self, ops: &[PathOp]) -> Result<()> {
        if self.args.clear_screen {
            clear_screen();
        }

        debug!("Launching child process");
        let mut guard = self.child_process.write()?;
        *guard = Some(process::spawn(&self.args.cmd, ops, self.args.no_shell)?);

        Ok(())
    }
}

impl Handler for ExecHandler {
    fn new(args: Args) -> Result<Self> {
        let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None));
        let weak_child = Arc::downgrade(&child_process);

        // Convert signal string to the corresponding integer
        let signal = signal::new(args.signal.clone());

        signal::install_handler(move |sig: Signal| {
            if let Some(lock) = weak_child.upgrade() {
                let strong = lock.read().unwrap();
                if let Some(ref child) = *strong {
                    match sig {
                        Signal::SIGCHLD => child.reap(), // SIGCHLD is special, initiate reap()
                        _ => child.signal(sig),
                    }
                }
            }
        });

        Ok(Self {
            args,
            signal,
            child_process,
        })
    }

    // Only returns Err() on lock poisoning.
    fn on_manual(&mut self) -> Result<bool> {
        if self.args.once {
            return Ok(true);
        }

        self.spawn(&[])?;
        Ok(true)
    }

    // Only returns Err() on lock poisoning.
    fn on_update(&mut self, ops: &[PathOp]) -> Result<bool> {
        // We have four scenarios here:
        //
        // 1. Send a specified signal to the child, wait for it to exit, then run the command again
        // 2. Send SIGTERM to the child, wait for it to exit, then run the command again
        // 3. Just send a specified signal to the child, do nothing more
        // 4. Make sure the previous run was ended, then run the command again
        //
        let scenario = (self.args.restart, self.signal.is_some());

        match scenario {
            // Custom restart behaviour (--restart was given, and --signal specified):
            // Send specified signal to the child, wait for it to exit, then run the command again
            (true, true) => {
                signal_process(&self.child_process, self.signal, true);
                self.spawn(ops)?;
            }

            // Default restart behaviour (--restart was given, but --signal wasn't specified):
            // Send SIGTERM to the child, wait for it to exit, then run the command again
            (true, false) => {
                let sigterm = signal::new(Some("SIGTERM".into()));
                signal_process(&self.child_process, sigterm, true);
                self.spawn(ops)?;
            }

            // SIGHUP scenario: --signal was given, but --restart was not
            // Just send a signal (e.g. SIGHUP) to the child, do nothing more
            (false, true) => signal_process(&self.child_process, self.signal, false),

            // Default behaviour (neither --signal nor --restart specified):
            // Make sure the previous run was ended, then run the command again
            (false, false) => {
                signal_process(&self.child_process, None, true);
                self.spawn(ops)?;
            }
        }

        // Handle once option for integration testing
        if self.args.once {
            signal_process(&self.child_process, self.signal, false);
            return Ok(false);
        }

        Ok(true)
    }
}

pub fn run(args: Args) -> Result<()> {
    watch::<ExecHandler>(args)
}

fn wait_fs(rx: &Receiver<Event>, filter: &NotificationFilter, debounce: u64) -> Vec<PathOp> {
    let mut paths = Vec::new();
    let mut cache = HashMap::new();

    loop {
        let e = rx.recv().expect("error when reading event");

        if let Some(ref path) = e.path {
            let pathop = PathOp::new(path, e.op.ok(), e.cookie);
            // Ignore cache for the initial file. Otherwise, in
            // debug mode it's hard to track what's going on
            let excluded = filter.is_excluded(path);
            if !cache.contains_key(&pathop) {
                cache.insert(pathop.clone(), excluded);
            }

            if !excluded {
                paths.push(pathop);
                break;
            }
        }
    }

    // Wait for filesystem activity to cool off
    let timeout = Duration::from_millis(debounce);
    while let Ok(e) = rx.recv_timeout(timeout) {
        if let Some(ref path) = e.path {
            let pathop = PathOp::new(path, e.op.ok(), e.cookie);
            if cache.contains_key(&pathop) {
                continue;
            }

            let excluded = filter.is_excluded(path);

            cache.insert(pathop.clone(), excluded);

            if !excluded {
                paths.push(pathop);
            }
        }
    }

    paths
}

// signal_process sends signal to process. It waits for the process to exit if wait is true
fn signal_process(process: &RwLock<Option<Process>>, signal: Option<Signal>, wait: bool) {
    let guard = process.read().unwrap();

    if let Some(ref child) = *guard {
        if let Some(s) = signal {
            child.signal(s);
        }

        if wait {
            debug!("Waiting for process to exit...");
            child.wait();
        }
    }
}
<|endoftext|>


<commit_before>mod game_id;

use byteorder::{LittleEndian, ReadBytesExt as _, WriteBytesExt as _};
use std::io::{self, Read, Write};
use std::convert::TryFrom;
use shakmaty::{Role, Square};
use shakmaty::uci::Uci;

pub use game_id::{GameId, InvalidGameId};

fn read_uint<R: Read>(reader: &mut R) -> io::Result<u64> {
    let mut n = 0;
    for shift in (0..).step_by(7) {
        let byte = reader.read_u8()?;
        n |= u64::from(byte & 127)
            .checked_shl(shift)
            .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidData))?;
        if byte & 128 == 0 {
            break;
        }
    }
    Ok(n)
}

fn write_uint<W: Write>(writer: &mut W, mut n: u64) -> io::Result<()> {
    while n > 127 {
        writer.write_u8((n as u8 & 127) | 128)?;
        n >>= 7;
    }
    writer.write_u8(n as u8)
}

fn read_uci<R: Read>(reader: &mut R) -> io::Result<Uci> {
    let n = reader.read_u16::<LittleEndian>()?;
    let from = Square::try_from(n & 63).unwrap();
    let to = Square::try_from((n >> 6) & 63).unwrap();
    let role = Role::try_from(n >> 12).ok();
    Ok(if from == to {
        match role {
            Some(role) => Uci::Put { role, to },
            None => Uci::Null,
        }
    } else {
        Uci::Normal { from, to, promotion: role }
    })
}

fn write_uci<W: Write>(writer: &mut W, uci: Uci) -> io::Result<()> {
    let (from, to, role) = match uci {
        Uci::Normal { from, to, promotion } => (from, to, promotion),
        Uci::Put { role, to } => (to, to, Some(role)),
        Uci::Null => (Square::A1, Square::A1, None),
    };
    writer.write_u16::<LittleEndian>(u16::from(from) | (u16::from(to) << 6) | role.map(u16::from).unwrap_or_default() << 12)
}

#[cfg(test)]
mod tests {
    use super::*;
    use quickcheck::quickcheck;
    use std::io::Cursor;

    quickcheck! {
        fn uint_roundtrip(n: u64) -> bool {
            let mut writer = Cursor::new(Vec::new());
            write_uint(&mut writer, n).unwrap();

            let mut reader = Cursor::new(writer.into_inner());
            read_uint(&mut reader).unwrap() == n
        }
    }
}
<commit_msg>cargo fmt<commit_after>mod game_id;

use byteorder::{LittleEndian, ReadBytesExt as _, WriteBytesExt as _};
use shakmaty::uci::Uci;
use shakmaty::{Role, Square};
use std::convert::TryFrom;
use std::io::{self, Read, Write};

pub use game_id::{GameId, InvalidGameId};

fn read_uint<R: Read>(reader: &mut R) -> io::Result<u64> {
    let mut n = 0;
    for shift in (0..).step_by(7) {
        let byte = reader.read_u8()?;
        n |= u64::from(byte & 127)
            .checked_shl(shift)
            .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidData))?;
        if byte & 128 == 0 {
            break;
        }
    }
    Ok(n)
}

fn write_uint<W: Write>(writer: &mut W, mut n: u64) -> io::Result<()> {
    while n > 127 {
        writer.write_u8((n as u8 & 127) | 128)?;
        n >>= 7;
    }
    writer.write_u8(n as u8)
}

fn read_uci<R: Read>(reader: &mut R) -> io::Result<Uci> {
    let n = reader.read_u16::<LittleEndian>()?;
    let from = Square::try_from(n & 63).unwrap();
    let to = Square::try_from((n >> 6) & 63).unwrap();
    let role = Role::try_from(n >> 12).ok();
    Ok(if from == to {
        match role {
            Some(role) => Uci::Put { role, to },
            None => Uci::Null,
        }
    } else {
        Uci::Normal {
            from,
            to,
            promotion: role,
        }
    })
}

fn write_uci<W: Write>(writer: &mut W, uci: Uci) -> io::Result<()> {
    let (from, to, role) = match uci {
        Uci::Normal {
            from,
            to,
            promotion,
        } => (from, to, promotion),
        Uci::Put { role, to } => (to, to, Some(role)),
        Uci::Null => (Square::A1, Square::A1, None),
    };
    writer.write_u16::<LittleEndian>(
        u16::from(from) | (u16::from(to) << 6) | (role.map(u16::from).unwrap_or_default() << 12),
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use quickcheck::quickcheck;
    use std::io::Cursor;

    quickcheck! {
        fn uint_roundtrip(n: u64) -> bool {
            let mut writer = Cursor::new(Vec::new());
            write_uint(&mut writer, n).unwrap();

            let mut reader = Cursor::new(writer.into_inner());
            read_uint(&mut reader).unwrap() == n
        }
    }
}
<|endoftext|>


<commit_before>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: util/log.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      A general logging collection
      with differen verbosity levels.
      Use Q3_LOG=num where num matches:

      0 => Disable all logging
      1 => Enable only error logging
      2 => Enable info logging (default)
      3 => Enable debug logging (very verbose)

      Usage of logging utilities is generally
      by means of the macros: log_debug!() and
      log_error!(). Logs can be owned/indented
      using a log_push!(), which must have an
      associated log_pop!().
*/

use std::{ u8, io, local_data, os };
use extra::term;
use extra::term::color;

/* Default is error. */
type Verbosity = u8;
static Verbosity_None: Verbosity = 0;
static Verbosity_Error: Verbosity = 1;
static Verbosity_Info: Verbosity = 2;
static Verbosity_Debug: Verbosity = 3;

static tls_key: local_data::Key<@mut Log> = &local_data::Key;

#[macro_escape]
mod log_macros;

struct Log
{
  verbosity: Verbosity,
  push_level: u8, /* The indentation level, for nested logs. */
  terminal: term::Terminal,
}

impl Log
{
  pub fn initialize()
  {
    let logger = @mut Log
    {
      verbosity: match os::getenv("Q3_LOG").take_unwrap()
                 {
                   ~"0" => Verbosity_None,
                   ~"1" => Verbosity_Error,
                   ~"2" => Verbosity_Info,
                   ~"3" => Verbosity_Debug,
                   _ => Verbosity_Info, /* default */
                 },
      push_level: 0,
      terminal: term::Terminal::new(io::stdout()).unwrap(),
    };

    local_data::set(tls_key, logger);

    log_debug!("Logging system initialized");
  }

  priv fn get() -> @mut Log
  {
    local_data::get(tls_key,
    |opt|
    {
      match opt
      {
        Some(x) => *x,
        None => fail!("Singleton not available")
      }
    })
  }

  pub fn debug(module: &str, message: &str)
  {
    let logger = Log::get();
    if logger.verbosity >= Verbosity_Debug
    { Log::log(module, message, Verbosity_Debug); }
  }

  pub fn info(module: &str, message: &str)
  {
    let logger = Log::get();
    if logger.verbosity >= Verbosity_Info
    { Log::log(module, message, Verbosity_Info); }
  }

  pub fn error(module: &str, message: &str)
  {
    let logger = Log::get();
    if logger.verbosity >= Verbosity_Error
    { Log::log(module, message, Verbosity_Error); }
  }

  pub fn get_module(file: &str) -> ~str
  {
    let i = file.find_str("src").unwrap();
    file.slice_from(i + 4).replace(".rs", "") /* 4 is strlen("src/") */
  }

  pub fn push()
  {
    let logger = Log::get();
    logger.push_level += 1;
  }

  pub fn pop()
  {
    let logger = Log::get();

    assert!(logger.push_level > 0);
    logger.push_level -= 1;
  }

  priv fn log(module: &str, message: &str, verbosity: Verbosity)
  {
    let logger = Log::get();

    /* Display the current module. */
    logger.terminal.fg(color::BRIGHT_WHITE);
    print(module);
    logger.terminal.reset();

    /* Indent as per the push level. */
    for u8::range(0, logger.push_level) |_|
    { print("  "); }

    match verbosity
    {
      Verbosity_Debug =>
      {
        logger.terminal.fg(color::BRIGHT_GREEN);
        print(" debug => ");
      },
      Verbosity_Info =>
      {
        logger.terminal.fg(color::BRIGHT_YELLOW);
        print(" info => ");
      },
      Verbosity_Error =>
      {
        logger.terminal.fg(color::BRIGHT_RED);
        print(" error => ");
      },
      val => fail!("Invalid verbosity for logging: %?", val)
    }
    logger.terminal.reset();
    println(message);
  }
}

<commit_msg> #28 Logger no longer relies on Q3_LOG var<commit_after>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: util/log.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      A general logging collection
      with differen verbosity levels.
      Use Q3_LOG=num where num matches:

      0 => Disable all logging
      1 => Enable only error logging
      2 => Enable info logging (default)
      3 => Enable debug logging (very verbose)

      Usage of logging utilities is generally
      by means of the macros: log_debug!() and
      log_error!(). Logs can be owned/indented
      using a log_push!(), which must have an
      associated log_pop!().
*/

use std::{ u8, io, local_data, os };
use extra::term;
use extra::term::color;

/* Default is error. */
type Verbosity = u8;
static Verbosity_None: Verbosity = 0;
static Verbosity_Error: Verbosity = 1;
static Verbosity_Info: Verbosity = 2;
static Verbosity_Debug: Verbosity = 3;

static tls_key: local_data::Key<@mut Log> = &local_data::Key;

#[macro_escape]
mod log_macros;

struct Log
{
  verbosity: Verbosity,
  push_level: u8, /* The indentation level, for nested logs. */
  terminal: term::Terminal,
}

impl Log
{
  pub fn initialize()
  {
    let logger = @mut Log
    {
      verbosity: match os::getenv("Q3_LOG").take()
                 {
                   Some(val) => match val
                   {
                     ~"0" => Verbosity_None,
                     ~"1" => Verbosity_Error,
                     ~"2" => Verbosity_Info,
                     ~"3" => Verbosity_Debug,
                     _ => Verbosity_Info, /* default */
                   },
                   None => Verbosity_Info /* default */
                 },
      push_level: 0,
      terminal: term::Terminal::new(io::stdout()).unwrap(),
    };

    local_data::set(tls_key, logger);

    log_debug!("Logging system initialized");
  }

  priv fn get() -> @mut Log
  {
    local_data::get(tls_key,
    |opt|
    {
      match opt
      {
        Some(x) => *x,
        None => fail!("Singleton not available")
      }
    })
  }

  pub fn debug(module: &str, message: &str)
  {
    let logger = Log::get();
    if logger.verbosity >= Verbosity_Debug
    { Log::log(module, message, Verbosity_Debug); }
  }

  pub fn info(module: &str, message: &str)
  {
    let logger = Log::get();
    if logger.verbosity >= Verbosity_Info
    { Log::log(module, message, Verbosity_Info); }
  }

  pub fn error(module: &str, message: &str)
  {
    let logger = Log::get();
    if logger.verbosity >= Verbosity_Error
    { Log::log(module, message, Verbosity_Error); }
  }

  pub fn get_module(file: &str) -> ~str
  {
    let i = file.find_str("src").unwrap();
    file.slice_from(i + 4).replace(".rs", "") /* 4 is strlen("src/") */
  }

  pub fn push()
  {
    let logger = Log::get();
    logger.push_level += 1;
  }

  pub fn pop()
  {
    let logger = Log::get();

    assert!(logger.push_level > 0);
    logger.push_level -= 1;
  }

  priv fn log(module: &str, message: &str, verbosity: Verbosity)
  {
    let logger = Log::get();

    /* Display the current module. */
    logger.terminal.fg(color::BRIGHT_WHITE);
    print(module);
    logger.terminal.reset();

    /* Indent as per the push level. */
    for u8::range(0, logger.push_level) |_|
    { print("  "); }

    match verbosity
    {
      Verbosity_Debug =>
      {
        logger.terminal.fg(color::BRIGHT_GREEN);
        print(" debug => ");
      },
      Verbosity_Info =>
      {
        logger.terminal.fg(color::BRIGHT_YELLOW);
        print(" info => ");
      },
      Verbosity_Error =>
      {
        logger.terminal.fg(color::BRIGHT_RED);
        print(" error => ");
      },
      val => fail!("Invalid verbosity for logging: %?", val)
    }
    logger.terminal.reset();
    println(message);
  }
}

<|endoftext|>


<commit_before>//! Provides asynchronous retry functionality via `futures`.
//!
//! # Examples
//!
//! ```rust
//! # extern crate futures;
//! # extern crate tokio_timer;
//! # extern crate retry;
//! # use futures::future::Future;
//! use tokio_timer::Timer;
//! use retry::delay::{Exponential, jitter};
//! use retry::async::retry;
//!
//! pub fn main() {
//!     let timer = Timer::default();
//!     let delay = Exponential::from_millis(10)
//!         .map(jitter).take(3);
//!
//!     let mut collection = vec![1, 2, 3].into_iter();
//!
//!     let future = retry(timer, delay, || {
//!         match collection.next() {
//!             Some(n) if n == 3 => Ok("n is 3!"),
//!             Some(_) => Err("n must be 3!"),
//!             None => Err("n was never 3!"),
//!         }
//!     });
//!
//!     let result = future.wait();
//!
//!     assert!(result.is_ok());
//! }
//! ```

use std::error::{Error as StdError};
use std::io::{Error as IoError};
use std::fmt::{Debug, Error as FmtError, Formatter};
use std::time::Duration;

use futures::{Async, IntoFuture, Future, Poll};
use futures::future::{Either, Flatten, FutureResult};
#[cfg(feature = "async_tokio_timer")]
use tokio_timer::{Timer, TimerError, Sleep as TimerSleep};
#[cfg(feature = "async_tokio_core")]
use tokio_core::reactor::{Handle as ReactorHandle, Timeout as ReactorTimeout};

use super::Error;

/// Produce a future that resolves after a given delay.
pub trait Sleep {
    /// The type of error that the future will result in if it fails.
    type Error: StdError;
    /// The future that `sleep` will return.
    type Future: Future<Error = Self::Error>;
    /// Returns a future that will resolve after a given delay.
    fn sleep(&mut self, duration: Duration) -> Self::Future;
}

#[cfg(feature = "async_tokio_timer")]
impl Sleep for Timer {
    type Error = TimerError;
    type Future = TimerSleep;
    fn sleep(&mut self, duration: Duration) -> Self::Future {
        Timer::sleep(self, duration)
    }
}

#[cfg(feature = "async_tokio_core")]
impl Sleep for ReactorHandle {
    type Error = IoError;
    type Future = Flatten<FutureResult<ReactorTimeout, IoError>>;
    fn sleep(&mut self, duration: Duration) -> Self::Future {
        ReactorTimeout::new(duration, self).into_future().flatten()
    }
}

/// Keep track of the state of our future, whether it
/// currently sleeps or executes the operation.
enum RetryState<S, A> where S: Sleep, A: IntoFuture {
    Running(A::Future),
    Sleeping(S::Future)
}

/// Future that drives multiple attempts at an operation.
pub struct RetryFuture<S, I, O, A> where S: Sleep, I: IntoIterator<Item = Duration>, A: IntoFuture, O: FnMut() -> A {
    delay: I::IntoIter,
    state: RetryState<S, A>,
    operation: O,
    sleep: S,
    total_delay: Duration,
    tries: u64
}

impl<S, I, O, A> Debug for RetryFuture<S, I, O, A> where S: Sleep, I: IntoIterator<Item = Duration>, A: IntoFuture, O: FnMut() -> A {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "RetryFuture {{ total_delay: {:?}, tries: {:?} }}", self.total_delay, self.tries)
    }
}

/// Retry the given operation asynchronously until it succeeds, or until the given Duration iterator ends.
pub fn retry<S, I, O, A>(sleep: S, iterable: I, operation: O) -> RetryFuture<S, I, O, A> where S: Sleep, I: IntoIterator<Item = Duration>, A: IntoFuture, O: FnMut() -> A {
    RetryFuture::spawn(sleep, iterable, operation)
}

impl<S, I, O, A> RetryFuture<S, I, O, A> where S: Sleep, I: IntoIterator<Item = Duration>, A: IntoFuture, O: FnMut() -> A {
    fn spawn(sleep: S, iterable: I, mut operation: O) -> RetryFuture<S, I, O, A> {
        RetryFuture {
            delay: iterable.into_iter(),
            state: RetryState::Running(operation().into_future()),
            operation: operation,
            sleep: sleep,
            total_delay: Duration::default(),
            tries: 1
        }
    }

    fn attempt(&mut self) -> Poll<A::Item, Error<A::Error>> {
        let future = (self.operation)().into_future();
        self.state = RetryState::Running(future);
        return self.poll();
    }

    fn retry(&mut self, err: A::Error) -> Poll<A::Item, Error<A::Error>> {
        match self.delay.next() {
            None => Err(Error::Operation{
                error: err,
                total_delay: self.total_delay,
                tries: self.tries
            }),
            Some(duration) => {
                self.total_delay += duration;
                self.tries += 1;
                let future = self.sleep.sleep(duration);
                self.state = RetryState::Sleeping(future);
                return self.poll();
            }
        }
    }
}

impl<S, I, O, A> Future for RetryFuture<S, I, O, A> where S: Sleep, I: IntoIterator<Item = Duration>, A: IntoFuture, O: FnMut() -> A {
    type Item = A::Item;
    type Error = Error<A::Error>;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let result = match self.state {
            RetryState::Running(ref mut future) =>
                Either::A(future.poll()),
            RetryState::Sleeping(ref mut future) =>
                Either::B(future.poll())
        };

        match result {
            Either::A(poll_result) => match poll_result {
                Ok(async) => Ok(async),
                Err(err) => self.retry(err)
            },
            Either::B(poll_result) => {
                let poll_async = poll_result
                    .map_err(|err| Error::Internal(err.description().to_string()))?;

                match poll_async {
                    Async::NotReady => Ok(Async::NotReady),
                    Async::Ready(_) => self.attempt()
                }
            }
        }
    }
}

#[test]
fn attempts_just_once() {
    use std::iter::empty;
    let delay = empty();
    let mut num_calls = 0;
    let timer = Timer::default();
    let res = retry(timer, delay, || {
        num_calls += 1;
        Err::<(), u64>(42)
    }).wait();

    assert_eq!(num_calls, 1);
    assert_eq!(res, Err(Error::Operation{
        error: 42,
        tries: 1,
        total_delay: Duration::from_millis(0)
    }));
}

#[test]
fn attempts_until_max_retries_exceeded() {
    use std::time::Duration;
    use super::delay::Fixed;
    let timer = Timer::default();
    let delay = Fixed::from_millis(100).take(2);
    let mut num_calls = 0;
    let res = retry(timer, delay, || {
        num_calls += 1;
        Err::<(), u64>(42)
    }).wait();

    assert_eq!(num_calls, 3);
    assert_eq!(res, Err(Error::Operation{
        error: 42,
        tries: 3,
        total_delay: Duration::from_millis(200)
    }));
}

#[test]
fn attempts_until_success() {
    use super::delay::Fixed;
    let timer = Timer::default();
    let delay = Fixed::from_millis(100);
    let mut num_calls = 0;
    let res = retry(timer, delay, || {
        num_calls += 1;
        if num_calls < 4 {
            Err::<(), u64>(42)
        } else {
            Ok::<(), u64>(())
        }
    }).wait();

    assert_eq!(res, Ok(()));
    assert_eq!(num_calls, 4);
}
<commit_msg>Remove `asynchronous` former module<commit_after><|endoftext|>