<commit_before>use entities::*;
use std::cmp::Ordering;
use std::iter::FilterMap;
use std::slice::Iter;
use super::geo::{self, Coordinate};

trait DistanceTo {
    fn distance_to(&self, &Coordinate) -> f64;
}

impl DistanceTo for Entry {
    fn distance_to(&self, c: &Coordinate) -> f64 {
        geo::distance(&Coordinate {
                          lat: self.lat,
                          lng: self.lng,
                      },
                      c)
    }
}

pub trait SortByDistanceTo {
    fn sort_by_distance_to(&mut self, &Coordinate);
}

impl SortByDistanceTo for Vec<Entry> {
    fn sort_by_distance_to(&mut self, c: &Coordinate) {
        if !(c.lat.is_finite() && c.lng.is_finite()) {
            return;
        }
        self.sort_by(|a, _|
            if a.lat.is_finite() && a.lng.is_finite() {
                Ordering::Less
            } else {
                warn!("invalid coordinate: {}/{}", a.lat, a.lng);
                Ordering::Greater
            }
        );
        self.sort_by(|a, b| {
            a.distance_to(c).partial_cmp(&b.distance_to(c)).unwrap_or(Ordering::Equal)
        })
    }
}

pub trait Rated {
    fn avg_rating(&self, &[Rating], &[Triple]) -> f64;
    fn avg_rating_for_context(&self, &[Rating], &Vec<(&String, &String)>, RatingContext) -> Option<f64>;
}

impl Rated for Entry {
    fn avg_rating(&self, ratings: &[Rating], triples: &[Triple]) -> f64 {
        let entry_ratings : Vec<(&String, &String)> = triples
            .into_iter()
            .filter_map(|x| match *x {
                Triple {
                    subject   : ObjectId::Entry(ref e_id),
                    predicate : Relation::IsRatedWith,
                    object    : ObjectId::Rating(ref r_id)
                } => Some((e_id, r_id)),
                _ => None
            })
            .filter(|entry_rating| *entry_rating.0 == self.id).collect();

        let avg_ratings = vec![
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Diversity),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Renewable),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Fairness),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Humanity),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Transparency),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Solidarity),
        ];

        let sum = avg_ratings.iter().fold(0.0, |acc, &r| acc + r.unwrap_or(0.0));
        let num_rated_contexts = avg_ratings.iter().fold(0, |acc, &r| acc + if r.is_some() {1} else {0});

        if(num_rated_contexts > 0){
            sum as f64 / num_rated_contexts as f64
        } else{
            0.0
        }
    }

    fn avg_rating_for_context(&self, ratings: &[Rating], entry_ratings: &Vec<(&String, &String)>, context: RatingContext) -> Option<f64> {
        let applicable_ratings : Vec<&Rating> = ratings.into_iter()
            .filter_map(|rating| if rating.context == context
                && entry_ratings.iter()
                .any(|entry_rating| *entry_rating.1 == rating.id) { Some(rating) } else { None })
            .collect();

        let sum = applicable_ratings.iter().fold(0, |acc, ref rating| acc + rating.value) as f64;
        let n = applicable_ratings.len();

        let avg = sum / n as f64;
        if avg.is_nan() {
            None
        } else {
            Some(avg as f64)
        }
    }
}

pub trait SortByAverageRating {
    fn sort_by_avg_rating(&mut self, &[Rating], &[Triple]);
}

