<commit_before>#![allow(dead_code)]

#[macro_use]
extern crate pest;

extern crate rand;

mod parse;

use pest::*;
use parse::*;

#[derive(Debug)]
pub struct Roller<'a> {
    roll: &'a str,
    total: i32,
}

impl<'a> Roller<'a> {
     fn new(roll: &str) -> Roller {
         let mut parser = Rdp::new(StringInput::new(roll));
         parser.expression();

         Roller{
             roll: roll,
             total: parser.compute()
         }
     }

     fn reroll(&mut self) {
         let mut parser = Rdp::new(StringInput::new(self.roll));
         parser.expression();

         self.total = parser.compute();
     }
}

#[test]
fn it_works() {
    let mut roller = Roller::new("4d6");
    let orig = roller.total;

    assert!((4 <= roller.total) && (roller.total <= 24));

    roller.reroll();

    assert!(orig != roller.total);
}<commit_msg>Implement total() method<commit_after>#![allow(dead_code)]

#[macro_use]
extern crate pest;

extern crate rand;

mod parse;

use pest::*;
use parse::*;

#[derive(Debug)]
pub struct Roller<'a> {
    roll: &'a str,
    total: i32,
}

impl<'a> Roller<'a> {
     fn new(roll: &str) -> Roller {
         let mut parser = Rdp::new(StringInput::new(roll));
         parser.expression();

         Roller{
             roll: roll,
             total: parser.compute()
         }
     }

     fn reroll(&mut self) {
         let mut parser = Rdp::new(StringInput::new(self.roll));
         parser.expression();

         self.total = parser.compute();
     }

     fn total(&self) -> i32 {
         self.total
     }
}

#[test]
fn it_works() {
    let mut roller = Roller::new("4d6");
    let orig = roller.total();

    assert!((4 <= roller.total()) && (roller.total() <= 24));

    roller.reroll();

    assert!(orig != roller.total());
}<|endoftext|>


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

use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

extern crate git2;
extern crate glob;
extern crate rustc_serialize;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

#[derive(RustcDecodable)]
pub struct CrateInfo {
    pub name: String,
    pub vers: String,
    pub deps: Vec<DepInfo>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

#[derive(RustcDecodable)]
pub struct DepInfo {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<String>
}

pub struct CratesIndex {
    path: PathBuf,
}

impl CratesIndex {
    /// Construct a new CratesIndex supplying a path where the index lives or should live
    pub fn new(path: PathBuf) -> CratesIndex {
        CratesIndex{path: path}
    }

    /// Determines if *anything* exists at the path specified from the constructor
    pub fn exists(&self) -> bool {
        fs::metadata(&self.path).is_ok()
    }

    /// Clones the index to the path specified from the constructor
    pub fn clone(&self) -> Result<(), git2::Error> {
        let _ = try!(git2::Repository::clone(INDEX_GIT_URL, &self.path));
        Ok(())
    }

    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.json_paths()
            .iter()
            .find(|path| path.file_name().unwrap().to_str().unwrap().eq_ignore_ascii_case(crate_name))
            .map(Crate::from_index_path)
    }

    // TODO: this should be crate_iter that returns an Iterator
    pub fn crates(&self) -> Vec<Crate> {
        self.json_paths()
            .iter()
            .map(Crate::from_index_path)
            .collect::<Vec<_>>()
    }

    /// Returns all the `.json` files in the index
    pub fn json_paths(&self) -> Vec<PathBuf> {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;

        let glob_pattern = format!("{}/*/*/*", self.path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", self.path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let index_paths = index_paths1.chain(index_paths2);
        index_paths.map(|glob_result| glob_result.unwrap()).collect()
    }

    /// Generates a map of dependencies where the keys are crate names and the values are vectors
    /// of crate names that are its dependencies
    pub fn dependency_map(&self) -> HashMap<String, Vec<String>> {
        let mut map = HashMap::new();
        for crate_ in self.crates().iter() {
            let version = crate_.latest_version();
            let mut deps_names = version.deps.iter().map(|d| d.name.clone()).collect::<Vec<_>>();
            deps_names.sort_by(|a, b| a.cmp(b));
            deps_names.dedup();
            map.insert(version.name.clone(), deps_names);
        }

        map
    }
}

pub struct Crate {
    infos: Vec<CrateInfo>,
}

impl Crate {
    pub fn from_index_path(index_path: &PathBuf) -> Crate {
        let mut infos = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let info: CrateInfo = rustc_serialize::json::decode(&line.unwrap()).unwrap();
            infos.push(info);
        }
        Crate {infos: infos}
    }

    pub fn latest_version(&self) -> &CrateInfo {
        &self.infos[self.infos.len()]
    }
}

#[test]
fn test_dependencies() {
    let index = CratesIndex::new("_test".into());
    if !index.exists() {
        index.clone().unwrap();
    }
}
<commit_msg>Rename a few structs and fields<commit_after>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

extern crate git2;
extern crate glob;
extern crate rustc_serialize;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of crate published to the index
#[derive(RustcDecodable)]
pub struct Version {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

/// A single dependency of a specific crate version
#[derive(RustcDecodable)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<String>
}

pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new(path: PathBuf) -> Index {
        Index{path: path}
    }

    /// Determines if *anything* exists at the path specified from the constructor
    pub fn exists(&self) -> bool {
        fs::metadata(&self.path).is_ok()
    }

    /// Clones the index to the path specified from the constructor
    pub fn clone(&self) -> Result<(), git2::Error> {
        let _ = try!(git2::Repository::clone(INDEX_GIT_URL, &self.path));
        Ok(())
    }

    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.json_paths()
            .iter()
            .find(|path| path.file_name().unwrap().to_str().unwrap().eq_ignore_ascii_case(crate_name))
            .map(Crate::from_index_path)
    }

    // TODO: this should be crate_iter that returns an Iterator
    pub fn crates(&self) -> Vec<Crate> {
        self.json_paths()
            .iter()
            .map(Crate::from_index_path)
            .collect::<Vec<_>>()
    }

    /// Returns all the `.json` files in the index
    pub fn json_paths(&self) -> Vec<PathBuf> {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;

        let glob_pattern = format!("{}/*/*/*", self.path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", self.path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let index_paths = index_paths1.chain(index_paths2);
        index_paths.map(|glob_result| glob_result.unwrap()).collect()
    }

    /// Generates a map of dependencies where the keys are crate names and the values are vectors
    /// of crate names that are its dependencies
    pub fn dependency_map(&self) -> HashMap<String, Vec<String>> {
        let mut map = HashMap::new();
        for crate_ in self.crates().iter() {
            let version = crate_.latest_version();
            let mut deps_names = version.deps.iter().map(|d| d.name.clone()).collect::<Vec<_>>();
            deps_names.sort_by(|a, b| a.cmp(b));
            deps_names.dedup();
            map.insert(version.name.clone(), deps_names);
        }

        map
    }
}

pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn from_index_path(index_path: &PathBuf) -> Crate {
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = rustc_serialize::json::decode(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate {versions: versions}
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len()]
    }
}

#[test]
fn test_dependencies() {
    let index = Index::new("_test".into());
    if !index.exists() {
        index.clone().unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 oauth-client-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Performs topological sorting.

#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::fmt;
use std::hash::Hash;
use std::iter::FromIterator;

#[derive(Clone)]
struct Dependency<T> {
    num_prec: usize,
    succ: HashSet<T>,
}

impl<T: Hash + Eq> Dependency<T> {
    fn new() -> Dependency<T> {
        Dependency {
            num_prec: 0,
            succ: HashSet::new(),
        }
    }
}

/// Performs topological sorting.
#[derive(Clone)]
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>,
}

impl<T: Hash + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    /// # extern crate topological_sort;
    /// # fn main() {
    /// use topological_sort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert!(ts.pop_all().is_empty());
    /// # }
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> {
        TopologicalSort { top: HashMap::new() }
    }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> usize {
        self.top.len()
    }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.top.is_empty()
    }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.insert(dep);
            }
            Entry::Occupied(e) => {
                if !e.into_mut().succ.insert(succ.clone()) {
                    // Already registered
                    return;
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.insert(dep);
            }
            Entry::Occupied(e) => {
                e.into_mut().num_prec += 1;
            }
        }
    }

    /// Registers a dependency link.
    pub fn add_link(&mut self, link: DependencyLink<T>) {
        self.add_dependency(link.prec, link.succ)
    }

    /// Inserts an element, without adding any dependencies from or to it.
    ///
    /// If the `TopologicalSort` did not have this element present, `true` is returned.
    ///
    /// If the `TopologicalSort` already had this element present, `false` is returned.
    pub fn insert(&mut self, elt: T) -> bool {
        match self.top.entry(elt) {
            Entry::Vacant(e) => {
                let dep = Dependency::new();
                let _ = e.insert(dep);
                true
            }
            Entry::Occupied(_) => false,
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if
    /// there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.peek()
            .map(T::clone)
            .map(|key| {
                     let _ = self.remove(&key);
                     key
                 })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty
    /// vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in keys.iter() {
            let _ = self.remove(k);
        }
        keys
    }

    /// Return a reference to the first item that does not depend on any other items, or `None` if
    /// there is no such item.
    pub fn peek(&self) -> Option<&T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k)
            .next()
    }

    /// Return a vector of references to all items that do not depend on any other items, or an
    /// empty vector if there are no such items.
    pub fn peek_all(&self) -> Vec<&T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k)
            .collect::<Vec<_>>()
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in p.succ.iter() {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: PartialOrd + Eq + Hash + Clone> FromIterator<T> for TopologicalSort<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> TopologicalSort<T> {
        let mut top = TopologicalSort::new();
        let mut seen = Vec::<T>::default();
        for item in iter {
            top.insert(item.clone());
            for seen_item in seen.iter().cloned() {
                match seen_item.partial_cmp(&item) {
                    Some(Ordering::Less) => {
                        top.add_dependency(seen_item, item.clone());
                    }
                    Some(Ordering::Greater) => {
                        top.add_dependency(item.clone(), seen_item);
                    }
                    _ => (),
                }
            }
            seen.push(item);
        }
        top
    }
}