impl SortByAverageRating for Vec<Entry> {
    fn sort_by_avg_rating(&mut self, ratings: &[Rating], triples: &[Triple]){
        self.sort_by(|a, b| {
            b.avg_rating(ratings, triples)
            .partial_cmp(&a.avg_rating(ratings, triples))
            .unwrap_or(Ordering::Equal)
        })
    }
}

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

    fn new_entry(id: &str, lat: f64, lng: f64) -> Entry {
        Entry{
            id          : id.into(),
            created     : 0,
            version     : 0,
            title       : "foo".into(),
            description : "bar".into(),
            lat         : lat,
            lng         : lng,
            street      : None,
            zip         : None,
            city        : None,
            country     : None,
            email       : None,
            telephone   : None,
            homepage    : None,
            categories  : vec![],
            license     : None,
        }
    }

    fn new_rating(id: &str, value: i8, context: RatingContext) -> Rating {
        Rating{
            id         : id.into(),
            created    : 0,
            title      : "blubb".into(),
            value      : value.into(),
            context    : context
        }
    }

    #[test]
    fn test_average_rating() {
        let entry1 = new_entry("a", 0.0, 0.0);
        let entry2 = new_entry("b", 0.0, 0.0);
        let entry3 = new_entry("c", 0.0, 0.0);

        let ratings = vec![
            new_rating("1", 0, RatingContext::Diversity),
            new_rating("2", 0, RatingContext::Diversity),
            new_rating("3", 3, RatingContext::Diversity),
            new_rating("4", 3, RatingContext::Diversity),
            new_rating("5", -3, RatingContext::Diversity),
            new_rating("6", 3, RatingContext::Diversity),
        ];

        let triples = vec![
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("1".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("2".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("3".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("4".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("5".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("6".into())},
        ];

        assert_eq!(entry1.avg_rating(&ratings, &triples), 1.5);
        assert_eq!(entry2.avg_rating(&ratings, &triples), 0.0);
        assert_eq!(entry3.avg_rating(&ratings, &triples), 0.0);
    }

    #[test]
    fn test_average_rating_different_contexts() {
        let entry1 = new_entry("a", 0.0, 0.0);
        let entry2 = new_entry("b", 0.0, 0.0);

        let ratings = vec![
            new_rating("1", 0, RatingContext::Diversity),
            new_rating("2", 2, RatingContext::Renewable),
            new_rating("3", 4, RatingContext::Fairness),
            new_rating("4", 4, RatingContext::Fairness),
            new_rating("5", -3, RatingContext::Diversity),
            new_rating("6", 3, RatingContext::Fairness),
        ];

        let triples = vec![
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("1".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("2".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("3".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("4".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("5".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("6".into())},
        ];

        assert_eq!(entry1.avg_rating(&ratings, &triples), 2.0);
        assert_eq!(entry2.avg_rating(&ratings, &triples), 0.0);
    }

    #[test]
    fn test_sort_by_avg_rating(){
        let mut entries = vec![
            new_entry("a", 0.0, 0.0),
            new_entry("b", 0.0, 0.0),
            new_entry("c", 0.0, 0.0),
            new_entry("d", 0.0, 0.0),
            new_entry("e", 0.0, 0.0),
        ];

        let ratings = vec![
            new_rating("1", 0, RatingContext::Diversity),
            new_rating("2", 10, RatingContext::Diversity),
            new_rating("3", 3, RatingContext::Diversity),
            new_rating("4", -1, RatingContext::Diversity),
            new_rating("5", 0, RatingContext::Diversity),
        ];

        let triples = vec![
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("1".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("2".into())},
            Triple{subject: ObjectId::Entry("c".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("3".into())},
            Triple{subject: ObjectId::Entry("d".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("4".into())},
            Triple{subject: ObjectId::Entry("e".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("5".into())},
        ];

        entries.sort_by_avg_rating(&ratings, &triples);

        assert_eq!(entries[0].id, "b");
        assert_eq!(entries[1].id, "c");
        assert!(entries[2].id == "a" || entries[2].id == "e");
        assert!(entries[3].id == "a" || entries[3].id == "e");
        assert_eq!(entries[4].id, "d");

        // tests:
        // - negative ratings
    }

    #[test]
    fn sort_by_distance() {
        let mut entries = vec![new_entry("a", 1.0, 0.0),
                               new_entry("b", 0.0, 0.0),
                               new_entry("c", 1.0, 1.0),
                               new_entry("d", 0.0, 0.5),
                               new_entry("e", -1.0, -1.0)];
        let x = Coordinate {
            lat: 0.0,
            lng: 0.0,
        };
        entries.sort_by_distance_to(&x);
        assert_eq!(entries[0].id, "b");
        assert_eq!(entries[1].id, "d");
        assert_eq!(entries[2].id, "a");
        assert!(entries[3].id == "c" || entries[3].id == "e");
        assert!(entries[4].id == "c" || entries[4].id == "e");
    }

    use std::f64::{NAN, INFINITY};

    #[test]
    fn sort_with_invalid_coordinates() {
        let mut entries = vec![new_entry("a", 1.0, NAN),
                               new_entry("b", 1.0, INFINITY),
                               new_entry("c", 2.0, 0.0),
                               new_entry("d", NAN, NAN),
                               new_entry("e", 1.0, 0.0)];
        let x = Coordinate {
            lat: 0.0,
            lng: 0.0,
        };
        entries.sort_by_distance_to(&x);
        assert_eq!(entries[0].id, "e");
        assert_eq!(entries[1].id, "c");

        let mut entries =
            vec![new_entry("a", 2.0, 0.0), new_entry("b", 0.0, 0.0), new_entry("c", 1.0, 0.0)];

        let x = Coordinate {
            lat: NAN,
            lng: 0.0,
        };
        entries.sort_by_distance_to(&x);
        assert_eq!(entries[0].id, "a");
        assert_eq!(entries[1].id, "b");
        assert_eq!(entries[2].id, "c");
    }

}
<commit_msg>changed average rating calculation: always divide by 6 no matter whether rating context has ratings<commit_after>use entities::*;
use std::cmp::Ordering;
use std::iter::FilterMap;
use std::slice::Iter;
use super::geo::{self, Coordinate};

trait DistanceTo {
    fn distance_to(&self, &Coordinate) -> f64;
}

impl DistanceTo for Entry {
    fn distance_to(&self, c: &Coordinate) -> f64 {
        geo::distance(&Coordinate {
                          lat: self.lat,
                          lng: self.lng,
                      },
                      c)
    }
}

pub trait SortByDistanceTo {
    fn sort_by_distance_to(&mut self, &Coordinate);
}

impl SortByDistanceTo for Vec<Entry> {
    fn sort_by_distance_to(&mut self, c: &Coordinate) {
        if !(c.lat.is_finite() && c.lng.is_finite()) {
            return;
        }
        self.sort_by(|a, _|
            if a.lat.is_finite() && a.lng.is_finite() {
                Ordering::Less
            } else {
                warn!("invalid coordinate: {}/{}", a.lat, a.lng);
                Ordering::Greater
            }
        );
        self.sort_by(|a, b| {
            a.distance_to(c).partial_cmp(&b.distance_to(c)).unwrap_or(Ordering::Equal)
        })
    }
}

pub trait Rated {
    fn avg_rating(&self, &[Rating], &[Triple]) -> f64;
    fn avg_rating_for_context(&self, &[Rating], &Vec<(&String, &String)>, RatingContext) -> Option<f64>;
}

impl Rated for Entry {
    fn avg_rating(&self, ratings: &[Rating], triples: &[Triple]) -> f64 {
        let entry_ratings : Vec<(&String, &String)> = triples
            .into_iter()
            .filter_map(|x| match *x {
                Triple {
                    subject   : ObjectId::Entry(ref e_id),
                    predicate : Relation::IsRatedWith,
                    object    : ObjectId::Rating(ref r_id)
                } => Some((e_id, r_id)),
                _ => None
            })
            .filter(|entry_rating| *entry_rating.0 == self.id).collect();

        let avg_ratings = vec![
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Diversity),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Renewable),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Fairness),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Humanity),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Transparency),
            self.avg_rating_for_context(ratings, &entry_ratings, RatingContext::Solidarity),
        ];

        let sum = avg_ratings.iter().fold(0.0, |acc, &r| acc + r.unwrap_or(0.0));
        let num_rated_contexts = avg_ratings.iter().fold(0, |acc, &r| acc + if r.is_some() {1} else {0});

        if(num_rated_contexts > 0){
            sum / 6.0
        } else{
            0.0
        }
    }

    fn avg_rating_for_context(&self, ratings: &[Rating], entry_ratings: &Vec<(&String, &String)>, context: RatingContext) -> Option<f64> {
        let applicable_ratings : Vec<&Rating> = ratings.into_iter()
            .filter_map(|rating| if rating.context == context
                && entry_ratings.iter()
                .any(|entry_rating| *entry_rating.1 == rating.id) { Some(rating) } else { None })
            .collect();

        let sum = applicable_ratings.iter().fold(0, |acc, ref rating| acc + rating.value) as f64;
        let n = applicable_ratings.len();

        let avg = sum / n as f64;
        if avg.is_nan() {
            None
        } else {
            Some(avg as f64)
        }
    }
}

pub trait SortByAverageRating {
    fn sort_by_avg_rating(&mut self, &[Rating], &[Triple]);
}

impl SortByAverageRating for Vec<Entry> {
    fn sort_by_avg_rating(&mut self, ratings: &[Rating], triples: &[Triple]){
        self.sort_by(|a, b| {
            b.avg_rating(ratings, triples)
            .partial_cmp(&a.avg_rating(ratings, triples))
            .unwrap_or(Ordering::Equal)
        })
    }
}

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

    fn new_entry(id: &str, lat: f64, lng: f64) -> Entry {
        Entry{
            id          : id.into(),
            created     : 0,
            version     : 0,
            title       : "foo".into(),
            description : "bar".into(),
            lat         : lat,
            lng         : lng,
            street      : None,
            zip         : None,
            city        : None,
            country     : None,
            email       : None,
            telephone   : None,
            homepage    : None,
            categories  : vec![],
            license     : None,
        }
    }

    fn new_rating(id: &str, value: i8, context: RatingContext) -> Rating {
        Rating{
            id         : id.into(),
            created    : 0,
            title      : "blubb".into(),
            value      : value.into(),
            context    : context
        }
    }

    #[test]
    fn test_average_rating() {
        let entry1 = new_entry("a", 0.0, 0.0);
        let entry2 = new_entry("b", 0.0, 0.0);
        let entry3 = new_entry("c", 0.0, 0.0);

        let ratings = vec![
            new_rating("1", 0, RatingContext::Diversity),
            new_rating("2", 0, RatingContext::Diversity),
            new_rating("3", 3, RatingContext::Diversity),
            new_rating("4", 3, RatingContext::Diversity),
            new_rating("5", -3, RatingContext::Diversity),
            new_rating("6", 3, RatingContext::Diversity),
        ];

        let triples = vec![
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("1".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("2".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("3".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("4".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("5".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("6".into())},
        ];

        assert_eq!(entry1.avg_rating(&ratings, &triples), 0.25);
        assert_eq!(entry2.avg_rating(&ratings, &triples), 0.0);
        assert_eq!(entry3.avg_rating(&ratings, &triples), 0.0);
    }

    #[test]
    fn test_average_rating_different_contexts() {
        let entry1 = new_entry("a", 0.0, 0.0);
        let entry2 = new_entry("b", 0.0, 0.0);

        let ratings = vec![
            new_rating("1", 0, RatingContext::Diversity),
            new_rating("2", 10, RatingContext::Renewable),
            new_rating("3", 7, RatingContext::Fairness),
            new_rating("4", 9, RatingContext::Fairness),
            new_rating("5", -3, RatingContext::Diversity),
            new_rating("6", 3, RatingContext::Fairness),
        ];

        let triples = vec![
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("1".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("2".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("3".into())},
            Triple{subject: ObjectId::Entry("a".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("4".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("5".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("6".into())},
        ];

        assert_eq!(entry1.avg_rating(&ratings, &triples), 3.0);
        assert_eq!(entry2.avg_rating(&ratings, &triples), 0.0);
    }

    #[test]
    fn test_sort_by_avg_rating(){
        let mut entries = vec![
            new_entry("a", 0.0, 0.0),
            new_entry("b", 0.0, 0.0),
            new_entry("c", 0.0, 0.0),
            new_entry("d", 0.0, 0.0),
            new_entry("e", 0.0, 0.0),
        ];

        let ratings = vec![
            new_rating("1", 0, RatingContext::Diversity),
            new_rating("2", 10, RatingContext::Diversity),
            new_rating("3", 3, RatingContext::Diversity),
            new_rating("4", -1, RatingContext::Diversity),
            new_rating("5", 0, RatingContext::Diversity),
        ];

        let triples = vec![
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("1".into())},
            Triple{subject: ObjectId::Entry("b".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("2".into())},
            Triple{subject: ObjectId::Entry("c".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("3".into())},
            Triple{subject: ObjectId::Entry("d".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("4".into())},
            Triple{subject: ObjectId::Entry("e".into()), predicate: Relation::IsRatedWith, object: ObjectId::Rating("5".into())},
        ];

        entries.sort_by_avg_rating(&ratings, &triples);

        assert_eq!(entries[0].id, "b");
        assert_eq!(entries[1].id, "c");
        assert!(entries[2].id == "a" || entries[2].id == "e");
        assert!(entries[3].id == "a" || entries[3].id == "e");
        assert_eq!(entries[4].id, "d");

        // tests:
        // - negative ratings
    }

    #[test]
    fn sort_by_distance() {
        let mut entries = vec![new_entry("a", 1.0, 0.0),
                               new_entry("b", 0.0, 0.0),
                               new_entry("c", 1.0, 1.0),
                               new_entry("d", 0.0, 0.5),
                               new_entry("e", -1.0, -1.0)];
        let x = Coordinate {
            lat: 0.0,
            lng: 0.0,
        };
        entries.sort_by_distance_to(&x);
        assert_eq!(entries[0].id, "b");
        assert_eq!(entries[1].id, "d");
        assert_eq!(entries[2].id, "a");
        assert!(entries[3].id == "c" || entries[3].id == "e");
        assert!(entries[4].id == "c" || entries[4].id == "e");
    }

    use std::f64::{NAN, INFINITY};

    #[test]
    fn sort_with_invalid_coordinates() {
        let mut entries = vec![new_entry("a", 1.0, NAN),
                               new_entry("b", 1.0, INFINITY),
                               new_entry("c", 2.0, 0.0),
                               new_entry("d", NAN, NAN),
                               new_entry("e", 1.0, 0.0)];
        let x = Coordinate {
            lat: 0.0,
            lng: 0.0,
        };
        entries.sort_by_distance_to(&x);
        assert_eq!(entries[0].id, "e");
        assert_eq!(entries[1].id, "c");

        let mut entries =
            vec![new_entry("a", 2.0, 0.0), new_entry("b", 0.0, 0.0), new_entry("c", 1.0, 0.0)];

        let x = Coordinate {
            lat: NAN,
            lng: 0.0,
        };
        entries.sort_by_distance_to(&x);
        assert_eq!(entries[0].id, "a");
        assert_eq!(entries[1].id, "b");
        assert_eq!(entries[2].id, "c");
    }

}
<|endoftext|>


<commit_before>use rand;
use rand::Rng;
use std::collections::VecDeque;
use common::{ParamType, MoveDestination};
use piston_window::*;

pub enum Content {
    Number(u8),
    Mine(bool), // bool is true when this is the mine that caused you to loose the game.
    None,
}

struct Cell {
    content: Content,
    revealed: bool,
    marked: bool,
}

impl Cell {
    pub fn clear(&mut self) {
        self.content = Content::None;
        self.revealed = false;
        self.marked = false;
    }

    fn reveal(&mut self) -> &Content {
        self.revealed = true;
        &self.content
    }

    fn toggle_mark(&mut self) {
        self.marked = !self.marked;
    }
}

pub struct Field {
    cells: Vec<Cell>,
    width: u32,
    height: u32,
    mines: u32,
    size: u32,
    selected_x: u32,
    selected_y: u32,
    nubmers_total: u32,
    nubmers_opened: u32
}

impl Field {
    pub fn new(width: u32, height: u32, mines: u32) -> Field {
        let mut field = Field {
            width: width,
            height: height,
            cells: vec![],
            mines: mines,
            size: width*height,
            selected_x: width/2,
            selected_y: height/2,
            nubmers_total: 0,
            nubmers_opened: 0
        };
        field.reinit_vec();
        field.fill();
        field
    }

    fn reinit_vec(&mut self) {
        self.cells.clear();
        self.size = self.width*self.height;
        for _i in 0..self.size {
            self.cells.push(Cell{content: Content::None,
                                 revealed: false,
                                 marked: false});
        }
        self.selected_x = self.width/2;
        self.selected_y = self.height/2;
    }

    fn fill(&mut self) {
        self.clear();
        //todo: maybe a better algorithm. for now, this

        if self.mines > self.size {
            panic!("too many mines");// avoid an infinite loop.. could retern a result
        }
        let mut nmines = 0u32;
        while nmines < self.mines {
            let ind = rand::thread_rng().gen_range(0, self.size);
            let cell = self.get_cell_mut(ind);
            match cell.content {
                Content::Mine(_) => {
                    continue;
                },
                _ => {
                    cell.content = Content::Mine(false);
                    nmines += 1;
                },
            }
        }

        let mut i: i32 = -1;
        let w = self.width as i32;
        while i < (self.size - 1) as i32 {
            i += 1;
            match self.get_content_safe(i) {
                Some(&Content::None) => {
                    let ct_mine = |b| {
                        match b {
                            true => 1,
                            false => 0
                        }
                    };
                     // don`t care about row
                    let mut ct = ct_mine(self.is_mine_safe(i-w)) +
                                 ct_mine(self.is_mine_safe(i+w));
                    if i % w > 0 { // check left side position
                        ct += ct_mine(self.is_mine_safe(i-w-1)) +
                              ct_mine(self.is_mine_safe(i-1)) +
                              ct_mine(self.is_mine_safe(i+w-1));
                    }
                    if i % w < w - 1 { // check right side position
                        ct += ct_mine(self.is_mine_safe(i-w+1)) +
                              ct_mine(self.is_mine_safe(i+1)) +
                              ct_mine(self.is_mine_safe(i+w+1));
                    }
                    if ct > 0 {
                        self.get_cell_mut(i as u32).content = Content::Number(ct);
                        self.nubmers_total += 1;
                    }
                },
                _ => {}
            }
        }
    }

    fn clear(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).clear();
        }
        self.nubmers_opened = 0;
        self.nubmers_total = 0;
    }

    pub fn reveal(&mut self, i: u32) -> &Content {
        if !self.revealed(i) {
            if let &Content::Number(_i) = self.get_cell_mut(i).reveal() {
                self.nubmers_opened += 1;
            }
        }
        &self.get_content(i)
    }

    pub fn revealed(&self, i: u32) -> bool {
        self.get_cell(i).revealed
    }

    pub fn marked(&self, i: u32) -> bool {
        self.get_cell(i).marked
    }

    pub fn set_killer(&mut self, i: u32) {
        self.get_cell_mut(i).content = Content::Mine(true);
    }

    fn get_cell_mut(&mut self, i:u32) -> &mut Cell {
        self.cells.get_mut(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell_mut ({})", i))
    }

    fn get_cell(& self, i:u32) -> &Cell {
        self.cells.get(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell ({})", i))
    }

    fn get_content_safe(&self, i:i32) -> Option<&Content> {
        if (i < 0) || ((i as u32) >= self.size) {
            None
        } else {
            Some(self.get_content(i as u32))
        }
    }

    pub fn get_content(& self, i: u32) -> &Content {
        &self.get_cell(i).content
    }

    fn is_mine_safe(&self, i: i32) -> bool {
        match self.get_content_safe(i) {
            Some(&Content::Mine(_)) => true,
            _ => false
        }
    }

    pub fn get_width(&self) -> u32 {
        self.width
    }

    pub fn get_height(&self) -> u32 {
        self.height
    }

    pub fn get_size(&self) -> u32 {
        self.size
    }

    pub fn restart(&mut self) {
        self.fill();
    }

    pub fn reveal_all(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).revealed = true;
        }
    }

    pub fn chain_reveal(&mut self, u: u32) {
        if self.marked(u) {
            return;
        }
        let w = self.width as i32;
        // clojure to check for blank cells
        let mut check = |x, d: &mut VecDeque<i32>| {
            match self.get_content_safe(x) {
                Some(&Content::None) => {
                    if !self.revealed(x as u32) {
                        d.push_back(x);
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                Some(&Content::Number(_n)) => {
                    if !(self.revealed(x as u32)) {
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                _ => {}
            }
        };
        // BFS initialize
        let deq = &mut VecDeque::new();
        deq.push_back(u as i32);
        // BFS
        while !deq.is_empty() {
            let i = deq.pop_front().unwrap();
            // don`t care about row
            check(i-w, deq);
            check(i+w, deq);
            if i % w > 0 { // check left side position
                check(i-w-1, deq);
                check(i-1, deq);
                check(i+w-1, deq);
            }
            if i % w < w - 1 { // check right side position
                check(i-w+1, deq);
                check(i+1, deq);
                check(i+w+1, deq);
            }
        }
    }

    pub fn draw(&mut self,
            context: Context,
            graphics: &mut G2d,
            field_rect: [u32; 4],
            glyps: &mut Glyphs)
    {
        let cell_w = field_rect[2] / self.get_width();
        let cell_h = field_rect[3] / self.get_height();
        for i in 0..self.get_width() {
            for j in 0..self.get_height() {
                let ind = i + j*self.get_width();
                let transform = context.transform.trans((field_rect[0] + i*cell_w) as f64 + 5.0,
                                                        (field_rect[1] + (j+1)*cell_h) as f64 - 5.0);
                if self.revealed(ind) {
                    match *self.get_content(i + j*self.get_width()) {
                        Content::Mine(killer) => {
                            rectangle([1.0, 0.0, 0.0, 1.0],
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                            if killer {
                                text::Text::colored([1.0, 1.0, 1.0, 1.0], cell_h).draw(
                                    "*",
                                    glyps,
                                    &context.draw_state,
                                    transform,
                                    graphics
                                );
                            }
                        },
                        Content::Number(n) => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);

                            let text_color = match n {
                                1 => color::hex("0000ff"),
                                2 => color::hex("008000"),
                                3 => color::hex("ff0000"),
                                4 => color::hex("000080"),
                                5 => color::hex("800000"),
                                6 => color::hex("008080"),
                                7 => color::hex("000000"),
                                8 => color::hex("808080"),
                                _ => [0.0, 0.0, 0.0, 1.0]
                            };

                            text::Text::colored(text_color, cell_h).draw(
                                &*n.to_string(),
                                glyps,
                                &context.draw_state,
                                transform,
                                graphics
                            );
                        },
                        Content::None => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                        }
                    }
                } else {
                    // non revealed
                    rectangle(color::hex("303030"),
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
                if self.marked(ind) {
                    rectangle([0.0, 1.0, 0.0, 0.75],
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
            }
        }
        rectangle([0.5, 0.5, 0.5, 0.75],
                  [
                    (field_rect[0] + self.selected_x*cell_w) as f64,
                    (field_rect[1] + self.selected_y*cell_h) as f64,
                    cell_w as f64,
                    cell_h as f64
                  ],
                  context.transform,
                  graphics);
        for i in 0..self.get_width() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        (field_rect[0] + i*cell_w) as f64,
                        field_rect[1] as f64,
                        (field_rect[0] + i*cell_w) as f64,
                        (field_rect[1] + field_rect[3]) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
        for i in 0..self.get_height() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        field_rect[0] as f64,
                        (field_rect[1] + i*cell_h) as f64,
                        (field_rect[0] + field_rect[2]) as f64,
                        (field_rect[1] + i*cell_h) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
    }

    pub fn move_selection(&mut self, dest: MoveDestination) {
        match dest {
            MoveDestination::Up => {
                if self.selected_y > 0 {
                    self.selected_y -= 1;
                }
            },
            MoveDestination::Down => {
                if self.selected_y < self.height - 1 {
                    self.selected_y += 1;
                }
            },
            MoveDestination::Left => {
                if self.selected_x > 0 {
                    self.selected_x -= 1;
                }
            },
            MoveDestination::Right => {
                if self.selected_x < self.width - 1 {
                    self.selected_x += 1;
                }
            }
        }
    }

    pub fn get_selected_ind(&self) -> u32 {
        self.selected_x + self.selected_y*self.width
    }

    pub fn is_victory(&self) -> bool {
        self.nubmers_total == self.nubmers_opened
    }

    pub fn reinit_field(&mut self, num: u32, param: ParamType) {
        let mut restart_neded = false;
        match param {
            ParamType::Height => {
                if self.height != num {
                    self.height = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Width => {
                if self.width != num {
                    self.width = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Mines => {
                if self.mines != num {
                    self.mines = num;
                    restart_neded = true;
                }
            }
        }
        if restart_neded {
            self.restart();
        }
    }

    pub fn toggle_mark(&mut self, i: u32) {
        self.get_cell_mut(i).toggle_mark();
    }
}
<commit_msg>improvement<commit_after>use rand;
use rand::Rng;
use std::collections::VecDeque;
use common::{ParamType, MoveDestination};
use piston_window::*;

pub enum Content {
    Number(u8),
    Mine(bool), // bool is true when this is the mine that caused you to loose the game.
    None,
}

struct Cell {
    content: Content,
    revealed: bool,
    marked: bool,
}

impl Cell {
    pub fn clear(&mut self) {
        self.content = Content::None;
        self.revealed = false;
        self.marked = false;
    }

    fn reveal(&mut self) -> &Content {
        self.revealed = true;
        &self.content
    }

    fn toggle_mark(&mut self) {
        self.marked = !self.marked;
    }
}

pub struct Field {
    cells: Vec<Cell>,
    width: u32,
    height: u32,
    mines: u32,
    size: u32,
    selected_x: u32,
    selected_y: u32,
    nubmers_total: u32,
    nubmers_opened: u32
}

impl Field {
    pub fn new(width: u32, height: u32, mines: u32) -> Field {
        let mut field = Field {
            width: width,
            height: height,
            cells: vec![],
            mines: mines,
            size: width*height,
            selected_x: width/2,
            selected_y: height/2,
            nubmers_total: 0,
            nubmers_opened: 0
        };
        field.reinit_vec();
        field.fill();
        field
    }

    fn reinit_vec(&mut self) {
        self.cells.clear();
        self.size = self.width*self.height;
        for _i in 0..self.size {
            self.cells.push(Cell{content: Content::None,
                                 revealed: false,
                                 marked: false});
        }
        self.selected_x = self.width/2;
        self.selected_y = self.height/2;
    }

    fn fill(&mut self) {
        self.clear();
        let mut rng = rand::thread_rng();
        let mut shuffled_idx : Vec<u32> = (0..self.size).collect();
        rng.shuffle(&mut shuffled_idx);
        let _: Vec<&u32>  = shuffled_idx.iter()
            .take(self.mines as usize)
            .inspect(|&idx| self.get_cell_mut(*idx).content = Content::Mine(false))
            .collect(); // collect is required due to lazy eval (i think).

        let mut i: i32 = -1;
        let w = self.width as i32;
        while i < (self.size - 1) as i32 {
            i += 1;
            match self.get_content_safe(i) {
                Some(&Content::None) => {
                    let ct_mine = |b| {
                        match b {
                            true => 1,
                            false => 0
                        }
                    };
                     // don`t care about row
                    let mut ct = ct_mine(self.is_mine_safe(i-w)) +
                                 ct_mine(self.is_mine_safe(i+w));
                    if i % w > 0 { // check left side position
                        ct += ct_mine(self.is_mine_safe(i-w-1)) +
                              ct_mine(self.is_mine_safe(i-1)) +
                              ct_mine(self.is_mine_safe(i+w-1));
                    }
                    if i % w < w - 1 { // check right side position
                        ct += ct_mine(self.is_mine_safe(i-w+1)) +
                              ct_mine(self.is_mine_safe(i+1)) +
                              ct_mine(self.is_mine_safe(i+w+1));
                    }
                    if ct > 0 {
                        self.get_cell_mut(i as u32).content = Content::Number(ct);
                        self.nubmers_total += 1;
                    }
                },
                _ => {}
            }
        }
    }

    fn clear(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).clear();
        }
        self.nubmers_opened = 0;
        self.nubmers_total = 0;
    }

    pub fn reveal(&mut self, i: u32) -> &Content {
        if !self.revealed(i) {
            if let &Content::Number(_i) = self.get_cell_mut(i).reveal() {
                self.nubmers_opened += 1;
            }
        }
        &self.get_content(i)
    }

    pub fn revealed(&self, i: u32) -> bool {
        self.get_cell(i).revealed
    }

    pub fn marked(&self, i: u32) -> bool {
        self.get_cell(i).marked
    }

    pub fn set_killer(&mut self, i: u32) {
        self.get_cell_mut(i).content = Content::Mine(true);
    }

    fn get_cell_mut(&mut self, i:u32) -> &mut Cell {
        self.cells.get_mut(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell_mut ({})", i))
    }

    fn get_cell(& self, i:u32) -> &Cell {
        self.cells.get(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell ({})", i))
    }

    fn get_content_safe(&self, i:i32) -> Option<&Content> {
        if (i < 0) || ((i as u32) >= self.size) {
            None
        } else {
            Some(self.get_content(i as u32))
        }
    }

    pub fn get_content(& self, i: u32) -> &Content {
        &self.get_cell(i).content
    }

    fn is_mine_safe(&self, i: i32) -> bool {
        match self.get_content_safe(i) {
            Some(&Content::Mine(_)) => true,
            _ => false
        }
    }

    pub fn get_width(&self) -> u32 {
        self.width
    }

    pub fn get_height(&self) -> u32 {
        self.height
    }

    pub fn get_size(&self) -> u32 {
        self.size
    }

    pub fn restart(&mut self) {
        self.fill();
    }

    pub fn reveal_all(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).revealed = true;
        }
    }

    pub fn chain_reveal(&mut self, u: u32) {
        if self.marked(u) {
            return;
        }
        let w = self.width as i32;
        // clojure to check for blank cells
        let mut check = |x, d: &mut VecDeque<i32>| {
            match self.get_content_safe(x) {
                Some(&Content::None) => {
                    if !self.revealed(x as u32) {
                        d.push_back(x);
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                Some(&Content::Number(_n)) => {
                    if !(self.revealed(x as u32)) {
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                _ => {}
            }
        };
        // BFS initialize
        let deq = &mut VecDeque::new();
        deq.push_back(u as i32);
        // BFS
        while !deq.is_empty() {
            let i = deq.pop_front().unwrap();
            // don`t care about row
            check(i-w, deq);
            check(i+w, deq);
            if i % w > 0 { // check left side position
                check(i-w-1, deq);
                check(i-1, deq);
                check(i+w-1, deq);
            }
            if i % w < w - 1 { // check right side position
                check(i-w+1, deq);
                check(i+1, deq);
                check(i+w+1, deq);
            }
        }
    }

    pub fn draw(&mut self,
            context: Context,
            graphics: &mut G2d,
            field_rect: [u32; 4],
            glyps: &mut Glyphs)
    {
        let cell_w = field_rect[2] / self.get_width();
        let cell_h = field_rect[3] / self.get_height();
        for i in 0..self.get_width() {
            for j in 0..self.get_height() {
                let ind = i + j*self.get_width();
                let transform = context.transform.trans((field_rect[0] + i*cell_w) as f64 + 5.0,
                                                        (field_rect[1] + (j+1)*cell_h) as f64 - 5.0);
                if self.revealed(ind) {
                    match *self.get_content(i + j*self.get_width()) {
                        Content::Mine(killer) => {
                            rectangle([1.0, 0.0, 0.0, 1.0],
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                            if killer {
                                text::Text::colored([1.0, 1.0, 1.0, 1.0], cell_h).draw(
                                    "*",
                                    glyps,
                                    &context.draw_state,
                                    transform,
                                    graphics
                                );
                            }
                        },
                        Content::Number(n) => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);

                            let text_color = match n {
                                1 => color::hex("0000ff"),
                                2 => color::hex("008000"),
                                3 => color::hex("ff0000"),
                                4 => color::hex("000080"),
                                5 => color::hex("800000"),
                                6 => color::hex("008080"),
                                7 => color::hex("000000"),
                                8 => color::hex("808080"),
                                _ => [0.0, 0.0, 0.0, 1.0]
                            };

                            text::Text::colored(text_color, cell_h).draw(
                                &*n.to_string(),
                                glyps,
                                &context.draw_state,
                                transform,
                                graphics
                            );
                        },
                        Content::None => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                        }
                    }
                } else {
                    // non revealed
                    rectangle(color::hex("303030"),
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
                if self.marked(ind) {
                    rectangle([0.0, 1.0, 0.0, 0.75],
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
            }
        }
        rectangle([0.5, 0.5, 0.5, 0.75],
                  [
                    (field_rect[0] + self.selected_x*cell_w) as f64,
                    (field_rect[1] + self.selected_y*cell_h) as f64,
                    cell_w as f64,
                    cell_h as f64
                  ],
                  context.transform,
                  graphics);
        for i in 0..self.get_width() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        (field_rect[0] + i*cell_w) as f64,
                        field_rect[1] as f64,
                        (field_rect[0] + i*cell_w) as f64,
                        (field_rect[1] + field_rect[3]) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
        for i in 0..self.get_height() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        field_rect[0] as f64,
                        (field_rect[1] + i*cell_h) as f64,
                        (field_rect[0] + field_rect[2]) as f64,
                        (field_rect[1] + i*cell_h) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
    }

    pub fn move_selection(&mut self, dest: MoveDestination) {
        match dest {
            MoveDestination::Up => {
                if self.selected_y > 0 {
                    self.selected_y -= 1;
                }
            },
            MoveDestination::Down => {
                if self.selected_y < self.height - 1 {
                    self.selected_y += 1;
                }
            },
            MoveDestination::Left => {
                if self.selected_x > 0 {
                    self.selected_x -= 1;
                }
            },
            MoveDestination::Right => {
                if self.selected_x < self.width - 1 {
                    self.selected_x += 1;
                }
            }
        }
    }

    pub fn get_selected_ind(&self) -> u32 {
        self.selected_x + self.selected_y*self.width
    }

    pub fn is_victory(&self) -> bool {
        self.nubmers_total == self.nubmers_opened
    }

    pub fn reinit_field(&mut self, num: u32, param: ParamType) {
        let mut restart_neded = false;
        match param {
            ParamType::Height => {
                if self.height != num {
                    self.height = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Width => {
                if self.width != num {
                    self.width = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Mines => {
                if self.mines != num {
                    self.mines = num;
                    restart_neded = true;
                }
            }
        }
        if restart_neded {
            self.restart();
        }
    }

    pub fn toggle_mark(&mut self, i: u32) {
        self.get_cell_mut(i).toggle_mark();
    }
}
<|endoftext|>


<commit_before>//! Execute benchmarks in a sysroot.

use std::env;
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use std::str;
use std::f64;
use std::fs::{self, File};
use std::collections::{HashMap, HashSet};
use std::cmp;

use tempdir::TempDir;

use collector::{Benchmark as CollectedBenchmark, BenchmarkState, Patch, Run, Stat};

use failure::{err_msg, Error, ResultExt};
use rust_sysroot::sysroot::Sysroot;
use serde_json;

use Mode;

fn command_output(cmd: &mut Command) -> Result<process::Output, Error> {
    trace!("running: {:?}", cmd);
    let output = cmd.output()?;
    if !output.status.success() {
        bail!(
            "expected success, got {}\n\nstderr={}\n\n stdout={}",
            output.status,
            String::from_utf8_lossy(&output.stderr),
            String::from_utf8_lossy(&output.stdout)
        );
    }
    Ok(output)
}

fn touch_all(path: &Path) -> Result<(), Error> {
    let mut cmd = Command::new("bash");
    cmd.current_dir(path)
        .args(&["-c", "find . -name '*.rs' | xargs touch"]);
    command_output(&mut cmd)?;
    Ok(())
}

fn default_runs() -> usize {
    3
}

fn default_true() -> bool {
    true
}

#[derive(Debug, Clone, Deserialize)]
struct BenchmarkConfig {
    cargo_opts: Option<String>,
    cargo_rustc_opts: Option<String>,
    cargo_toml: Option<String>,
    #[serde(default)]
    disabled: bool,
    #[serde(default = "default_runs")]
    runs: usize,
    #[serde(default = "default_true")]
    run_optimized: bool,
    #[serde(default = "default_true")]
    run_debug: bool,
    #[serde(default = "default_true")]
    nll: bool,
}

impl Default for BenchmarkConfig {
    fn default() -> BenchmarkConfig {
        BenchmarkConfig {
            cargo_opts: None,
            cargo_rustc_opts: None,
            cargo_toml: None,
            disabled: false,
            runs: default_runs(),
            run_optimized: true,
            run_debug: true,
            nll: true,
        }
    }
}

pub struct Benchmark {
    pub name: String,
    pub path: PathBuf,
    patches: Vec<Patch>,
    config: BenchmarkConfig,
}

struct CargoProcess<'sysroot> {
    sysroot: &'sysroot Sysroot,
    incremental: Incremental,
    nll: bool,
    options: Options,
    perf: bool,
    manifest_path: String,
    cargo_args: Vec<String>,
    rustc_args: Vec<String>,
}

#[derive(Copy, Clone, Debug)]
struct Incremental(bool);

impl<'sysroot> CargoProcess<'sysroot> {
    fn base(&self) -> Command {
        let mut cmd = self.sysroot.command("cargo");
        cmd
            .env("SHELL", env::var_os("SHELL").unwrap_or_default())
            .env("RUSTC", &*FAKE_RUSTC)
            .env("RUSTC_REAL", &self.sysroot.rustc)
            .env(
                "CARGO_INCREMENTAL",
                &format!("{}", self.incremental.0 as usize),
            )
            .env("USE_PERF", &format!("{}", self.perf as usize));
        cmd
    }

    fn nll(mut self, nll: bool) -> Self {
        self.nll = nll;
        self
    }

    fn perf(mut self, perf: bool) -> Self {
        self.perf = perf;
        self
    }

    fn run(self, cwd: &Path, mode: CargoMode) -> Result<Vec<Stat>, Error> {
        let mut cmd = self.base();
        cmd.current_dir(cwd);
        cmd.arg(match mode {
            CargoMode::Build => "rustc",
            CargoMode::Clean => "clean",
        });
        {
            let mut pkgid_cmd = self.base();
            pkgid_cmd
                .current_dir(cwd)
                .arg("pkgid")
                .arg("--manifest-path")
                .arg(&self.manifest_path);
            let out = command_output(&mut pkgid_cmd)
                .unwrap_or_else(|e| {
                    panic!("failed to obtain pkgid in {:?}: {:?}", cwd, e);
                })
                .stdout;
            let package_id = str::from_utf8(&out).unwrap();
            cmd.arg("-p").arg(package_id.trim());
        }
        if mode == CargoMode::Build && self.options.check {
            cmd.arg("--profile").arg("check");
        }
        if self.options.release {
            cmd.arg("--release");
        }
        cmd.arg("--manifest-path").arg(&self.manifest_path);
        if mode == CargoMode::Build {
            cmd.args(&self.cargo_args);
            cmd.arg("--");
            if self.nll {
                cmd.arg("-Znll");
            }
            cmd.arg("-Ztime-passes");
            cmd.args(&self.rustc_args);
        }

        debug!("running cargo: {:?}", cmd);

        match mode {
            CargoMode::Build => loop {
                touch_all(&cwd)?;
                let output = command_output(&mut cmd)?;
                match process_output(output) {
                    Ok(stats) => return Ok(stats),
                    Err(DeserializeStatError::NoOutput(output)) => {
                        warn!(
                            "failed to deserialize stats, retrying; output: {:?}",
                            output
                        );
                    }
                    Err(e @ DeserializeStatError::ParseError { .. }) => {
                        panic!("process_output failed: {:?}", e);
                    }
                }
            },
            CargoMode::Clean => {
                let _output = command_output(&mut cmd)?;
                return Ok(Vec::new());
            }
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum CargoMode {
    Build,
    Clean,
}

#[derive(Debug, PartialEq, Clone, Copy)]
struct Options {
    release: bool,
    check: bool,
}

lazy_static! {
    static ref FAKE_RUSTC: PathBuf = {
        let mut fake_rustc = env::current_exe().unwrap();
        fake_rustc.pop();
        fake_rustc.push("rustc-fake");
        fake_rustc
    };
}

impl Benchmark {
    pub fn new(name: String, path: PathBuf) -> Result<Self, Error> {
        let mut patches = vec![];
        for entry in fs::read_dir(&path)? {
            let entry = entry?;
            let path = entry.path();
            if let Some(ext) = path.extension() {
                if ext == "patch" {
                    patches.push(path.clone());
                }
            }
        }

        patches.sort();

        let patches = patches.into_iter().map(|p| Patch::new(p)).collect();

        let config_path = path.join("perf-config.json");
        let config: BenchmarkConfig = if config_path.exists() {
            serde_json::from_reader(File::open(&config_path)
                .with_context(|_| format!("failed to open {:?}", config_path))?)
                .with_context(|_| {
                format!("failed to parse {:?}", config_path)
            })?
        } else {
            BenchmarkConfig::default()
        };

        Ok(Benchmark {
            name,
            path,
            patches,
            config,
        })
    }

    fn make_temp_dir(&self, base: &Path) -> Result<TempDir, Error> {
        let tmp_dir = TempDir::new(&format!("rustc-benchmark-{}", self.name))?;
        let mut cmd = Command::new("cp");
        cmd.arg("-r")
            .arg("-T")
            .arg("--")
            .arg(base)
            .arg(tmp_dir.path());
        command_output(&mut cmd).with_context(|_| format!("copying {} to tmp dir", self.name))?;
        Ok(tmp_dir)
    }

    fn mk_cargo_process<'a>(
        &self,
        sysroot: &'a Sysroot,
        incremental: Incremental,
        options: Options,
    ) -> CargoProcess<'a> {
        CargoProcess {
            sysroot: sysroot,
            incremental: incremental,
            options: options,
            perf: true,
            nll: false,
            manifest_path: self.config
                .cargo_toml
                .clone()
                .unwrap_or_else(|| String::from("Cargo.toml")),
            cargo_args: self.config
                .cargo_opts
                .clone()
                .unwrap_or_default()
                .split_whitespace()
                .map(String::from)
                .collect(),
            rustc_args: self.config
                .cargo_rustc_opts
                .clone()
                .unwrap_or_default()
                .split_whitespace()
                .map(String::from)
                .collect(),
        }
    }

    /// Run a specific benchmark on a specific commit
    pub fn run(
        &self,
        sysroot: &Sysroot,
        iterations: usize,
        mode: Mode,
    ) -> Result<CollectedBenchmark, Error> {
        let iterations = cmp::min(iterations, self.config.runs);
        if self.config.disabled {
            eprintln!("skipping {}: disabled", self.name);
            bail!("disabled benchmark");
        }

        let has_perf = Command::new("perf").output().is_ok();
        assert!(has_perf);

        let mut ret = CollectedBenchmark {
            name: self.name.clone(),
            runs: Vec::new(),
        };

        let mut opts = Vec::with_capacity(3);
        match mode {
            Mode::Normal => {
                if self.config.run_debug {
                    opts.push(Options {
                        check: true,
                        release: false,
                    });
                    opts.push(Options {
                        check: false,
                        release: false,
                    });
                }
                if self.config.run_optimized {
                    opts.push(Options {
                        check: false,
                        release: true,
                    });
                }
            }
            Mode::Test => {
                opts.push(Options {
                    check: true,
                    release: false,
                });
            }
        }

        for opt in opts {
            let mut clean_stats = Vec::new();
            let mut nll_stats = Vec::new();
            let mut incr_stats = Vec::new();
            let mut incr_clean_stats = Vec::new();
            let mut incr_patched_stats: Vec<(Patch, Vec<Vec<Stat>>)> = Vec::new();

            info!(
                "Benchmarking {} with release: {}, check: {}, iterations: {}",
                self.name, opt.release, opt.check, iterations
            );

            let base_build = self.make_temp_dir(&self.path)?;
            let clean = self.mk_cargo_process(sysroot, Incremental(false), opt)
                .run(base_build.path(), CargoMode::Build)?;
            clean_stats.push(clean);
            self.mk_cargo_process(sysroot, Incremental(false), opt)
                .perf(false)
                .run(base_build.path(), CargoMode::Clean)?;

            for i in 0..iterations {
                debug!("Benchmark iteration {}/{}", i + 1, iterations);
                let tmp_dir = self.make_temp_dir(base_build.path())?;

                let clean = self.mk_cargo_process(sysroot, Incremental(false), opt)
                    .run(tmp_dir.path(), CargoMode::Build)?;
                if self.config.nll {
                    let nll = self.mk_cargo_process(sysroot, Incremental(false), opt)
                        .nll(true)
                        .run(base_build.path(), CargoMode::Build)?;
                    nll_stats.push(nll);
                }
                let incr = self.mk_cargo_process(sysroot, Incremental(true), opt)
                    .run(tmp_dir.path(), CargoMode::Build)?;
                let incr_clean = self.mk_cargo_process(sysroot, Incremental(true), opt)
                    .run(tmp_dir.path(), CargoMode::Build)?;

                clean_stats.push(clean);
                incr_stats.push(incr);
                incr_clean_stats.push(incr_clean);

                for patch in &self.patches {
                    debug!("applying patch {}", patch.name);
                    patch.apply(tmp_dir.path()).map_err(|s| err_msg(s))?;
                    let out = self.mk_cargo_process(sysroot, Incremental(true), opt)
                        .run(tmp_dir.path(), CargoMode::Build)?;
                    if let Some(mut entry) = incr_patched_stats.iter_mut().find(|s| &s.0 == patch) {
                        entry.1.push(out);
                        continue;
                    }

                    incr_patched_stats.push((patch.clone(), vec![out]));
                }
            }

            ret.runs
                .push(process_stats(opt, BenchmarkState::Clean, clean_stats));
            if self.config.nll {
                ret.runs
                    .push(process_stats(opt, BenchmarkState::Nll, nll_stats));
            }
            ret.runs.push(process_stats(
                opt,
                BenchmarkState::IncrementalStart,
                incr_stats,
            ));
            ret.runs.push(process_stats(
                opt,
                BenchmarkState::IncrementalClean,
                incr_clean_stats,
            ));

            for (patch, results) in incr_patched_stats {
                ret.runs.push(process_stats(
                    opt,
                    BenchmarkState::IncrementalPatched(patch),
                    results,
                ));
            }
        }

        Ok(ret)
    }
}

#[derive(Fail, PartialEq, Eq, Debug)]
enum DeserializeStatError {
    #[fail(display = "could not deserialize empty output to stats, output: {:?}", _0)]
    NoOutput(process::Output),
    #[fail(display = "could not parse `{}` as a float", _0)]
    ParseError(String, #[fail(cause)] ::std::num::ParseFloatError),
}

fn process_output(output: process::Output) -> Result<Vec<Stat>, DeserializeStatError> {
    let stdout = String::from_utf8(output.stdout.clone()).expect("utf8 output");
    let mut stats = Vec::new();

    for line in stdout.lines() {
        // github.com/torvalds/linux/blob/bc78d646e708/tools/perf/Documentation/perf-stat.txt#L281
        macro_rules! get {
            ($e: expr) => {
                match $e {
                    Some(s) => s,
                    None => {
                        warn!("unhandled line: {}", line);
                        continue;
                    }
                }
            };
        }
        let mut parts = line.split(';').map(|s| s.trim());
        let cnt = get!(parts.next());
        let _unit = get!(parts.next());
        let name = get!(parts.next());
        let _time = get!(parts.next());
        let pct = get!(parts.next());
        if cnt == "<not supported>" {
            continue;
        }
        if !pct.starts_with("100.") {
            panic!(
                "measurement of `{}` only active for {}% of the time",
                name, pct
            );
        }
        stats.push(Stat {
            name: name.to_string(),
            cnt: cnt.parse()
                .map_err(|e| DeserializeStatError::ParseError(cnt.to_string(), e))?,
        });
    }

    if stats.is_empty() {
        return Err(DeserializeStatError::NoOutput(output));
    }

    Ok(stats)
}

fn process_stats(options: Options, state: BenchmarkState, runs: Vec<Vec<Stat>>) -> Run {
    let mut stats: HashMap<String, Vec<f64>> = HashMap::new();
    for run in runs.clone() {
        for stat in run {
            stats
                .entry(stat.name.clone())
                .or_insert_with(|| Vec::new())
                .push(stat.cnt);
        }
    }
    // all stats should be present in all runs
    let map = stats.values().map(|v| v.len()).collect::<HashSet<_>>();
    if map.len() != 1 {
        eprintln!("options: {:?}", options);
        eprintln!("state: {:?}", state);
        eprintln!("lengths: {:?}", map);
        eprintln!("runs: {:?}", runs);
        eprintln!("stats: {:?}", stats);
        panic!("expected all stats to be present in all runs");
    }
    let stats = stats
        .into_iter()
        .map(|(stat, counts)| Stat {
            name: stat,
            cnt: counts
                .into_iter()
                .fold(f64::INFINITY, |acc, v| f64::min(acc, v)),
        })
        .collect();

    Run {
        stats,
        check: options.check,
        release: options.release,
        state: state,
    }
}
<commit_msg>Move common code into CargoProcess::base.<commit_after>//! Execute benchmarks in a sysroot.

use std::env;
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use std::str;
use std::f64;
use std::fs::{self, File};
use std::collections::{HashMap, HashSet};
use std::cmp;

use tempdir::TempDir;

use collector::{Benchmark as CollectedBenchmark, BenchmarkState, Patch, Run, Stat};

use failure::{err_msg, Error, ResultExt};
use rust_sysroot::sysroot::Sysroot;
use serde_json;

use Mode;

fn command_output(cmd: &mut Command) -> Result<process::Output, Error> {
    trace!("running: {:?}", cmd);
    let output = cmd.output()?;
    if !output.status.success() {
        bail!(
            "expected success, got {}\n\nstderr={}\n\n stdout={}",
            output.status,
            String::from_utf8_lossy(&output.stderr),
            String::from_utf8_lossy(&output.stdout)
        );
    }
    Ok(output)
}

fn touch_all(path: &Path) -> Result<(), Error> {
    let mut cmd = Command::new("bash");
    cmd.current_dir(path)
        .args(&["-c", "find . -name '*.rs' | xargs touch"]);
    command_output(&mut cmd)?;
    Ok(())
}

fn default_runs() -> usize {
    3
}

fn default_true() -> bool {
    true
}

#[derive(Debug, Clone, Deserialize)]
struct BenchmarkConfig {
    cargo_opts: Option<String>,
    cargo_rustc_opts: Option<String>,
    cargo_toml: Option<String>,
    #[serde(default)]
    disabled: bool,
    #[serde(default = "default_runs")]
    runs: usize,
    #[serde(default = "default_true")]
    run_optimized: bool,
    #[serde(default = "default_true")]
    run_debug: bool,
    #[serde(default = "default_true")]
    nll: bool,
}

impl Default for BenchmarkConfig {
    fn default() -> BenchmarkConfig {
        BenchmarkConfig {
            cargo_opts: None,
            cargo_rustc_opts: None,
            cargo_toml: None,
            disabled: false,
            runs: default_runs(),
            run_optimized: true,
            run_debug: true,
            nll: true,
        }
    }
}

pub struct Benchmark {
    pub name: String,
    pub path: PathBuf,
    patches: Vec<Patch>,
    config: BenchmarkConfig,
}

struct CargoProcess<'sysroot> {
    sysroot: &'sysroot Sysroot,
    incremental: Incremental,
    nll: bool,
    options: Options,
    perf: bool,
    manifest_path: String,
    cargo_args: Vec<String>,
    rustc_args: Vec<String>,
}

#[derive(Copy, Clone, Debug)]
struct Incremental(bool);

impl<'sysroot> CargoProcess<'sysroot> {
    fn base_command(&self, cwd: &Path, subcommand: &str) -> Command {
        let mut cmd = self.sysroot.command("cargo");
        cmd
            .env("SHELL", env::var_os("SHELL").unwrap_or_default())
            .env("RUSTC", &*FAKE_RUSTC)
            .env("RUSTC_REAL", &self.sysroot.rustc)
            .env(
                "CARGO_INCREMENTAL",
                &format!("{}", self.incremental.0 as usize),
            )
            .env("USE_PERF", &format!("{}", self.perf as usize))
            .current_dir(cwd)
            .arg(subcommand)
            .arg("--manifest-path")
            .arg(&self.manifest_path);
        cmd
    }

    fn nll(mut self, nll: bool) -> Self {
        self.nll = nll;
        self
    }

    fn perf(mut self, perf: bool) -> Self {
        self.perf = perf;
        self
    }

    fn run(self, cwd: &Path, mode: CargoMode) -> Result<Vec<Stat>, Error> {
        let subcommand = match mode {
            CargoMode::Build => "rustc",
            CargoMode::Clean => "clean",
        };
        let mut cmd = self.base_command(cwd, subcommand);
        {
            let mut pkgid_cmd = self.base_command(cwd, "pkgid");
            let out = command_output(&mut pkgid_cmd)
                .unwrap_or_else(|e| {
                    panic!("failed to obtain pkgid in {:?}: {:?}", cwd, e);
                })
                .stdout;
            let package_id = str::from_utf8(&out).unwrap();
            cmd.arg("-p").arg(package_id.trim());
        }
        if mode == CargoMode::Build && self.options.check {
            cmd.arg("--profile").arg("check");
        }
        if self.options.release {
            cmd.arg("--release");
        }
        if mode == CargoMode::Build {
            cmd.args(&self.cargo_args);
            cmd.arg("--");
            if self.nll {
                cmd.arg("-Znll");
            }
            cmd.arg("-Ztime-passes");
            cmd.args(&self.rustc_args);
        }

        debug!("running cargo: {:?}", cmd);

        match mode {
            CargoMode::Build => loop {
                touch_all(&cwd)?;
                let output = command_output(&mut cmd)?;
                match process_output(output) {
                    Ok(stats) => return Ok(stats),
                    Err(DeserializeStatError::NoOutput(output)) => {
                        warn!(
                            "failed to deserialize stats, retrying; output: {:?}",
                            output
                        );
                    }
                    Err(e @ DeserializeStatError::ParseError { .. }) => {
                        panic!("process_output failed: {:?}", e);
                    }
                }
            },
            CargoMode::Clean => {
                let _output = command_output(&mut cmd)?;
                return Ok(Vec::new());
            }
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum CargoMode {
    Build,
    Clean,
}

#[derive(Debug, PartialEq, Clone, Copy)]
struct Options {
    release: bool,
    check: bool,
}

lazy_static! {
    static ref FAKE_RUSTC: PathBuf = {
        let mut fake_rustc = env::current_exe().unwrap();
        fake_rustc.pop();
        fake_rustc.push("rustc-fake");
        fake_rustc
    };
}

impl Benchmark {
    pub fn new(name: String, path: PathBuf) -> Result<Self, Error> {
        let mut patches = vec![];
        for entry in fs::read_dir(&path)? {
            let entry = entry?;
            let path = entry.path();
            if let Some(ext) = path.extension() {
                if ext == "patch" {
                    patches.push(path.clone());
                }
            }
        }

        patches.sort();

        let patches = patches.into_iter().map(|p| Patch::new(p)).collect();

        let config_path = path.join("perf-config.json");
        let config: BenchmarkConfig = if config_path.exists() {
            serde_json::from_reader(File::open(&config_path)
                .with_context(|_| format!("failed to open {:?}", config_path))?)
                .with_context(|_| {
                format!("failed to parse {:?}", config_path)
            })?
        } else {
            BenchmarkConfig::default()
        };

        Ok(Benchmark {
            name,
            path,
            patches,
            config,
        })
    }

    fn make_temp_dir(&self, base: &Path) -> Result<TempDir, Error> {
        let tmp_dir = TempDir::new(&format!("rustc-benchmark-{}", self.name))?;
        let mut cmd = Command::new("cp");
        cmd.arg("-r")
            .arg("-T")
            .arg("--")
            .arg(base)
            .arg(tmp_dir.path());
        command_output(&mut cmd).with_context(|_| format!("copying {} to tmp dir", self.name))?;
        Ok(tmp_dir)
    }

    fn mk_cargo_process<'a>(
        &self,
        sysroot: &'a Sysroot,
        incremental: Incremental,
        options: Options,
    ) -> CargoProcess<'a> {
        CargoProcess {
            sysroot: sysroot,
            incremental: incremental,
            options: options,
            perf: true,
            nll: false,
            manifest_path: self.config
                .cargo_toml
                .clone()
                .unwrap_or_else(|| String::from("Cargo.toml")),
            cargo_args: self.config
                .cargo_opts
                .clone()
                .unwrap_or_default()
                .split_whitespace()
                .map(String::from)
                .collect(),
            rustc_args: self.config
                .cargo_rustc_opts
                .clone()
                .unwrap_or_default()
                .split_whitespace()
                .map(String::from)
                .collect(),
        }
    }

    /// Run a specific benchmark on a specific commit
    pub fn run(
        &self,
        sysroot: &Sysroot,
        iterations: usize,
        mode: Mode,
    ) -> Result<CollectedBenchmark, Error> {
        let iterations = cmp::min(iterations, self.config.runs);
        if self.config.disabled {
            eprintln!("skipping {}: disabled", self.name);
            bail!("disabled benchmark");
        }

        let has_perf = Command::new("perf").output().is_ok();
        assert!(has_perf);

        let mut ret = CollectedBenchmark {
            name: self.name.clone(),
            runs: Vec::new(),
        };

        let mut opts = Vec::with_capacity(3);
        match mode {
            Mode::Normal => {
                if self.config.run_debug {
                    opts.push(Options {
                        check: true,
                        release: false,
                    });
                    opts.push(Options {
                        check: false,
                        release: false,
                    });
                }
                if self.config.run_optimized {
                    opts.push(Options {
                        check: false,
                        release: true,
                    });
                }
            }
            Mode::Test => {
                opts.push(Options {
                    check: true,
                    release: false,
                });
            }
        }

        for opt in opts {
            let mut clean_stats = Vec::new();
            let mut nll_stats = Vec::new();
            let mut incr_stats = Vec::new();
            let mut incr_clean_stats = Vec::new();
            let mut incr_patched_stats: Vec<(Patch, Vec<Vec<Stat>>)> = Vec::new();

            info!(
                "Benchmarking {} with release: {}, check: {}, iterations: {}",
                self.name, opt.release, opt.check, iterations
            );

            let base_build = self.make_temp_dir(&self.path)?;
            let clean = self.mk_cargo_process(sysroot, Incremental(false), opt)
                .run(base_build.path(), CargoMode::Build)?;
            clean_stats.push(clean);
            self.mk_cargo_process(sysroot, Incremental(false), opt)
                .perf(false)
                .run(base_build.path(), CargoMode::Clean)?;

            for i in 0..iterations {
                debug!("Benchmark iteration {}/{}", i + 1, iterations);
                let tmp_dir = self.make_temp_dir(base_build.path())?;

                let clean = self.mk_cargo_process(sysroot, Incremental(false), opt)
                    .run(tmp_dir.path(), CargoMode::Build)?;
                if self.config.nll {
                    let nll = self.mk_cargo_process(sysroot, Incremental(false), opt)
                        .nll(true)
                        .run(base_build.path(), CargoMode::Build)?;
                    nll_stats.push(nll);
                }
                let incr = self.mk_cargo_process(sysroot, Incremental(true), opt)
                    .run(tmp_dir.path(), CargoMode::Build)?;
                let incr_clean = self.mk_cargo_process(sysroot, Incremental(true), opt)
                    .run(tmp_dir.path(), CargoMode::Build)?;

                clean_stats.push(clean);
                incr_stats.push(incr);
                incr_clean_stats.push(incr_clean);

                for patch in &self.patches {
                    debug!("applying patch {}", patch.name);
                    patch.apply(tmp_dir.path()).map_err(|s| err_msg(s))?;
                    let out = self.mk_cargo_process(sysroot, Incremental(true), opt)
                        .run(tmp_dir.path(), CargoMode::Build)?;
                    if let Some(mut entry) = incr_patched_stats.iter_mut().find(|s| &s.0 == patch) {
                        entry.1.push(out);
                        continue;
                    }

                    incr_patched_stats.push((patch.clone(), vec![out]));
                }
            }

            ret.runs
                .push(process_stats(opt, BenchmarkState::Clean, clean_stats));
            if self.config.nll {
                ret.runs
                    .push(process_stats(opt, BenchmarkState::Nll, nll_stats));
            }
            ret.runs.push(process_stats(
                opt,
                BenchmarkState::IncrementalStart,
                incr_stats,
            ));
            ret.runs.push(process_stats(
                opt,
                BenchmarkState::IncrementalClean,
                incr_clean_stats,
            ));

            for (patch, results) in incr_patched_stats {
                ret.runs.push(process_stats(
                    opt,
                    BenchmarkState::IncrementalPatched(patch),
                    results,
                ));
            }
        }

        Ok(ret)
    }
}

#[derive(Fail, PartialEq, Eq, Debug)]
enum DeserializeStatError {
    #[fail(display = "could not deserialize empty output to stats, output: {:?}", _0)]
    NoOutput(process::Output),
    #[fail(display = "could not parse `{}` as a float", _0)]
    ParseError(String, #[fail(cause)] ::std::num::ParseFloatError),
}

fn process_output(output: process::Output) -> Result<Vec<Stat>, DeserializeStatError> {
    let stdout = String::from_utf8(output.stdout.clone()).expect("utf8 output");
    let mut stats = Vec::new();

    for line in stdout.lines() {
        // github.com/torvalds/linux/blob/bc78d646e708/tools/perf/Documentation/perf-stat.txt#L281
        macro_rules! get {
            ($e: expr) => {
                match $e {
                    Some(s) => s,
                    None => {
                        warn!("unhandled line: {}", line);
                        continue;
                    }
                }
            };
        }
        let mut parts = line.split(';').map(|s| s.trim());
        let cnt = get!(parts.next());
        let _unit = get!(parts.next());
        let name = get!(parts.next());
        let _time = get!(parts.next());
        let pct = get!(parts.next());
        if cnt == "<not supported>" {
            continue;
        }
        if !pct.starts_with("100.") {
            panic!(
                "measurement of `{}` only active for {}% of the time",
                name, pct
            );
        }
        stats.push(Stat {
            name: name.to_string(),
            cnt: cnt.parse()
                .map_err(|e| DeserializeStatError::ParseError(cnt.to_string(), e))?,
        });
    }

    if stats.is_empty() {
        return Err(DeserializeStatError::NoOutput(output));
    }

    Ok(stats)
}

fn process_stats(options: Options, state: BenchmarkState, runs: Vec<Vec<Stat>>) -> Run {
    let mut stats: HashMap<String, Vec<f64>> = HashMap::new();
    for run in runs.clone() {
        for stat in run {
            stats
                .entry(stat.name.clone())
                .or_insert_with(|| Vec::new())
                .push(stat.cnt);
        }
    }
    // all stats should be present in all runs
    let map = stats.values().map(|v| v.len()).collect::<HashSet<_>>();
    if map.len() != 1 {
        eprintln!("options: {:?}", options);
        eprintln!("state: {:?}", state);
        eprintln!("lengths: {:?}", map);
        eprintln!("runs: {:?}", runs);
        eprintln!("stats: {:?}", stats);
        panic!("expected all stats to be present in all runs");
    }
    let stats = stats
        .into_iter()
        .map(|(stat, counts)| Stat {
            name: stat,
            cnt: counts
                .into_iter()
                .fold(f64::INFINITY, |acc, v| f64::min(acc, v)),
        })
        .collect();

    Run {
        stats,
        check: options.check,
        release: options.release,
        state: state,
    }
}
<|endoftext|>


<commit_before>extern crate num;
extern crate nalgebra as na;

// As this goes up, so does simulation accuracy, but the reaction-diffusion stuff slows down.
pub const ACCURACY: f64 = 5.0;
pub const TOTAL_FLUIDS: usize = 8;
pub const NORMAL_DIFFUSION: [f64; TOTAL_FLUIDS] = [0.0004 * ACCURACY,
                                                   1.0,
                                                   0.5,
                                                   0.2 * ACCURACY,
                                                   SIGNAL_FLUID_DIFFUSION * ACCURACY,
                                                   SIGNAL_FLUID_DIFFUSION * ACCURACY,
                                                   SIGNAL_FLUID_DIFFUSION * ACCURACY,
                                                   SIGNAL_FLUID_DIFFUSION * ACCURACY];
pub const KILL_FLUID_NORMAL: f64 = 0.05;
pub const KILL_FLUID_DECAY: f64 = 0.01 * ACCURACY;
pub const KILL_FLUID_UPPER_THRESHOLD: f64 = 0.052;
pub const KILL_FLUID_LOWER_THRESHOLD: f64 = 0.048;
pub const SIGNAL_FLUID_PRODUCTION: f64 = 0.5;
pub const SIGNAL_FLUID_DIFFUSION: f64 = 0.01;
pub const SIGNAL_FLUID_DECAY: f64 = 0.1 * ACCURACY;
pub const B_FOOD_RATE: f64 = 0.003 * ACCURACY;

const TIMESTEP: f64 = 0.2 / ACCURACY;

pub enum DiffusionType {
    FlatSignals,
    DynSignals,
}

#[derive(Default, Debug)]
pub struct Solution {
    pub fluids: [f64; TOTAL_FLUIDS],
    pub coefficients: [f64; TOTAL_FLUIDS],
    pub diffuse: [f64; TOTAL_FLUIDS],
}

impl Solution {
    pub fn new(fluids: [f64; TOTAL_FLUIDS], coefficients: [f64; TOTAL_FLUIDS]) -> Self {
        Solution {
            fluids: fluids,
            coefficients: coefficients,
            diffuse: [0.0; TOTAL_FLUIDS],
        }
    }

    pub fn react_deltas(&self) -> [f64; TOTAL_FLUIDS] {
        let a = self.fluids[1];
        let b = self.fluids[2];
        let kill = self.fluids[3];
        let f = 0.029;
        let k = 0.057;
        [B_FOOD_RATE * b,
         -a * b * b + f * (1.0 - a),
         a * b * b - (k + f) * b,
         KILL_FLUID_DECAY * (KILL_FLUID_NORMAL - kill),
         -SIGNAL_FLUID_DECAY * self.fluids[4],
         -SIGNAL_FLUID_DECAY * self.fluids[5],
         -SIGNAL_FLUID_DECAY * self.fluids[6],
         -SIGNAL_FLUID_DECAY * self.fluids[7]]
    }

    pub fn diffuse_from(&mut self, other: &Solution, dtype: DiffusionType) {
        // Handle normal fluids.
        for i in 0..4 {
            self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
        }
        // Handle signal fluids.
        match dtype {
            DiffusionType::DynSignals => {
                for i in 4..TOTAL_FLUIDS {
                    self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
                }
            }
            DiffusionType::FlatSignals => {
                for i in 4..TOTAL_FLUIDS {
                    self.diffuse[i] += SIGNAL_FLUID_PRODUCTION * other.coefficients[i] / 6.0;
                }
            }
        }
    }

    pub fn end_cycle(&mut self) {
        let reacts = self.react_deltas();
        // Handle normal fluids.
        for i in 0..4 {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - self.coefficients[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
        // Handle signal fluids.
        for i in 4..TOTAL_FLUIDS {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - NORMAL_DIFFUSION[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
    }
}
<commit_msg>further increase simulation accuracy for longer simulation<commit_after>extern crate num;
extern crate nalgebra as na;

// As this goes up, so does simulation accuracy, but the reaction-diffusion stuff slows down.
pub const ACCURACY: f64 = 10.0;
pub const TOTAL_FLUIDS: usize = 8;
pub const NORMAL_DIFFUSION: [f64; TOTAL_FLUIDS] = [0.0004 * ACCURACY,
                                                   1.0,
                                                   0.5,
                                                   0.2 * ACCURACY,
                                                   SIGNAL_FLUID_DIFFUSION * ACCURACY,
                                                   SIGNAL_FLUID_DIFFUSION * ACCURACY,
                                                   SIGNAL_FLUID_DIFFUSION * ACCURACY,
                                                   SIGNAL_FLUID_DIFFUSION * ACCURACY];
pub const KILL_FLUID_NORMAL: f64 = 0.05;
pub const KILL_FLUID_DECAY: f64 = 0.01 * ACCURACY;
pub const KILL_FLUID_UPPER_THRESHOLD: f64 = 0.052;
pub const KILL_FLUID_LOWER_THRESHOLD: f64 = 0.048;
pub const SIGNAL_FLUID_PRODUCTION: f64 = 0.5;
pub const SIGNAL_FLUID_DIFFUSION: f64 = 0.01;
pub const SIGNAL_FLUID_DECAY: f64 = 0.1 * ACCURACY;
pub const B_FOOD_RATE: f64 = 0.003 * ACCURACY;

const TIMESTEP: f64 = 0.2 / ACCURACY;

pub enum DiffusionType {
    FlatSignals,
    DynSignals,
}

#[derive(Default, Debug)]
pub struct Solution {
    pub fluids: [f64; TOTAL_FLUIDS],
    pub coefficients: [f64; TOTAL_FLUIDS],
    pub diffuse: [f64; TOTAL_FLUIDS],
}

impl Solution {
    pub fn new(fluids: [f64; TOTAL_FLUIDS], coefficients: [f64; TOTAL_FLUIDS]) -> Self {
        Solution {
            fluids: fluids,
            coefficients: coefficients,
            diffuse: [0.0; TOTAL_FLUIDS],
        }
    }

    pub fn react_deltas(&self) -> [f64; TOTAL_FLUIDS] {
        let a = self.fluids[1];
        let b = self.fluids[2];
        let kill = self.fluids[3];
        let f = 0.029;
        let k = 0.057;
        [B_FOOD_RATE * b,
         -a * b * b + f * (1.0 - a),
         a * b * b - (k + f) * b,
         KILL_FLUID_DECAY * (KILL_FLUID_NORMAL - kill),
         -SIGNAL_FLUID_DECAY * self.fluids[4],
         -SIGNAL_FLUID_DECAY * self.fluids[5],
         -SIGNAL_FLUID_DECAY * self.fluids[6],
         -SIGNAL_FLUID_DECAY * self.fluids[7]]
    }

    pub fn diffuse_from(&mut self, other: &Solution, dtype: DiffusionType) {
        // Handle normal fluids.
        for i in 0..4 {
            self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
        }
        // Handle signal fluids.
        match dtype {
            DiffusionType::DynSignals => {
                for i in 4..TOTAL_FLUIDS {
                    self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
                }
            }
            DiffusionType::FlatSignals => {
                for i in 4..TOTAL_FLUIDS {
                    self.diffuse[i] += SIGNAL_FLUID_PRODUCTION * other.coefficients[i] / 6.0;
                }
            }
        }
    }

    pub fn end_cycle(&mut self) {
        let reacts = self.react_deltas();
        // Handle normal fluids.
        for i in 0..4 {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - self.coefficients[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
        // Handle signal fluids.
        for i in 4..TOTAL_FLUIDS {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - NORMAL_DIFFUSION[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
    }
}
<|endoftext|>


<commit_before>extern crate server;
use std::io::{self, stdout, Write};
use server::parse;
use server::query;
use server::auth;

fn main() {
    print!("Username: ");
    let username = read_query();
    let mut user = auth::User { _name: username.into(), _currentDatabase: None };
    println!("to exit program type 'exit'");
    print!("Sql Query: ");
    let mut query = read_query();
    while query != "exit" {
        execute(&query, & mut user);
        print!("Sql Query: ");
        query = read_query();
    }

}

fn execute(query: &str, user: & mut auth::User) {
        let ast = parse::parse(query);

        match ast {
        Ok(tree) => {
                println!("{:?}", tree);
                match query::execute_from_ast(tree, user) {
                    Ok(s) => println!("Resultset: {:?}", s),
                    Err(error) => println!("{:?}", error),
                };
            },
        Err(error) => println!("{:?}", error),
}
}

pub fn read_query() -> String {
        let e = stdout().flush();
        match e {
            Ok(_) => {},
            Err(_) => {},
        }
        let a = read_line();
        return a;
}

fn read_line() -> String {
    let mut input = String::new();
    loop {
        match io::stdin().read_line(&mut input) {
            Ok(_) => {
                match &*input {
                    "\n" => return input,
                    _ => return input.trim().into()
                }
            },
            _ => { }
        }
    }
}
<commit_msg>solves error in query_example #1<commit_after>extern crate server;
use std::io::{self, stdout, Write};
use server::parse;
use server::query;
use server::auth;

fn main() {
    print!("Username: ");
    let username = read_query();
    let mut user = auth::User { _name: username.into(), _currentDatabase: None };
    println!("to exit program type 'exit'");
    print!("Sql Query: ");
    let mut query = read_query();
    while query != "exit" {
        //execute(&query, & mut user);
        //print!("Sql Query: ");
        //query = read_query();
    }

}

fn execute(query: &str, user: & mut auth::User) {
        let ast = parse::parse(query);

        match ast {
        Ok(tree) => {
                println!("{:?}", tree);
                match query::execute_from_ast(tree, user) {
                    Ok(s) => println!("Resultset: {:?}", s),
                    Err(error) => println!("{:?}", error),
                };
            },
        Err(error) => println!("{:?}", error),
}
}

pub fn read_query() -> String {
        let e = stdout().flush();
        match e {
            Ok(_) => {},
            Err(_) => {},
        }
        let a = read_line();
        return a;
}

fn read_line() -> String {
    let mut input = String::new();
    loop {
        match io::stdin().read_line(&mut input) {
            Ok(_) => {
                match &*input {
                    "\n" => return input,
                    _ => return input.trim().into()
                }
            },
            _ => { }
        }
    }
}
<|endoftext|>