/// A link between two items in a sort.
#[derive(Copy, Clone, Debug)]
pub struct DependencyLink<T> {
    /// The element which is depened upon by `succ`.
    pub prec: T,
    /// The element which depends on `prec`.
    pub succ: T,
}

impl<T> From<(T, T)> for DependencyLink<T> {
    fn from(tuple: (T, T)) -> Self {
        DependencyLink {
            succ: tuple.0,
            prec: tuple.1,
        }
    }
}

impl<T: Eq + Hash + Clone> FromIterator<DependencyLink<T>> for TopologicalSort<T> {
    fn from_iter<I: IntoIterator<Item = DependencyLink<T>>>(iter: I) -> TopologicalSort<T> {
        let mut top = TopologicalSort::new();
        for link in iter {
            top.add_link(link);
        }
        top
    }
}

impl<T: Hash + Eq + Clone> Iterator for TopologicalSort<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.pop()
    }
}

impl<T: fmt::Debug + Hash + Eq> fmt::Debug for Dependency<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "prec={}, succ={:?}", self.num_prec, self.succ)
    }
}

impl<T: fmt::Debug + Hash + Eq + Clone> fmt::Debug for TopologicalSort<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.top)
    }
}

#[cfg(test)]
mod test {
    use super::TopologicalSort;
    use std::iter::FromIterator;

    #[test]
    fn from_iter() {
        let t = vec![4, 3, 3, 5, 7, 6, 8];
        let mut ts = TopologicalSort::<i32>::from_iter(t);
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(Some(5), ts.next());
        assert_eq!(Some(6), ts.next());
        assert_eq!(Some(7), ts.next());
        assert_eq!(Some(8), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<i32>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[i32], ts: &mut TopologicalSort<i32>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, &v[..]);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }

    #[test]
    fn cyclic_deadlock() {
        let mut ts = TopologicalSort::new();
        ts.add_dependency("stone", "sharp");

        ts.add_dependency("bucket", "hole");
        ts.add_dependency("hole", "straw");
        ts.add_dependency("straw", "axe");
        ts.add_dependency("axe", "sharp");
        ts.add_dependency("sharp", "water");
        ts.add_dependency("water", "bucket");
        assert_eq!(ts.pop(), Some("stone"));
        assert!(ts.pop().is_none());
        println!("{:?}", ts);
    }
}
<commit_msg>Add clippy lints<commit_after>// Copyright 2016 oauth-client-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Performs topological sorting.

#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

#![cfg_attr(feature = "cargo-clippy", warn(if_not_else))]
#![cfg_attr(feature = "cargo-clippy", warn(invalid_upcast_comparisons))]
#![cfg_attr(feature = "cargo-clippy", warn(items_after_statements))]
#![cfg_attr(feature = "cargo-clippy", warn(mut_mut))]
#![cfg_attr(feature = "cargo-clippy", warn(never_loop))]
#![cfg_attr(feature = "cargo-clippy", warn(nonminimal_bool))]
#![cfg_attr(feature = "cargo-clippy", warn(option_map_unwrap_or))]
#![cfg_attr(feature = "cargo-clippy", warn(option_map_unwrap_or_else))]
#![cfg_attr(feature = "cargo-clippy", warn(option_unwrap_used))]
#![cfg_attr(feature = "cargo-clippy", warn(result_unwrap_used))]
#![cfg_attr(feature = "cargo-clippy", warn(used_underscore_binding))]

use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::fmt;
use std::hash::Hash;
use std::iter::FromIterator;

#[derive(Clone)]
struct Dependency<T> {
    num_prec: usize,
    succ: HashSet<T>,
}

impl<T: Hash + Eq> Dependency<T> {
    fn new() -> Dependency<T> {
        Dependency {
            num_prec: 0,
            succ: HashSet::new(),
        }
    }
}

/// Performs topological sorting.
#[derive(Clone)]
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>,
}

impl<T: Hash + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    /// # extern crate topological_sort;
    /// # fn main() {
    /// use topological_sort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert!(ts.pop_all().is_empty());
    /// # }
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> {
        TopologicalSort { top: HashMap::new() }
    }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> usize {
        self.top.len()
    }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.top.is_empty()
    }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.insert(dep);
            }
            Entry::Occupied(e) => {
                if !e.into_mut().succ.insert(succ.clone()) {
                    // Already registered
                    return;
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.insert(dep);
            }
            Entry::Occupied(e) => {
                e.into_mut().num_prec += 1;
            }
        }
    }

    /// Registers a dependency link.
    pub fn add_link(&mut self, link: DependencyLink<T>) {
        self.add_dependency(link.prec, link.succ)
    }

    /// Inserts an element, without adding any dependencies from or to it.
    ///
    /// If the `TopologicalSort` did not have this element present, `true` is returned.
    ///
    /// If the `TopologicalSort` already had this element present, `false` is returned.
    pub fn insert(&mut self, elt: T) -> bool {
        match self.top.entry(elt) {
            Entry::Vacant(e) => {
                let dep = Dependency::new();
                let _ = e.insert(dep);
                true
            }
            Entry::Occupied(_) => false,
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if
    /// there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.peek()
            .map(T::clone)
            .map(|key| {
                     let _ = self.remove(&key);
                     key
                 })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty
    /// vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in &keys {
            let _ = self.remove(k);
        }
        keys
    }

    /// Return a reference to the first item that does not depend on any other items, or `None` if
    /// there is no such item.
    pub fn peek(&self) -> Option<&T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k)
            .next()
    }

    /// Return a vector of references to all items that do not depend on any other items, or an
    /// empty vector if there are no such items.
    pub fn peek_all(&self) -> Vec<&T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k)
            .collect::<Vec<_>>()
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in &p.succ {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: PartialOrd + Eq + Hash + Clone> FromIterator<T> for TopologicalSort<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> TopologicalSort<T> {
        let mut top = TopologicalSort::new();
        let mut seen = Vec::<T>::default();
        for item in iter {
            top.insert(item.clone());
            for seen_item in seen.iter().cloned() {
                match seen_item.partial_cmp(&item) {
                    Some(Ordering::Less) => {
                        top.add_dependency(seen_item, item.clone());
                    }
                    Some(Ordering::Greater) => {
                        top.add_dependency(item.clone(), seen_item);
                    }
                    _ => (),
                }
            }
            seen.push(item);
        }
        top
    }
}

/// A link between two items in a sort.
#[derive(Copy, Clone, Debug)]
pub struct DependencyLink<T> {
    /// The element which is depened upon by `succ`.
    pub prec: T,
    /// The element which depends on `prec`.
    pub succ: T,
}

impl<T> From<(T, T)> for DependencyLink<T> {
    fn from(tuple: (T, T)) -> Self {
        DependencyLink {
            succ: tuple.0,
            prec: tuple.1,
        }
    }
}

impl<T: Eq + Hash + Clone> FromIterator<DependencyLink<T>> for TopologicalSort<T> {
    fn from_iter<I: IntoIterator<Item = DependencyLink<T>>>(iter: I) -> TopologicalSort<T> {
        let mut top = TopologicalSort::new();
        for link in iter {
            top.add_link(link);
        }
        top
    }
}

impl<T: Hash + Eq + Clone> Iterator for TopologicalSort<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.pop()
    }
}

impl<T: fmt::Debug + Hash + Eq> fmt::Debug for Dependency<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "prec={}, succ={:?}", self.num_prec, self.succ)
    }
}

impl<T: fmt::Debug + Hash + Eq + Clone> fmt::Debug for TopologicalSort<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.top)
    }
}

#[cfg(test)]
mod test {
    use super::TopologicalSort;
    use std::iter::FromIterator;

    #[test]
    fn from_iter() {
        let t = vec![4, 3, 3, 5, 7, 6, 8];
        let mut ts = TopologicalSort::<i32>::from_iter(t);
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(Some(5), ts.next());
        assert_eq!(Some(6), ts.next());
        assert_eq!(Some(7), ts.next());
        assert_eq!(Some(8), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<i32>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[i32], ts: &mut TopologicalSort<i32>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, &v[..]);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }

    #[test]
    fn cyclic_deadlock() {
        let mut ts = TopologicalSort::new();
        ts.add_dependency("stone", "sharp");

        ts.add_dependency("bucket", "hole");
        ts.add_dependency("hole", "straw");
        ts.add_dependency("straw", "axe");
        ts.add_dependency("axe", "sharp");
        ts.add_dependency("sharp", "water");
        ts.add_dependency("water", "bucket");
        assert_eq!(ts.pop(), Some("stone"));
        assert!(ts.pop().is_none());
        println!("{:?}", ts);
    }
}
<|endoftext|>


<commit_before>extern crate toml;
extern crate shellexpand;

// Import traits
use std::io::prelude::Read;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

#[derive(Debug)]
enum OnSuccess {
    Continue,
    Echo {message: String},
    Warn {message: String},
    Abort {message: String},
}

#[derive(Debug)]
enum OnFailure {
    Continue,
    Echo {message: String},
    Warn {message: String},
    Abort {message: String},
}

#[derive(Debug)]
enum Step {
    Echo {name: String, message: String},
    Run {name: String, command: String, arguments: String, on_success: OnSuccess, on_failure: OnFailure},
    Shell {name: String, command: String, on_success: OnSuccess, on_failure: OnFailure},
    SetEnv {variable: String, value: String},
}

fn parse_toml(filename: &str) -> Vec<Step> {

    println!("Reading toml file {}", filename);

    // Read toml file content
    let mut input = String::new();
    std::fs::File::open(&filename).and_then(|mut f| {
        f.read_to_string(&mut input)
    }).unwrap();

    // Pase toml file
    let mut parser = toml::Parser::new(&input);

    let toml = parser.parse().unwrap_or_else(|| {
        for err in &parser.errors {
            let (loline, locol) = parser.to_linecol(err.lo);
            let (hiline, hicol) = parser.to_linecol(err.hi);
            println!("{}:{}:{}-{}:{} error: {}",
                     filename, loline, locol, hiline, hicol, err.desc);
        }
        panic!("Error parsing toml file.");
    });

    // println!("toml: {:#?}", toml);

    // Parse "variables" table
    for (variable, value) in toml.get("variables").unwrap().as_table().unwrap() {
        let value = value.as_str().unwrap();
        // println!("variable: {}   value: {}", variable, value);
        std::env::set_var(variable, value);
    }

    // Parse "steps" table
    let mut steps = Vec::<Step>::with_capacity(10);

    for step in toml.get("step").unwrap().as_slice().unwrap() {
        let action = step.as_table().unwrap().get("action").unwrap().as_str().unwrap();
        let name = step.as_table().unwrap().get("name").unwrap().as_str().unwrap().to_string();
        let details = step.as_table().unwrap().get("details").unwrap().as_table().unwrap();
        let step = match action {
            "echo" => {
                let message = details.get("message").unwrap().as_str().unwrap().to_string();
                Step::Echo {name: name, message: message}
            },
            "run" => {
                let command = details.get("command").unwrap().as_str().unwrap().to_string();

                // Allow non-existing 'arguments' field, defaulting to empty string.
                let arguments_option = details.get("arguments");
                let arguments = match arguments_option {
                    None => String::new(),
                    Some(arguments_toml_value) => arguments_toml_value.as_str().unwrap().to_string(),
                };

                let on_success = match details.get("on_success") {
                    None => {
                        println!("WARNING: No 'on_success' set for {:?}, default of 'OnSuccess::Continue'", name);
                        OnSuccess::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "echo" => OnSuccess::Echo {message: message.as_str().unwrap().to_string()},
                            "warn" => OnSuccess::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnSuccess::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                let on_failure = match details.get("on_failure") {
                    None => {
                        println!("WARNING: No 'on_failure' set for {:?}, default of 'OnFailure::Continue'", name);
                        OnFailure::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "echo" => OnFailure::Echo {message: message.as_str().unwrap().to_string()},
                            "warn" => OnFailure::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnFailure::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                Step::Run {name: name, command: command, arguments: arguments, on_success: on_success, on_failure: on_failure}
            },
            "setenv" => {
                let variable = details.get("variable").unwrap().as_str().unwrap().to_string();
                let value = details.get("value").unwrap().as_str().unwrap().to_string();
                Step::SetEnv {variable: variable, value: value}
            },
            "shell" => {
                let command = details.get("command").unwrap().as_str().unwrap().to_string();
                // FIXME: Add possibility to store stdout/stderr in variable.

                let on_success = match details.get("on_success") {
                    None => {
                        println!("WARNING: No 'on_success' set for {:?}, default of 'OnSuccess::Continue'", name);
                        OnSuccess::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "echo" => OnSuccess::Echo {message: message.as_str().unwrap().to_string()},
                            "warn" => OnSuccess::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnSuccess::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                let on_failure = match details.get("on_failure") {
                    None => {
                        println!("WARNING: No 'on_failure' set for {:?}, default of 'OnFailure::Continue'", name);
                        OnFailure::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "echo" => OnFailure::Echo {message: message.as_str().unwrap().to_string()},
                            "warn" => OnFailure::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnFailure::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                Step::Shell {name: name, command: command, on_success: on_success, on_failure: on_failure}
            },
            _ => {
                println!("Unknown action '{}' in toml file", action);
                unimplemented!();
            },
        };
        // println!("Step: {:?}", step);

        steps.push(step);
    }

    steps
}

pub fn execute_steps(filename: &str) {

    let steps = parse_toml(filename);

    println!("Steps: {:#?}", steps);

    // Loop over steps
    let nb_steps = steps.len();
    for (idx, step) in steps.into_iter().enumerate() {
        // println!("Step {}/{} -- ", idx+1, nb_steps);
        match step {
            Step::Echo {name, message} => {
                // NOTE: If an environment variable is non-existing, the following line will panic.
                println!("{}", shellexpand::full(&message).unwrap());
            },
            Step::Run {name, command, arguments, on_success, on_failure} => {
                // NOTE: If an environment variable is non-existing, the following line will panic.
                let command: String = shellexpand::full(&command).unwrap().to_string();
                // NOTE: If an environment variable is non-existing, the following line will panic.
                let arguments: String = shellexpand::full(&arguments).unwrap().to_string();
                println!("    command: {} {}", command, arguments);
                let arguments: Vec<&str> = arguments.split(' ').collect();
                // println!("    command: {}   arguments: {:?}", command, arguments);
                let output = std::process::Command::new(command)
                                                       .args(&arguments)
                                                       .output()
                                                       .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

                // println!("output: {:#?}", output);

                // Print stdout
                println!("{}", String::from_utf8_lossy(&output.stdout));
                println!("{}", String::from_utf8_lossy(&output.stderr));

                if output.status.success() {
                    println!("Success!");
                    match on_success {
                        OnSuccess::Continue => {},
                        OnSuccess::Echo {message} => {
                            println!("{}", message);
                        },
                        OnSuccess::Warn {message} => {
                            println!("WARNING: {}", message);
                        },
                        OnSuccess::Abort {message} => {
                            println!("ABORT: {}", message);
                            break;
                        },
                    }
                } else {
                    match on_failure {
                        OnFailure::Continue => {},
                        OnFailure::Echo {message} => {
                            println!("{}", message);
                        },
                        OnFailure::Warn {message} => {
                            println!("WARNING: {}", message);
                        },
                        OnFailure::Abort {message} => {
                            println!("ABORT: {}", message);
                            break;
                        },
                    }
                }
            },
            Step::SetEnv {variable, value} => {
                std::env::set_var(variable, value);
            },
            Step::Shell {name, command, on_success, on_failure} => {
                let shell = "sh";
                println!("    command: {} -c '{}'", shell, command);
                let output = std::process::Command::new(shell)
                                                       .arg("-c")
                                                       .arg(command)
                                                       .output()
                                                       .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

               // Print stdout
               println!("{}", String::from_utf8_lossy(&output.stdout));
               println!("{}", String::from_utf8_lossy(&output.stderr));

               if output.status.success() {
                   println!("Success!");
                   match on_success {
                       OnSuccess::Continue => {},
                       OnSuccess::Echo {message} => {
                           println!("{}", message);
                       },
                       OnSuccess::Warn {message} => {
                           println!("WARNING: {}", message);
                       },
                       OnSuccess::Abort {message} => {
                           println!("ABORT: {}", message);
                           break;
                       },
                   }
               } else {
                   match on_failure {
                       OnFailure::Continue => {},
                       OnFailure::Echo {message} => {
                           println!("{}", message);
                       },
                       OnFailure::Warn {message} => {
                           println!("WARNING: {}", message);
                       },
                       OnFailure::Abort {message} => {
                           println!("ABORT: {}", message);
                           break;
                       },
                   }
               }
            },
        }
    }

}
<commit_msg>Support saving stdout to variable, showing it, or pipe it.<commit_after>extern crate toml;
extern crate shellexpand;

// Import traits
use std::io::prelude::Read;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

#[derive(Debug)]
enum OnSuccess {
    Continue,
    Echo {message: String},
    Warn {message: String},
    Abort {message: String},
}

#[derive(Debug)]
enum OnFailure {
    Continue,
    Echo {message: String},
    Warn {message: String},
    Abort {message: String},
}

#[derive(Debug)]
enum Pipe {
    Null,
    StdOut,
    StdErr,
    Variable {name: String},
    File {filename: String},
}

#[derive(Debug)]
enum Step {
    Echo {name: String, message: String},
    Run {name: String, command: String, arguments: String, on_success: OnSuccess, on_failure: OnFailure},
    Shell {name: String, command: String, stdout: Pipe, on_success: OnSuccess, on_failure: OnFailure},
    SetEnv {variable: String, value: String},
}

fn parse_toml(filename: &str) -> Vec<Step> {

    println!("Reading toml file {}", filename);

    // Read toml file content
    let mut input = String::new();
    std::fs::File::open(&filename).and_then(|mut f| {
        f.read_to_string(&mut input)
    }).unwrap();

    // Pase toml file
    let mut parser = toml::Parser::new(&input);

    let toml = parser.parse().unwrap_or_else(|| {
        for err in &parser.errors {
            let (loline, locol) = parser.to_linecol(err.lo);
            let (hiline, hicol) = parser.to_linecol(err.hi);
            println!("{}:{}:{}-{}:{} error: {}",
                     filename, loline, locol, hiline, hicol, err.desc);
        }
        panic!("Error parsing toml file.");
    });

    // println!("toml: {:#?}", toml);

    // Parse "variables" table
    for (variable, value) in toml.get("variables").unwrap().as_table().unwrap() {
        let value = value.as_str().unwrap();
        // println!("variable: {}   value: {}", variable, value);
        std::env::set_var(variable, value);
    }

    // Parse "steps" table
    let mut steps = Vec::<Step>::with_capacity(10);

    for step in toml.get("step").unwrap().as_slice().unwrap() {
        let action = step.as_table().unwrap().get("action").unwrap().as_str().unwrap();
        let name = step.as_table().unwrap().get("name").unwrap().as_str().unwrap().to_string();
        let details = step.as_table().unwrap().get("details").unwrap().as_table().unwrap();
        let step = match action {
            "echo" => {
                let message = details.get("message").unwrap().as_str().unwrap().to_string();
                Step::Echo {name: name, message: message}
            },
            "run" => {
                let command = details.get("command").unwrap().as_str().unwrap().to_string();

                // Allow non-existing 'arguments' field, defaulting to empty string.
                let arguments_option = details.get("arguments");
                let arguments = match arguments_option {
                    None => String::new(),
                    Some(arguments_toml_value) => arguments_toml_value.as_str().unwrap().to_string(),
                };

                let on_success = match details.get("on_success") {
                    None => {
                        println!("WARNING: No 'on_success' set for {:?}, default of 'OnSuccess::Continue'", name);
                        OnSuccess::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "echo" => OnSuccess::Echo {message: message.as_str().unwrap().to_string()},
                            "warn" => OnSuccess::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnSuccess::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                let on_failure = match details.get("on_failure") {
                    None => {
                        println!("WARNING: No 'on_failure' set for {:?}, default of 'OnFailure::Continue'", name);
                        OnFailure::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "echo" => OnFailure::Echo {message: message.as_str().unwrap().to_string()},
                            "warn" => OnFailure::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnFailure::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                Step::Run {name: name, command: command, arguments: arguments, on_success: on_success, on_failure: on_failure}
            },
            "setenv" => {
                let variable = details.get("variable").unwrap().as_str().unwrap().to_string();
                let value = details.get("value").unwrap().as_str().unwrap().to_string();
                Step::SetEnv {variable: variable, value: value}
            },
            "shell" => {
                let command = details.get("command").unwrap().as_str().unwrap().to_string();

                let stdout = match details.get("stdout") {
                    None => {
                        Pipe::StdOut
                    },
                    Some(toml_value) => {
                        Pipe::Variable {name: toml_value.as_str().unwrap().to_owned()}
                    }
                };

                let on_success = match details.get("on_success") {
                    None => {
                        println!("WARNING: No 'on_success' set for {:?}, default of 'OnSuccess::Continue'", name);
                        OnSuccess::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "echo" => OnSuccess::Echo {message: message.as_str().unwrap().to_string()},
                            "warn" => OnSuccess::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnSuccess::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                let on_failure = match details.get("on_failure") {
                    None => {
                        println!("WARNING: No 'on_failure' set for {:?}, default of 'OnFailure::Continue'", name);
                        OnFailure::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "echo" => OnFailure::Echo {message: message.as_str().unwrap().to_string()},
                            "warn" => OnFailure::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnFailure::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                Step::Shell {name: name, command: command, stdout: stdout, on_success: on_success, on_failure: on_failure}
            },
            _ => {
                println!("Unknown action '{}' in toml file", action);
                unimplemented!();
            },
        };
        // println!("Step: {:?}", step);

        steps.push(step);
    }

    steps
}

pub fn execute_steps(filename: &str) {

    let steps = parse_toml(filename);

    println!("Steps: {:#?}", steps);

    // Loop over steps
    let nb_steps = steps.len();
    for (idx, step) in steps.into_iter().enumerate() {
        // println!("Step {}/{} -- ", idx+1, nb_steps);
        match step {
            Step::Echo {name, message} => {
                // NOTE: If an environment variable is non-existing, the following line will panic.
                println!("{}", shellexpand::full(&message).unwrap());
            },
            Step::Run {name, command, arguments, on_success, on_failure} => {
                // NOTE: If an environment variable is non-existing, the following line will panic.
                let command: String = shellexpand::full(&command).unwrap().to_string();
                // NOTE: If an environment variable is non-existing, the following line will panic.
                let arguments: String = shellexpand::full(&arguments).unwrap().to_string();
                println!("    command: {} {}", command, arguments);
                let arguments: Vec<&str> = arguments.split(' ').collect();
                // println!("    command: {}   arguments: {:?}", command, arguments);
                let output = std::process::Command::new(command)
                                                       .args(&arguments)
                                                       .output()
                                                       .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

                // println!("output: {:#?}", output);

                // Print stdout
                println!("{}", String::from_utf8_lossy(&output.stdout));
                println!("{}", String::from_utf8_lossy(&output.stderr));

                if output.status.success() {
                    println!("Success!");
                    match on_success {
                        OnSuccess::Continue => {},
                        OnSuccess::Echo {message} => {
                            println!("{}", message);
                        },
                        OnSuccess::Warn {message} => {
                            println!("WARNING: {}", message);
                        },
                        OnSuccess::Abort {message} => {
                            println!("ABORT: {}", message);
                            break;
                        },
                    }
                } else {
                    match on_failure {
                        OnFailure::Continue => {},
                        OnFailure::Echo {message} => {
                            println!("{}", message);
                        },
                        OnFailure::Warn {message} => {
                            println!("WARNING: {}", message);
                        },
                        OnFailure::Abort {message} => {
                            println!("ABORT: {}", message);
                            break;
                        },
                    }
                }
            },
            Step::SetEnv {variable, value} => {
                std::env::set_var(variable, value);
            },
            Step::Shell {name, command, stdout, on_success, on_failure} => {
                let shell = "sh";
                println!("    command: {} -c '{}'", shell, command);
                let output = std::process::Command::new(shell)
                                                       .arg("-c")
                                                       .arg(command)
                                                       .output()
                                                       .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

               // Print stdout
                match stdout {
                    Pipe::Null => { },
                    Pipe::StdOut => {
                        println!("{}", String::from_utf8_lossy(&output.stdout));
                    },
                    Pipe::StdErr => {
                        // FIXME: Outout to stderr, not stdout
                        unimplemented!();
                    },
                    Pipe::Variable {name} => {
                        std::env::set_var(name, String::from_utf8_lossy(&output.stdout).into_owned());
                    },
                    Pipe::File {filename} => {
                        // FIXME: Save to file
                        unimplemented!();
                    }
                };

               if output.status.success() {
                   println!("Success!");
                   match on_success {
                       OnSuccess::Continue => {},
                       OnSuccess::Echo {message} => {
                           println!("{}", message);
                       },
                       OnSuccess::Warn {message} => {
                           println!("WARNING: {}", message);
                       },
                       OnSuccess::Abort {message} => {
                           println!("ABORT: {}", message);
                           break;
                       },
                   }
               } else {
                   match on_failure {
                       OnFailure::Continue => {},
                       OnFailure::Echo {message} => {
                           println!("{}", message);
                       },
                       OnFailure::Warn {message} => {
                           println!("WARNING: {}", message);
                       },
                       OnFailure::Abort {message} => {
                           println!("ABORT: {}", message);
                           break;
                       },
                   }
               }
            },
        }
    }

}
<|endoftext|>


<commit_before>extern crate rand;

use rand::{Rand, Rng};
use rand::Closed01 as RandClosed01;

/// Encapsulates a floating point number in the range [0, 1] including both endpoints.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Closed01<F>(F);

impl Closed01<f32> {
    #[inline(always)]
    pub fn new(f: f32) -> Closed01<f32> {
        assert!(f >= 0.0 && f <= 1.0);
        Closed01(f)
    }

    #[inline(always)]
    pub fn zero() -> Closed01<f32> {
        Closed01(0.0)
    }

    #[inline(always)]
    pub fn middle() -> Closed01<f32> {
        Closed01(0.5)
    }

    #[inline(always)]
    pub fn one() -> Closed01<f32> {
        Closed01(1.0)
    }

    #[inline(always)]
    /// Returns the smaller of the two.
    pub fn min(self, other: Closed01<f32>) -> Closed01<f32> {
        if self.0 <= other.0 {
            self
        } else {
            other
        }
    }

    #[inline(always)]
    /// Returns the greater of the two.
    pub fn max(self, other: Closed01<f32>) -> Closed01<f32> {
        if self.0 >= other.0 {
            self
        } else {
            other
        }
    }

    #[inline(always)]
    /// Returns the distance between the two numbers.
    pub fn distance(self, other: Closed01<f32>) -> Closed01<f32> {
        let d = (self.0 - other.0).abs();
        debug_assert!(d >= 0.0 && d <= 1.0);
        Closed01(d)
    }

    #[inline(always)]
    pub fn get(self) -> f32 {
        debug_assert!(self.0 >= 0.0 && self.0 <= 1.0);
        self.0
    }

    #[inline(always)]
    /// The average of two values.
    pub fn average(self: Closed01<f32>, other: Closed01<f32>) -> Closed01<f32> {
        let avg = (self.get() + other.get()) / 2.0;
        debug_assert!(avg >= 0.0 && avg <= 1.0);
        Closed01(avg)
    }

    #[inline(always)]
    /// Saturating add
    pub fn saturating_add(self, other: Closed01<f32>) -> Closed01<f32> {
        let mut sum = self.0 + other.0;
        if sum > 1.0 {
            sum = 1.0;
        }
        debug_assert!(sum >= 0.0 && sum <= 1.0);
        Closed01(sum)
    }

    #[inline(always)]
    /// Saturating sub
    pub fn saturating_sub(self, other: Closed01<f32>) -> Closed01<f32> {
        let mut sub = self.0 - other.0;
        if sub < 0.0 {
            sub = 0.0;
        }
        debug_assert!(sub >= 0.0 && sub <= 1.0);
        Closed01(sub)
    }

    #[inline(always)]
    /// Multiplies both numbers
    pub fn mul(self, scalar: Closed01<f32>) -> Closed01<f32> {
        let s = self.get() * scalar.get();
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }

    #[inline(always)]
    pub fn approx_eq(self, other: Closed01<f32>, eps: Closed01<f32>) -> bool {
        self.distance(other) < eps
    }

    #[inline(always)]
    /// This scales `self` towards 1.0
    pub fn scale_up(self, other: Closed01<f32>) -> Closed01<f32> {
        let s = self.0 + (1.0 - self.0) * other.0;
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }

    #[inline(always)]
    /// This scales `self` towards 0.0
    pub fn scale_down(self, other: Closed01<f32>) -> Closed01<f32> {
        let s = self.0 - self.0 * other.0;
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }

    #[inline(always)]
    /// Invert the number (Mirror at 0.5; 1.0 - number).
    pub fn inv(self) -> Closed01<f32> {
        let s = 1.0 - self.0;
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }

    #[inline(always)]
    /// Round the number to 0.0 or 1.0
    pub fn round(self) -> Closed01<f32> {
        if self.0 < 0.5 {
            Closed01::zero()
        } else {
            Closed01::one()
        }
    }
}

impl Into<f32> for Closed01<f32> {
    fn into(self) -> f32 {
        self.get()
    }
}

impl Rand for Closed01<f32> {
    fn rand<R: Rng>(rng: &mut R) -> Closed01<f32> {
        Closed01::new(RandClosed01::<f32>::rand(rng).0)
    }
}

#[test]
fn test_into() {
    assert_eq!(0.5f32, Closed01::new(0.5).into());
}

#[test]
fn test_minmax() {
    let a = Closed01::new(0.4);
    let b = Closed01::new(0.5);
    assert_eq!(a, a.min(b));
    assert_eq!(a, b.min(a));
    assert_eq!(b, a.max(b));
    assert_eq!(b, b.max(a));
}

#[test]
fn test_saturation() {
    let a = Closed01::new(0.4);
    let b = Closed01::new(0.5);
    let c = Closed01::new(0.6);

    assert_eq!(0.9, a.saturating_add(b).get());
    assert_eq!(1.0, a.saturating_add(c).get());
    assert_eq!(1.0, b.saturating_add(c).get());

    assert_eq!(0.0, a.saturating_sub(b).get());
    assert_eq!(0.0, a.saturating_sub(c).get());
    assert_eq!(0.0, b.saturating_sub(c).get());

    let eps = Closed01::new(0.001);
    assert!(c.saturating_sub(b).approx_eq(Closed01::new(0.1), eps));
    assert!(c.saturating_sub(a).approx_eq(Closed01::new(0.2), eps));
}

#[test]
fn test_scale_up() {
    let a = Closed01::new(0.0);
    let b = Closed01::new(1.0);
    let c = Closed01::new(0.5);

    assert_eq!(b, a.scale_up(b));
    assert_eq!(c, a.scale_up(c));

    assert_eq!(c, c.scale_up(a));
    assert_eq!(b, c.scale_up(b));
}

#[test]
fn test_scale_down() {
    let a = Closed01::new(0.0);
    let b = Closed01::new(1.0);
    let c = Closed01::new(0.5);

    assert_eq!(a, c.scale_down(b));
    assert_eq!(b, b.scale_down(a));
    assert_eq!(c, b.scale_down(c));
}

#[test]
fn test_invert() {
    let a = Closed01::new(0.0);
    let b = Closed01::new(1.0);
    let c = Closed01::new(0.5);

    assert_eq!(a, a.inv().inv());
    assert_eq!(b, b.inv().inv());
    assert_eq!(c, c.inv().inv());

    assert_eq!(b, a.inv());
    assert_eq!(a, b.inv());
    assert_eq!(c, c.inv());
}

#[test]
fn test_round() {
    assert_eq!(Closed01::zero(), Closed01::new(0.0).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.1).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.2).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.3).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.4).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.49999).round());
    assert_eq!(Closed01::one(), Closed01::new(0.5).round());
    assert_eq!(Closed01::one(), Closed01::new(0.6).round());
    assert_eq!(Closed01::one(), Closed01::new(0.8).round());
    assert_eq!(Closed01::one(), Closed01::new(0.9).round());
    assert_eq!(Closed01::one(), Closed01::new(1.0).round());
}
<commit_msg>Rename middle -> center<commit_after>extern crate rand;

use rand::{Rand, Rng};
use rand::Closed01 as RandClosed01;

/// Encapsulates a floating point number in the range [0, 1] including both endpoints.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Closed01<F>(F);

impl Closed01<f32> {
    #[inline(always)]
    pub fn new(f: f32) -> Closed01<f32> {
        assert!(f >= 0.0 && f <= 1.0);
        Closed01(f)
    }

    #[inline(always)]
    pub fn zero() -> Closed01<f32> {
        Closed01(0.0)
    }

    #[inline(always)]
    pub fn center() -> Closed01<f32> {
        Closed01(0.5)
    }

    #[inline(always)]
    pub fn one() -> Closed01<f32> {
        Closed01(1.0)
    }

    #[inline(always)]
    /// Returns the smaller of the two.
    pub fn min(self, other: Closed01<f32>) -> Closed01<f32> {
        if self.0 <= other.0 {
            self
        } else {
            other
        }
    }

    #[inline(always)]
    /// Returns the greater of the two.
    pub fn max(self, other: Closed01<f32>) -> Closed01<f32> {
        if self.0 >= other.0 {
            self
        } else {
            other
        }
    }

    #[inline(always)]
    /// Returns the distance between the two numbers.
    pub fn distance(self, other: Closed01<f32>) -> Closed01<f32> {
        let d = (self.0 - other.0).abs();
        debug_assert!(d >= 0.0 && d <= 1.0);
        Closed01(d)
    }

    #[inline(always)]
    pub fn get(self) -> f32 {
        debug_assert!(self.0 >= 0.0 && self.0 <= 1.0);
        self.0
    }

    #[inline(always)]
    /// The average of two values.
    pub fn average(self: Closed01<f32>, other: Closed01<f32>) -> Closed01<f32> {
        let avg = (self.get() + other.get()) / 2.0;
        debug_assert!(avg >= 0.0 && avg <= 1.0);
        Closed01(avg)
    }

    #[inline(always)]
    /// Saturating add
    pub fn saturating_add(self, other: Closed01<f32>) -> Closed01<f32> {
        let mut sum = self.0 + other.0;
        if sum > 1.0 {
            sum = 1.0;
        }
        debug_assert!(sum >= 0.0 && sum <= 1.0);
        Closed01(sum)
    }

    #[inline(always)]
    /// Saturating sub
    pub fn saturating_sub(self, other: Closed01<f32>) -> Closed01<f32> {
        let mut sub = self.0 - other.0;
        if sub < 0.0 {
            sub = 0.0;
        }
        debug_assert!(sub >= 0.0 && sub <= 1.0);
        Closed01(sub)
    }

    #[inline(always)]
    /// Multiplies both numbers
    pub fn mul(self, scalar: Closed01<f32>) -> Closed01<f32> {
        let s = self.get() * scalar.get();
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }

    #[inline(always)]
    pub fn approx_eq(self, other: Closed01<f32>, eps: Closed01<f32>) -> bool {
        self.distance(other) < eps
    }

    #[inline(always)]
    /// This scales `self` towards 1.0
    pub fn scale_up(self, other: Closed01<f32>) -> Closed01<f32> {
        let s = self.0 + (1.0 - self.0) * other.0;
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }

    #[inline(always)]
    /// This scales `self` towards 0.0
    pub fn scale_down(self, other: Closed01<f32>) -> Closed01<f32> {
        let s = self.0 - self.0 * other.0;
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }

    #[inline(always)]
    /// Invert the number (Mirror at 0.5; 1.0 - number).
    pub fn inv(self) -> Closed01<f32> {
        let s = 1.0 - self.0;
        debug_assert!(s >= 0.0 && s <= 1.0);
        Closed01(s)
    }

    #[inline(always)]
    /// Round the number to 0.0 or 1.0
    pub fn round(self) -> Closed01<f32> {
        if self.0 < 0.5 {
            Closed01::zero()
        } else {
            Closed01::one()
        }
    }
}

impl Into<f32> for Closed01<f32> {
    fn into(self) -> f32 {
        self.get()
    }
}

impl Rand for Closed01<f32> {
    fn rand<R: Rng>(rng: &mut R) -> Closed01<f32> {
        Closed01::new(RandClosed01::<f32>::rand(rng).0)
    }
}

#[test]
fn test_into() {
    assert_eq!(0.5f32, Closed01::new(0.5).into());
}

#[test]
fn test_minmax() {
    let a = Closed01::new(0.4);
    let b = Closed01::new(0.5);
    assert_eq!(a, a.min(b));
    assert_eq!(a, b.min(a));
    assert_eq!(b, a.max(b));
    assert_eq!(b, b.max(a));
}

#[test]
fn test_saturation() {
    let a = Closed01::new(0.4);
    let b = Closed01::new(0.5);
    let c = Closed01::new(0.6);

    assert_eq!(0.9, a.saturating_add(b).get());
    assert_eq!(1.0, a.saturating_add(c).get());
    assert_eq!(1.0, b.saturating_add(c).get());

    assert_eq!(0.0, a.saturating_sub(b).get());
    assert_eq!(0.0, a.saturating_sub(c).get());
    assert_eq!(0.0, b.saturating_sub(c).get());

    let eps = Closed01::new(0.001);
    assert!(c.saturating_sub(b).approx_eq(Closed01::new(0.1), eps));
    assert!(c.saturating_sub(a).approx_eq(Closed01::new(0.2), eps));
}

#[test]
fn test_scale_up() {
    let a = Closed01::new(0.0);
    let b = Closed01::new(1.0);
    let c = Closed01::new(0.5);

    assert_eq!(b, a.scale_up(b));
    assert_eq!(c, a.scale_up(c));

    assert_eq!(c, c.scale_up(a));
    assert_eq!(b, c.scale_up(b));
}

#[test]
fn test_scale_down() {
    let a = Closed01::new(0.0);
    let b = Closed01::new(1.0);
    let c = Closed01::new(0.5);

    assert_eq!(a, c.scale_down(b));
    assert_eq!(b, b.scale_down(a));
    assert_eq!(c, b.scale_down(c));
}

#[test]
fn test_invert() {
    let a = Closed01::new(0.0);
    let b = Closed01::new(1.0);
    let c = Closed01::new(0.5);

    assert_eq!(a, a.inv().inv());
    assert_eq!(b, b.inv().inv());
    assert_eq!(c, c.inv().inv());

    assert_eq!(b, a.inv());
    assert_eq!(a, b.inv());
    assert_eq!(c, c.inv());
}

#[test]
fn test_round() {
    assert_eq!(Closed01::zero(), Closed01::new(0.0).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.1).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.2).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.3).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.4).round());
    assert_eq!(Closed01::zero(), Closed01::new(0.49999).round());
    assert_eq!(Closed01::one(), Closed01::new(0.5).round());
    assert_eq!(Closed01::one(), Closed01::new(0.6).round());
    assert_eq!(Closed01::one(), Closed01::new(0.8).round());
    assert_eq!(Closed01::one(), Closed01::new(0.9).round());
    assert_eq!(Closed01::one(), Closed01::new(1.0).round());
}
<|endoftext|>


<commit_before>use std::io::{BufReader, IoResult};

struct Triangle {
    normal: [f32; 3],
    v1: [f32; 3],
    v2: [f32; 3],
    v3: [f32; 3],
    attr_byte_count: u16
}

fn point_eq(lhs: [f32; 3], rhs: [f32; 3]) -> bool {
    lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2]
}

impl PartialEq for Triangle {
    fn eq(&self, rhs: &Triangle) -> bool {
        point_eq(self.normal, rhs.normal)
            && point_eq(self.v1, rhs.v1)
            && point_eq(self.v2, rhs.v2)
            && point_eq(self.v3, rhs.v3)
            && self.attr_byte_count == rhs.attr_byte_count
    }
}

impl Eq for Triangle {}

struct BinaryStlHeader {
    header: [u8; 80],
    num_triangles: u32
}

pub struct BinaryStlFile {
    header: BinaryStlHeader,
    triangles: Vec<Triangle>
}

fn read_point<T: Reader>(input: &mut T) -> IoResult<[f32; 3]> {
    let x1 = try!(input.read_le_f32());
    let x2 = try!(input.read_le_f32());
    let x3 = try!(input.read_le_f32());

    Ok([x1, x2, x3])
}

fn read_triangle<T: Reader>(input: &mut T) -> IoResult<Triangle> {
    let normal = try!(read_point(input));
    let v1 = try!(read_point(input));
    let v2 = try!(read_point(input));
    let v3 = try!(read_point(input));
    let attr_count = try!(input.read_le_u16());

    Ok(Triangle { normal: normal,
                  v1: v1, v2: v2, v3: v3,
                  attr_byte_count: attr_count })
}

pub fn read_stl<T: Reader>(input: &mut T) -> IoResult<BinaryStlFile> {
    let mut header = BinaryStlHeader { header: [0u8; 80],
                                       num_triangles: 0 };

    // read the header
    try!(input.read_at_least(header.header.len(), &mut header.header));

    // TODO: check the header to make sure whether this is a binary
    // STL file.

    header.num_triangles = try!(input.read_le_u32());

    let mut triangles = Vec::new();
    for _ in 0 .. header.num_triangles {
        triangles.push(try!(read_triangle(input)));
    }

    Ok(BinaryStlFile {
        header: header,
        triangles: triangles
    })
}

fn write_point<T: Writer>(out: &mut T, p: [f32; 3]) -> IoResult<()> {
    for x in p.iter() {
        try!(out.write_le_f32(*x));
    }
    Ok(())
}

pub fn write_stl<T: Writer>(out: &mut T, stl: &BinaryStlFile) -> IoResult<()> {
    assert!(stl.header.num_triangles as usize == stl.triangles.len());

    //write the header.
    try!(out.write(&stl.header.header));
    try!(out.write_le_u32(stl.header.num_triangles));

    // write all the triangles
    for t in stl.triangles.iter() {
        try!(write_point(out, t.normal));
        try!(write_point(out, t.v1));
        try!(write_point(out, t.v2));
        try!(write_point(out, t.v3));
        try!(out.write_le_u16(t.attr_byte_count));
    }

    Ok(())
}

#[test]
fn write_read() {
    // Make sure we can write and read a simple file.
    let file = BinaryStlFile {
        header: BinaryStlHeader { header: [0u8; 80],
                                  num_triangles: 1 },
        triangles: vec![Triangle { normal: [0f32, 1f32, 0f32],
                                   v1: [0f32, 0f32, 0f32],
                                   v2: [0f32, 0f32, 1f32],
                                   v3: [1f32, 0f32, 1f32],
                                   attr_byte_count: 0 }]
    };

    let mut buffer = Vec::new();

    match write_stl(&mut buffer, &file) {
        Ok(_) => (),
        Err(_) => panic!()
    }

    match read_stl(&mut BufReader::new(&buffer[])) {
        Ok(stl) => {
            assert!(stl.header.num_triangles == file.header.num_triangles);
            assert!(stl.triangles.len() == 1);
            assert!(stl.triangles[0] == file.triangles[0])
        },
        Err(_) => panic!()
    }
}
<commit_msg>Merging<commit_after>#![feature(io)]
#![feature(core)]

use std::old_io::IoResult;

struct Triangle {
    normal: [f32; 3],
    v1: [f32; 3],
    v2: [f32; 3],
    v3: [f32; 3],
    attr_byte_count: u16
}

fn point_eq(lhs: [f32; 3], rhs: [f32; 3]) -> bool {
    lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2]
}

impl PartialEq for Triangle {
    fn eq(&self, rhs: &Triangle) -> bool {
        point_eq(self.normal, rhs.normal)
            && point_eq(self.v1, rhs.v1)
            && point_eq(self.v2, rhs.v2)
            && point_eq(self.v3, rhs.v3)
            && self.attr_byte_count == rhs.attr_byte_count
    }
}

impl Eq for Triangle {}

struct BinaryStlHeader {
    header: [u8; 80],
    num_triangles: u32
}

pub struct BinaryStlFile {
    header: BinaryStlHeader,
    triangles: Vec<Triangle>
}

fn read_point<T: Reader>(input: &mut T) -> IoResult<[f32; 3]> {
    let x1 = try!(input.read_le_f32());
    let x2 = try!(input.read_le_f32());
    let x3 = try!(input.read_le_f32());

    Ok([x1, x2, x3])
}

fn read_triangle<T: Reader>(input: &mut T) -> IoResult<Triangle> {
    let normal = try!(read_point(input));
    let v1 = try!(read_point(input));
    let v2 = try!(read_point(input));
    let v3 = try!(read_point(input));
    let attr_count = try!(input.read_le_u16());

    Ok(Triangle { normal: normal,
                  v1: v1, v2: v2, v3: v3,
                  attr_byte_count: attr_count })
}

pub fn read_stl<T: Reader>(input: &mut T) -> IoResult<BinaryStlFile> {
    let mut header = BinaryStlHeader { header: [0u8; 80],
                                       num_triangles: 0 };

    // read the header
    try!(input.read_at_least(header.header.len(), &mut header.header));

    // TODO: check the header to make sure whether this is a binary
    // STL file.

    header.num_triangles = try!(input.read_le_u32());

    let mut triangles = Vec::new();
    for _ in 0 .. header.num_triangles {
        triangles.push(try!(read_triangle(input)));
    }

    Ok(BinaryStlFile {
        header: header,
        triangles: triangles
    })
}

fn write_point<T: Writer>(out: &mut T, p: [f32; 3]) -> IoResult<()> {
    for x in p.iter() {
        try!(out.write_le_f32(*x));
    }
    Ok(())
}

pub fn write_stl<T: Writer>(out: &mut T, stl: &BinaryStlFile) -> IoResult<()> {
    assert!(stl.header.num_triangles as usize == stl.triangles.len());

    //write the header.
    try!(out.write_all(&stl.header.header));
    try!(out.write_le_u32(stl.header.num_triangles));

    // write all the triangles
    for t in stl.triangles.iter() {
        try!(write_point(out, t.normal));
        try!(write_point(out, t.v1));
        try!(write_point(out, t.v2));
        try!(write_point(out, t.v3));
        try!(out.write_le_u16(t.attr_byte_count));
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use std::old_io::BufReader;
    use super::{BinaryStlFile, BinaryStlHeader, write_stl, read_stl, Triangle};
    #[test]
    fn write_read() {
        // Make sure we can write and read a simple file.
        let file = BinaryStlFile {
            header: BinaryStlHeader { header: [0u8; 80],
                                      num_triangles: 1 },
            triangles: vec![Triangle { normal: [0f32, 1f32, 0f32],
                                       v1: [0f32, 0f32, 0f32],
                                       v2: [0f32, 0f32, 1f32],
                                       v3: [1f32, 0f32, 1f32],
                                       attr_byte_count: 0 }]
        };

        let mut buffer = Vec::new();

        match write_stl(&mut buffer, &file) {
            Ok(_) => (),
            Err(_) => panic!()
        }

        match read_stl(&mut BufReader::new(buffer.as_slice())) {
            Ok(stl) => {
                assert!(stl.header.num_triangles == file.header.num_triangles);
                assert!(stl.triangles.len() == 1);
                assert!(stl.triangles[0] == file.triangles[0])
            },
            Err(_) => panic!()
        }
    }
}
<|endoftext|>


<commit_before>extern crate walkdir;
extern crate git2;
extern crate regex;
extern crate url;

use std::process::Command;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

#[derive(Debug)]
struct Repository {
  root: String,
  path: String,
}

pub fn command_get(projects: Vec<String>, skip_pull: bool, shallow: bool) -> i32 {
  for project in projects {
    let (protocol, base_url, user, repo);
    if url::Url::parse(&project).is_ok() {
      let re = regex::Regex::new(r"([a-z]+)://([\w-\.]+)/([\w-.]+)/([\w-.]+)\.git").unwrap();
      let caps = re.captures(&project).unwrap();
      protocol = caps.at(1).unwrap().to_owned();
      base_url = caps.at(2).unwrap().to_owned();
      user = caps.at(3).unwrap().to_owned();
      repo = caps.at(4).unwrap().to_owned();
    } else {
      protocol = "https".to_owned();
      base_url = "github.com".to_owned();
      let re = regex::Regex::new(r"([\w-.]+)/([\w-.]+)").unwrap();
      if let Some(caps) = re.captures(&project) {
        user = caps.at(1).unwrap().to_owned();
        repo = caps.at(2).unwrap().to_owned();
      } else {
        user = project.clone();
        repo = project.clone();
      }
    }
    let url = url::Url::parse(&format!("{}://{}/{}/{}.git", protocol, base_url, user, repo))
      .unwrap();

    let mut dest = PathBuf::from(&get_local_repos_roots()[0]);
    dest.push(base_url);
    dest.push(user);
    dest.push(repo);

    git_clone_or_pull(url, dest.as_path(), skip_pull, shallow);
  }
  0
}

pub fn command_list(exact: bool, fullpath: bool, unique: bool, query: Option<String>) -> i32 {
  let filter: Box<Fn(&str) -> bool> = {
    if let Some(query) = query {
      if exact {
        Box::new(move |s: &str| s == query)
      } else {
        Box::new(move |s: &str| s.contains(&query))
      }
    } else {
      Box::new(|_| true)
    }
  };

  for repo in get_local_repositories(filter) {
    if fullpath {
      let mut repo_path = PathBuf::from(repo.root);
      repo_path.push(repo.path);
      println!("{}", repo_path.display());
    } else if unique {
      let repo_name = Path::new(&repo.path)
        .file_name()
        .unwrap()
        .to_str()
        .unwrap();
      println!("{}", repo_name);
    } else {
      println!("{}", repo.path);
    }
  }

  0
}

pub fn command_root(all: bool) -> i32 {
  let roots = get_local_repos_roots();
  if all {
    for root in roots {
      println!("{}", root);
    }
  } else {
    println!("{}", roots[0]);
  }
  0
}

fn git_clone_or_pull(url: url::Url, dest: &Path, skip_pull: bool, shallow: bool) {
  if dest.exists() {
    if !skip_pull {
      git_pull(url, dest);
    }
  } else {
    git_clone(url, dest, shallow);
  }
}

#[allow(unreachable_code)]
fn git_clone(url: url::Url, dest: &Path, shallow: bool) {
  println!("clone: {:?} -> {:?} ({})",
           url,
           dest,
           if shallow { "Shallow" } else { "" });
  return;

  let mut args = vec!["clone", url.as_str(), dest.to_str().unwrap()];
  if shallow {
    args.extend(&["--depth", "1"]);
  }

  let output = Command::new("git")
    .args(&args[..])
    .output()
    .expect("failed to clone repository");
  if !output.status.success() {
    panic!("git clone failed");
  }
}

#[allow(unreachable_code)]
fn git_pull(url: url::Url, dest: &Path) {
  println!("pull: {:?} -> {:?}", url, dest);
  return;

  let output = Command::new("git")
    .args(&["clone", url.as_str(), dest.to_str().unwrap()])
    .output()
    .expect("failed to clone repository");
  if !output.status.success() {
    panic!("git clone failed");
  }
}

fn git_config(key: &str) -> String {
  let output = Command::new("git")
    .args(&["config", "--path", "--null", "--get-all", key])
    .output()
    .expect("failed to execute git");
  let len = output.stdout.len();
  String::from_utf8(Vec::from(&output.stdout[0..len - 1])).unwrap()
}

fn get_local_repositories(filter: Box<Fn(&str) -> bool>) -> Vec<Repository> {
  let mut dst = Vec::new();

  let roots = get_local_repos_roots();
  for root in roots {
    for entry in WalkDir::new(&root).follow_links(true).into_iter().filter_map(|e| e.ok()) {
      let path = format!("{}", entry.path().display()).replace(&format!("{}/", root), "");
      if entry.depth() == 3 {

        let entry = vec![".git", ".svn", ".hg", "_darcs"].into_iter().find(|&e| {
          let mut buf = PathBuf::from(format!("{}", entry.path().display()));
          if !filter(buf.file_name().unwrap().to_str().unwrap()) {
            return false;
          }
          buf.push(e);
          buf.exists()
        });

        if entry.is_some() {
          dst.push(Repository {
            root: root.clone(),
            path: path,
          });
        }
      }
    }
  }

  dst
}

fn get_local_repos_roots() -> Vec<String> {
  let mut local_repo_roots;

  let env_root: String = std::env::var("GHQ_ROOT").unwrap_or("".to_owned());
  if env_root == "" {
    local_repo_roots = vec![git_config("ghq.root")];
  } else {
    local_repo_roots = env_root.split(":").map(|s| s.to_owned()).collect();
  }

  if local_repo_roots.len() == 0 {
    let mut ghq_path = std::env::home_dir().unwrap();
    ghq_path.push(".ghq");
    local_repo_roots.push(format!("{}", ghq_path.display()));
  }

  assert!(local_repo_roots.len() >= 1);

  local_repo_roots
}
<commit_msg>revise 'git_pull'<commit_after>extern crate walkdir;
extern crate git2;
extern crate regex;
extern crate url;

use std::process::Command;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

#[derive(Debug)]
struct Repository {
  root: String,
  path: String,
}

pub fn command_get(projects: Vec<String>, skip_pull: bool, shallow: bool) -> i32 {
  for project in projects {
    let (protocol, base_url, user, repo);
    if url::Url::parse(&project).is_ok() {
      let re = regex::Regex::new(r"([a-z]+)://([\w-\.]+)/([\w-.]+)/([\w-.]+)\.git").unwrap();
      let caps = re.captures(&project).unwrap();
      protocol = caps.at(1).unwrap().to_owned();
      base_url = caps.at(2).unwrap().to_owned();
      user = caps.at(3).unwrap().to_owned();
      repo = caps.at(4).unwrap().to_owned();
    } else {
      protocol = "https".to_owned();
      base_url = "github.com".to_owned();
      let re = regex::Regex::new(r"([\w-.]+)/([\w-.]+)").unwrap();
      if let Some(caps) = re.captures(&project) {
        user = caps.at(1).unwrap().to_owned();
        repo = caps.at(2).unwrap().to_owned();
      } else {
        user = project.clone();
        repo = project.clone();
      }
    }
    let url = url::Url::parse(&format!("{}://{}/{}/{}.git", protocol, base_url, user, repo))
      .unwrap();

    let mut dest = PathBuf::from(&get_local_repos_roots()[0]);
    dest.push(base_url);
    dest.push(user);
    dest.push(repo);

    git_clone_or_pull(url, dest.as_path(), skip_pull, shallow);
  }
  0
}

pub fn command_list(exact: bool, fullpath: bool, unique: bool, query: Option<String>) -> i32 {
  let filter: Box<Fn(&str) -> bool> = {
    if let Some(query) = query {
      if exact {
        Box::new(move |s: &str| s == query)
      } else {
        Box::new(move |s: &str| s.contains(&query))
      }
    } else {
      Box::new(|_| true)
    }
  };

  for repo in get_local_repositories(filter) {
    if fullpath {
      let mut repo_path = PathBuf::from(repo.root);
      repo_path.push(repo.path);
      println!("{}", repo_path.display());
    } else if unique {
      let repo_name = Path::new(&repo.path)
        .file_name()
        .unwrap()
        .to_str()
        .unwrap();
      println!("{}", repo_name);
    } else {
      println!("{}", repo.path);
    }
  }

  0
}

pub fn command_root(all: bool) -> i32 {
  let roots = get_local_repos_roots();
  if all {
    for root in roots {
      println!("{}", root);
    }
  } else {
    println!("{}", roots[0]);
  }
  0
}

fn git_clone_or_pull(url: url::Url, dest: &Path, skip_pull: bool, shallow: bool) {
  if dest.exists() {
    if !skip_pull {
      git_pull(dest);
    }
  } else {
    git_clone(url, dest, shallow);
  }
}

#[allow(unreachable_code)]
fn git_clone(url: url::Url, dest: &Path, shallow: bool) {
  println!("clone: {:?} -> {:?} ({})",
           url,
           dest,
           if shallow { "Shallow" } else { "" });
  return;

  let mut args = vec!["clone", url.as_str(), dest.to_str().unwrap()];
  if shallow {
    args.extend(&["--depth", "1"]);
  }

  let output = Command::new("git")
    .args(&args[..])
    .output()
    .expect("failed to clone repository");
  if !output.status.success() {
    panic!("git clone failed");
  }
}

struct ScopeExit<F: FnMut()> {
  caller: F,
}

impl<F: FnMut()> ScopeExit<F> {
  fn new(c: F) -> ScopeExit<F> {
    ScopeExit { caller: c }
  }
}

impl<F: FnMut()> Drop for ScopeExit<F> {
  fn drop(&mut self) {
    (self.caller)();
  }
}

#[allow(unreachable_code)]
fn git_pull(dest: &Path) {
  println!("pull: {:?}", dest);
  return;

  let curr_dir = std::env::current_dir().unwrap().to_str().unwrap().to_owned();
  std::env::set_current_dir(dest).unwrap();
  ScopeExit::new(|| {
    std::env::set_current_dir(curr_dir.clone()).unwrap();
  });

  let output = Command::new("git")
    .args(&["pull"])
    .output()
    .expect("failed to clone repository");
  if !output.status.success() {
    panic!("git pull failed");
  }
}

fn git_config(key: &str) -> String {
  let output = Command::new("git")
    .args(&["config", "--path", "--null", "--get-all", key])
    .output()
    .expect("failed to execute git");
  let len = output.stdout.len();
  String::from_utf8(Vec::from(&output.stdout[0..len - 1])).unwrap()
}

fn get_local_repositories(filter: Box<Fn(&str) -> bool>) -> Vec<Repository> {
  let mut dst = Vec::new();

  let roots = get_local_repos_roots();
  for root in roots {
    for entry in WalkDir::new(&root).follow_links(true).into_iter().filter_map(|e| e.ok()) {
      let path = format!("{}", entry.path().display()).replace(&format!("{}/", root), "");
      if entry.depth() == 3 {

        let entry = vec![".git", ".svn", ".hg", "_darcs"].into_iter().find(|&e| {
          let mut buf = PathBuf::from(format!("{}", entry.path().display()));
          if !filter(buf.file_name().unwrap().to_str().unwrap()) {
            return false;
          }
          buf.push(e);
          buf.exists()
        });

        if entry.is_some() {
          dst.push(Repository {
            root: root.clone(),
            path: path,
          });
        }
      }
    }
  }

  dst
}

fn get_local_repos_roots() -> Vec<String> {
  let mut local_repo_roots;

  let env_root: String = std::env::var("GHQ_ROOT").unwrap_or("".to_owned());
  if env_root == "" {
    local_repo_roots = vec![git_config("ghq.root")];
  } else {
    local_repo_roots = env_root.split(":").map(|s| s.to_owned()).collect();
  }

  if local_repo_roots.len() == 0 {
    let mut ghq_path = std::env::home_dir().unwrap();
    ghq_path.push(".ghq");
    local_repo_roots.push(format!("{}", ghq_path.display()));
  }

  assert!(local_repo_roots.len() >= 1);

  local_repo_roots
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! The official Piston window back-end for the Piston game engine

extern crate glutin_window;
extern crate piston;

use std::cell::RefCell;
use std::rc::Rc;
use std::any::Any;

use glutin_window::GlutinWindow;
use piston::{ event, window };

/// The type of event emitted from event loop.
pub type PistonEvent = event::Event<<GlutinWindow as window::Window>::Event>;

/// Contains everything required for controlling window, graphics, event loop.
#[derive(Clone)]
pub struct PistonWindow<T = ()> {
    /// The window.
    pub window: Rc<RefCell<GlutinWindow>>,
    /// The event loop.
    pub events: Rc<RefCell<event::events::Events<GlutinWindow, PistonEvent>>>,
    /// The event.
    pub event: Option<PistonEvent>,
    /// Application structure.
    pub app: Rc<RefCell<T>>,
}

impl<T> PistonWindow<T> {
    /// Creates a new piston object.
    pub fn new(window: Rc<RefCell<GlutinWindow>>, app: Rc<RefCell<T>>) -> Self {
        use piston::event::Events;

        PistonWindow {
            window: window.clone(),
            events: Rc::new(RefCell::new(window.events())),
            event: None,
            app: app,
        }
    }

    /// Changes application structure.
    pub fn app<U>(self, app: Rc<RefCell<U>>) -> PistonWindow<U> {
        PistonWindow {
            window: self.window.clone(),
            events: self.events.clone(),
            event: self.event,
            app: app,
        }
    }
}

impl Iterator for PistonWindow {
    type Item = PistonWindow;

    fn next(&mut self) -> Option<PistonWindow> {
        if let Some(e) = self.events.borrow_mut().next() {
            Some(PistonWindow {
                window: self.window.clone(),
                events: self.events.clone(),
                event: Some(e),
                app: self.app.clone(),
            })
        } else { None }
    }
}

impl event::GenericEvent for PistonWindow {
    fn event_id(&self) -> event::EventId {
        match self.event {
            Some(ref e) => e.event_id(),
            None => event::EventId("")
        }
    }

    fn with_args<'a, F, U>(&'a self, f: F) -> U
       where F: FnMut(&Any) -> U
    {
        self.event.as_ref().unwrap().with_args(f)
    }

    fn from_args(event_id: event::EventId, any: &Any, old_event: &Self) -> Option<Self> {
        if let Some(ref e) = old_event.event {
            match event::GenericEvent::from_args(event_id, any, e) {
                Some(e) => {
                    Some(PistonWindow {
                        window: old_event.window.clone(),
                        events: old_event.events.clone(),
                        event: Some(e),
                        app: old_event.app.clone(),
                    })
                }
                None => None
            }
        } else { None }
    }
}

impl window::Window for PistonWindow {
    type Event = <GlutinWindow as window::Window>::Event;

    fn should_close(&self) -> bool { self.window.borrow().should_close() }
    fn size(&self) -> window::Size { self.window.borrow().size() }
    fn draw_size(&self) -> window::Size { self.window.borrow().draw_size() }
    fn swap_buffers(&mut self) { self.window.borrow_mut().swap_buffers() }
    fn poll_event(&mut self) -> Option<Self::Event> {
        window::Window::poll_event(&mut *self.window.borrow_mut())
    }
}

impl window::AdvancedWindow for PistonWindow {
    fn get_title(&self) -> String { self.window.borrow().get_title() }
    fn set_title(&mut self, title: String) {
        self.window.borrow_mut().set_title(title)
    }
    fn get_exit_on_esc(&self) -> bool { self.window.borrow().get_exit_on_esc() }
    fn set_exit_on_esc(&mut self, value: bool) {
        self.window.borrow_mut().set_exit_on_esc(value)
    }
    fn set_capture_cursor(&mut self, value: bool) {
        self.window.borrow_mut().set_capture_cursor(value)
    }
}

/// Creates a new empty application.
pub fn empty_app() -> Rc<RefCell<()>> { Rc::new(RefCell::new(())) }
<commit_msg>Removed unneccesary clones<commit_after>#![deny(missing_docs)]

//! The official Piston window back-end for the Piston game engine

extern crate glutin_window;
extern crate piston;

use std::cell::RefCell;
use std::rc::Rc;
use std::any::Any;

use glutin_window::GlutinWindow;
use piston::{ event, window };

/// The type of event emitted from event loop.
pub type PistonEvent = event::Event<<GlutinWindow as window::Window>::Event>;

/// Contains everything required for controlling window, graphics, event loop.
#[derive(Clone)]
pub struct PistonWindow<T = ()> {
    /// The window.
    pub window: Rc<RefCell<GlutinWindow>>,
    /// The event loop.
    pub events: Rc<RefCell<event::events::Events<GlutinWindow, PistonEvent>>>,
    /// The event.
    pub event: Option<PistonEvent>,
    /// Application structure.
    pub app: Rc<RefCell<T>>,
}

impl<T> PistonWindow<T> {
    /// Creates a new piston object.
    pub fn new(window: Rc<RefCell<GlutinWindow>>, app: Rc<RefCell<T>>) -> Self {
        use piston::event::Events;

        PistonWindow {
            window: window.clone(),
            events: Rc::new(RefCell::new(window.events())),
            event: None,
            app: app,
        }
    }

    /// Changes application structure.
    pub fn app<U>(self, app: Rc<RefCell<U>>) -> PistonWindow<U> {
        PistonWindow {
            window: self.window,
            events: self.events,
            event: self.event,
            app: app,
        }
    }
}

impl Iterator for PistonWindow {
    type Item = PistonWindow;

    fn next(&mut self) -> Option<PistonWindow> {
        if let Some(e) = self.events.borrow_mut().next() {
            Some(PistonWindow {
                window: self.window.clone(),
                events: self.events.clone(),
                event: Some(e),
                app: self.app.clone(),
            })
        } else { None }
    }
}

impl event::GenericEvent for PistonWindow {
    fn event_id(&self) -> event::EventId {
        match self.event {
            Some(ref e) => e.event_id(),
            None => event::EventId("")
        }
    }

    fn with_args<'a, F, U>(&'a self, f: F) -> U
       where F: FnMut(&Any) -> U
    {
        self.event.as_ref().unwrap().with_args(f)
    }

    fn from_args(event_id: event::EventId, any: &Any, old_event: &Self) -> Option<Self> {
        if let Some(ref e) = old_event.event {
            match event::GenericEvent::from_args(event_id, any, e) {
                Some(e) => {
                    Some(PistonWindow {
                        window: old_event.window.clone(),
                        events: old_event.events.clone(),
                        event: Some(e),
                        app: old_event.app.clone(),
                    })
                }
                None => None
            }
        } else { None }
    }
}

impl window::Window for PistonWindow {
    type Event = <GlutinWindow as window::Window>::Event;

    fn should_close(&self) -> bool { self.window.borrow().should_close() }
    fn size(&self) -> window::Size { self.window.borrow().size() }
    fn draw_size(&self) -> window::Size { self.window.borrow().draw_size() }
    fn swap_buffers(&mut self) { self.window.borrow_mut().swap_buffers() }
    fn poll_event(&mut self) -> Option<Self::Event> {
        window::Window::poll_event(&mut *self.window.borrow_mut())
    }
}

impl window::AdvancedWindow for PistonWindow {
    fn get_title(&self) -> String { self.window.borrow().get_title() }
    fn set_title(&mut self, title: String) {
        self.window.borrow_mut().set_title(title)
    }
    fn get_exit_on_esc(&self) -> bool { self.window.borrow().get_exit_on_esc() }
    fn set_exit_on_esc(&mut self, value: bool) {
        self.window.borrow_mut().set_exit_on_esc(value)
    }
    fn set_capture_cursor(&mut self, value: bool) {
        self.window.borrow_mut().set_capture_cursor(value)
    }
}

/// Creates a new empty application.
pub fn empty_app() -> Rc<RefCell<()>> { Rc::new(RefCell::new(())) }
<|endoftext|>