<commit_before>use std::string::ToString;
use std::collections::BTreeMap;
use std::error::Error;
use std::fmt;
use std::{i32,usize};
use rustc_serialize::json::{Json,ToJson};

use parse::Presence::*;

#[derive(Clone, PartialEq, Debug)]
pub enum ParseError {
    InvalidJsonType(String),
    InvalidStructure(String),
    MissingField(String),
    UnknownMethod(String),
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::InvalidJsonType(_)  => "invalid JSON type for conversion",
            ParseError::InvalidStructure(_) => "invalid value structure for conversion",
            ParseError::MissingField(_)     => "missing field",
            ParseError::UnknownMethod(_)    => "unknown method",
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            ParseError::InvalidJsonType(ref e)  => format!("invalid JSON type for conversion to {}", e),
            ParseError::InvalidStructure(ref e) => format!("invalid value structure for conversion to {}", e),
            ParseError::MissingField(ref e)     => format!("missing field \"{}\"", e),
            ParseError::UnknownMethod(ref e)    => format!("unknown method \"{}\"", e),
        }.to_string())
    }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Presence<T> {
    Present(T),
    Absent,
}
impl<T> Presence<T> {
    pub fn as_option<'a>(&'a self) -> Option<&'a T> {
        match *self {
            Present(ref tt) => Some(&tt),
            Absent          => None,
        }
    }
}
impl<T> Default for Presence<T> {
    fn default() -> Presence<T> {
        Absent
    }
}

// trait for things that can be created from a JSON fragment
pub trait FromJson {
    fn from_json(json: &Json) -> Result<Self,ParseError>;
}

// conversions for system types
impl FromJson for String {
    fn from_json(json: &Json) -> Result<String,ParseError> {
        match *json {
            Json::String(ref s) => Ok(s.to_string()),
            _                   => Err(ParseError::InvalidJsonType("String".to_string())),
        }
    }
}
impl FromJson for u64 {
    fn from_json(json: &Json) -> Result<u64,ParseError> {
        match *json {
            Json::U64(n) => Ok(n),
            Json::I64(n) => Ok(n as u64),
            _            => Err(ParseError::InvalidJsonType("u64".to_string())),
        }
    }
}
impl FromJson for bool {
    fn from_json(json: &Json) -> Result<bool,ParseError> {
        match *json {
            Json::Boolean(b) => Ok(b),
            _                => Err(ParseError::InvalidJsonType("bool".to_string())),
        }
    }
}
impl FromJson for i32 {
    fn from_json(json: &Json) -> Result<i32,ParseError> {
        match *json {
            Json::U64(n) if n <= (i32::MAX as u64)
                => Ok(n as i32),
            Json::I64(n) if n >= (i32::MIN as i64) && n <= (i32::MAX as i64)
                => Ok(n as i32),
            _ => Err(ParseError::InvalidJsonType("i32".to_string())),
        }
    }
}
impl FromJson for usize {
    fn from_json(json: &Json) -> Result<usize,ParseError> {
        match *json {
            Json::U64(n) if n <= (usize::MAX as u64)
                => Ok(n as usize),
            Json::I64(n) if n >= (usize::MIN as i64) && n <= (usize::MAX as i64)
                => Ok(n as usize),
            _ => Err(ParseError::InvalidJsonType("usize".to_string())),
        }
    }
}

impl<T> FromJson for Vec<T> where T: FromJson {
    fn from_json(json: &Json) -> Result<Vec<T>,ParseError> {
        match *json {
            Json::Array(ref a) => {
                let (ok, mut err): (Vec<_>,Vec<_>)  = a.iter().map(|ref j| T::from_json(j)).partition(|ref r| match **r { Ok(_) => true, Err(_) => false });
                match err.len() {
                    0 => Ok(ok.into_iter().map(|r| r.ok().unwrap()).collect()),
                    _ => Err(err.remove(0).err().unwrap()),
                }
            }
            _ => Err(ParseError::InvalidJsonType("Vec".to_string())),
        }
    }
}

impl<T> FromJson for BTreeMap<String,T> where T: FromJson {
    fn from_json(json: &Json) -> Result<Self,ParseError> {
        match *json {
            Json::Object(ref o) => {
                let mut m = BTreeMap::<String,T>::new();
                for (k, v) in o.iter() {
                    let vv = try!(T::from_json(v));
                    m.insert(k.clone(), vv);
                }
                Ok(m)
            },
            _ => Err(ParseError::InvalidJsonType("BTreeMap".to_string()))
        }
    }
}

pub trait FromJsonField {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError>;
}

impl<T> FromJsonField for T where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(ref v) => T::from_json(&v),
            None        => Err(ParseError::MissingField(field.to_string())),
        }
    }
}
impl<T> FromJsonField for Option<T> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(v) => {
                match *v {
                    Json::Null => Ok(None),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Some(j)),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(None),
        }
    }
}
impl<T> FromJsonField for Presence<T> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(ref v) => {
                match *v {
                    &Json::Null => Ok(Absent),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Present(j)),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(Absent),
        }
    }
}
impl<T> FromJsonField for Presence<Option<T>> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(v) => {
                match *v {
                    Json::Null => Ok(Present(None)),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Present(Some(j))),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(Absent),
        }
    }
}

pub trait ToJsonField {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str);
}

impl<T> ToJsonField for T where T: ToJson {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str) {
        json.insert(field.to_string(), self.to_json());
    }
}

impl<T> ToJsonField for Presence<T> where T: ToJson {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str) {
        if let Present(ref v) = *self {
            json.insert(field.to_string(), v.to_json());
        }
    }
}
<commit_msg>Have traits inherit from Sized for inclusion in Result<commit_after>use std::string::ToString;
use std::collections::BTreeMap;
use std::error::Error;
use std::fmt;
use std::{i32,usize};
use rustc_serialize::json::{Json,ToJson};

use parse::Presence::*;

#[derive(Clone, PartialEq, Debug)]
pub enum ParseError {
    InvalidJsonType(String),
    InvalidStructure(String),
    MissingField(String),
    UnknownMethod(String),
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::InvalidJsonType(_)  => "invalid JSON type for conversion",
            ParseError::InvalidStructure(_) => "invalid value structure for conversion",
            ParseError::MissingField(_)     => "missing field",
            ParseError::UnknownMethod(_)    => "unknown method",
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            ParseError::InvalidJsonType(ref e)  => format!("invalid JSON type for conversion to {}", e),
            ParseError::InvalidStructure(ref e) => format!("invalid value structure for conversion to {}", e),
            ParseError::MissingField(ref e)     => format!("missing field \"{}\"", e),
            ParseError::UnknownMethod(ref e)    => format!("unknown method \"{}\"", e),
        }.to_string())
    }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Presence<T> {
    Present(T),
    Absent,
}
impl<T> Presence<T> {
    pub fn as_option<'a>(&'a self) -> Option<&'a T> {
        match *self {
            Present(ref tt) => Some(&tt),
            Absent          => None,
        }
    }
}
impl<T> Default for Presence<T> {
    fn default() -> Presence<T> {
        Absent
    }
}

// trait for things that can be created from a JSON fragment
pub trait FromJson: Sized {
    fn from_json(json: &Json) -> Result<Self,ParseError>;
}

// conversions for system types
impl FromJson for String {
    fn from_json(json: &Json) -> Result<String,ParseError> {
        match *json {
            Json::String(ref s) => Ok(s.to_string()),
            _                   => Err(ParseError::InvalidJsonType("String".to_string())),
        }
    }
}
impl FromJson for u64 {
    fn from_json(json: &Json) -> Result<u64,ParseError> {
        match *json {
            Json::U64(n) => Ok(n),
            Json::I64(n) => Ok(n as u64),
            _            => Err(ParseError::InvalidJsonType("u64".to_string())),
        }
    }
}
impl FromJson for bool {
    fn from_json(json: &Json) -> Result<bool,ParseError> {
        match *json {
            Json::Boolean(b) => Ok(b),
            _                => Err(ParseError::InvalidJsonType("bool".to_string())),
        }
    }
}
impl FromJson for i32 {
    fn from_json(json: &Json) -> Result<i32,ParseError> {
        match *json {
            Json::U64(n) if n <= (i32::MAX as u64)
                => Ok(n as i32),
            Json::I64(n) if n >= (i32::MIN as i64) && n <= (i32::MAX as i64)
                => Ok(n as i32),
            _ => Err(ParseError::InvalidJsonType("i32".to_string())),
        }
    }
}
impl FromJson for usize {
    fn from_json(json: &Json) -> Result<usize,ParseError> {
        match *json {
            Json::U64(n) if n <= (usize::MAX as u64)
                => Ok(n as usize),
            Json::I64(n) if n >= (usize::MIN as i64) && n <= (usize::MAX as i64)
                => Ok(n as usize),
            _ => Err(ParseError::InvalidJsonType("usize".to_string())),
        }
    }
}

impl<T> FromJson for Vec<T> where T: FromJson {
    fn from_json(json: &Json) -> Result<Vec<T>,ParseError> {
        match *json {
            Json::Array(ref a) => {
                let (ok, mut err): (Vec<_>,Vec<_>)  = a.iter().map(|ref j| T::from_json(j)).partition(|ref r| match **r { Ok(_) => true, Err(_) => false });
                match err.len() {
                    0 => Ok(ok.into_iter().map(|r| r.ok().unwrap()).collect()),
                    _ => Err(err.remove(0).err().unwrap()),
                }
            }
            _ => Err(ParseError::InvalidJsonType("Vec".to_string())),
        }
    }
}

impl<T> FromJson for BTreeMap<String,T> where T: FromJson {
    fn from_json(json: &Json) -> Result<Self,ParseError> {
        match *json {
            Json::Object(ref o) => {
                let mut m = BTreeMap::<String,T>::new();
                for (k, v) in o.iter() {
                    let vv = try!(T::from_json(v));
                    m.insert(k.clone(), vv);
                }
                Ok(m)
            },
            _ => Err(ParseError::InvalidJsonType("BTreeMap".to_string()))
        }
    }
}

pub trait FromJsonField: Sized {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError>;
}

impl<T> FromJsonField for T where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(ref v) => T::from_json(&v),
            None        => Err(ParseError::MissingField(field.to_string())),
        }
    }
}
impl<T> FromJsonField for Option<T> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(v) => {
                match *v {
                    Json::Null => Ok(None),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Some(j)),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(None),
        }
    }
}
impl<T> FromJsonField for Presence<T> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(ref v) => {
                match *v {
                    &Json::Null => Ok(Absent),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Present(j)),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(Absent),
        }
    }
}
impl<T> FromJsonField for Presence<Option<T>> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(v) => {
                match *v {
                    Json::Null => Ok(Present(None)),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Present(Some(j))),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(Absent),
        }
    }
}

pub trait ToJsonField {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str);
}

impl<T> ToJsonField for T where T: ToJson {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str) {
        json.insert(field.to_string(), self.to_json());
    }
}

impl<T> ToJsonField for Presence<T> where T: ToJson {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str) {
        if let Present(ref v) = *self {
            json.insert(field.to_string(), v.to_json());
        }
    }
}
<|endoftext|>


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

use model::Model;
use resource::ResourceManager;

pub struct Scene<'a> {
  /// Resource manager.
  res_manager: ResourceManager,
  /// List of all models used in the scene.
  models: Vec<Model<'a>>,
  /// Model cache used to resolve Id based on instance name.
  model_cache: HashMap<String, Id>,
  /// Scene model instances.
  model_instances: Vec<Id>
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      res_manager: ResourceManager::new(root),
      models: Vec::new(),
      model_cache: HashMap::new(),
      model_instances: Vec::new()
    }
  }

  pub fn get_id<T>(&mut self, inst_name: String) -> Option<Id> where T: GetId {
    T::get_id(self, inst_name)
  }
}

pub type Id = u32;

pub trait GetId {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: String) -> Option<Id>;
}

impl<'b> GetId for Model<'b> {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: String) -> Option<Id> {
    match scene.model_cache.get(&inst_name).cloned() {
      id@Some(..) => id,
      None => {
        // cache miss; load then
        let path_str = format!("data/models/{}.obj", inst_name);
        let path = Path::new(&path_str);

        if path.exists() {
          match Model::load(&mut scene.res_manager, path) {
            Ok(model) => {
              let model_id = scene.models.len() as u32;

              // add the model to the list of loaded models
              scene.models.push(model);
              // add the model to the cache
              scene.model_cache.insert(inst_name, model_id);

              Some(model_id)
            },
            Err(e) => {
              err!("unable to load model '{}': '{:?}'", inst_name, e);
              None
            }
          }
        } else { // TODO: add a manifest override to look in somewhere else
          err!("model '{}' cannot be found", inst_name);
          None
        }
      }
    }
  }
}
<commit_msg>String -> &str for get_id in public interface.<commit_after>use std::collections::HashMap;
use std::path::Path;

use model::Model;
use resource::ResourceManager;

pub struct Scene<'a> {
  /// Resource manager.
  res_manager: ResourceManager,
  /// List of all models used in the scene.
  models: Vec<Model<'a>>,
  /// Model cache used to resolve Id based on instance name.
  model_cache: HashMap<String, Id>,
  /// Scene model instances.
  model_instances: Vec<Id>
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      res_manager: ResourceManager::new(root),
      models: Vec::new(),
      model_cache: HashMap::new(),
      model_instances: Vec::new()
    }
  }

  pub fn get_id<T>(&mut self, inst_name: &str) -> Option<Id> where T: GetId {
    T::get_id(self, inst_name)
  }

  pub fn resource_manager(&mut self) -> &mut ResourceManager {
    &mut self.res_manager
  }
}

pub type Id = u32;

pub trait GetId {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: &str) -> Option<Id>;
}

impl<'b> GetId for Model<'b> {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: &str) -> Option<Id> {
    match scene.model_cache.get(inst_name).cloned() {
      id@Some(..) => id,
      None => {
        // cache miss; load then
        let path_str = format!("data/models/{}.obj", inst_name);
        let path = Path::new(&path_str);

        if path.exists() {
          match Model::load(&mut scene.res_manager, path) {
            Ok(model) => {
              let model_id = scene.models.len() as u32;

              // add the model to the list of loaded models
              scene.models.push(model);
              // add the model to the cache
              scene.model_cache.insert(inst_name.to_owned(), model_id);

              Some(model_id)
            },
            Err(e) => {
              err!("unable to load model '{}': '{:?}'", inst_name, e);
              None
            }
          }
        } else { // TODO: add a manifest override to look in somewhere else
          err!("model '{}' cannot be found", inst_name);
          None
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>
extern crate regex;
extern crate core;

use std::str;
use std::slice::SliceConcatExt;
use self::core::str::StrExt;
use self::regex::Regex;
use std::num::ToPrimitive;

pub fn score(choice: &str, query: &str) -> f64 {
    if choice == "" || query.char_len() > choice.char_len() {
        0f64
    } else if query == "" {
        1f64
    } else {
        let match_length = compute_match_length(choice, query);

        if match_length > 0 {
            return 1f64 / choice.char_len().to_f64().unwrap();
        } else {
            return 0f64;
        }
    }
}

// Find the length of the shortest substring matching the given characters.
fn compute_match_length(string: &str, query: &str) -> usize {
    let re_string = make_query_regex(query);
    let re = match Regex::new(re_string.as_slice()) {
        Ok(re)   => { println!("RE: {}", re); re},
        Err(err) => panic!("{}", err.msg),
    };

    if re.is_match(string) {
        let caps = re.captures(string).unwrap();
        match caps.at(0) {
            Some(s) => return s.char_len(),
            None    => return 0
        };
    } else {
        return 0;
    }
}

// Creates a regex for performing a case-insensitive non-greedy fuzzy match.
// Turns "abc" into "(?i)a.*?b.*?c.*?".
fn make_query_regex(query: &str) -> String {
    let mut v = query
        .chars()
        .map(|ch| regex::quote(ch.to_string().as_slice()))
        .collect::<Vec<String>>();

    v.insert(0, String::from_str("(?i)"));

    return v.connect(".*?");
}

#[cfg(test)]
mod test {

    use super::core::str::StrExt;
    use std::num::ToPrimitive;

    #[test]
    fn scores_zero_when_the_choice_is_empty() {
        assert_eq!(super::score("", ""), 0f64);
    }

    #[test]
    fn scores_one_when_the_query_is_empty() {
        assert_eq!(super::score("a", ""), 1f64);
    }

    #[test]
    fn scores_zero_when_the_query_is_longer_than_the_choice() {
        assert_eq!(super::score("short", "longer"), 0f64);
    }

    #[test]
    fn scores_zero_when_only_a_prefix_of_the_query_matches() {
        assert_eq!(super::score("ab", "ac"), 0f64);
    }

    #[test]
    fn scores_greater_than_zero_when_it_matches() {
        assert!(super::score("a", "a") > 0f64);
        assert!(super::score("ab", "a") > 0f64);
        assert!(super::score("ba", "a") > 0f64);
        assert!(super::score("bab", "a") > 0f64);
        assert!(super::score("babababab", "aaaa") > 0f64);
    }

    #[test]
    fn scores_one_normalized_to_length_when_the_query_equals_the_choice() {
        assert_eq!(super::score("a", "a"), 1.0f64);
        assert_eq!(super::score("ab", "ab"), 0.5f64);
        assert_eq!(super::score("a long string", "a long string"),
            1.0f64 / ("a long string".char_len().to_f64().unwrap()));

        assert_eq!(super::score("spec/search_spec.rb", "sear"),
            1.0f64 / ("spec/search_spec.rb".char_len().to_f64().unwrap()));
    }

    // Character matching

    #[test]
    fn it_matches_punctuation() {
        assert!(super::score("/! symbols $^", "/!$^") > 0f64);
    }

    #[test]
    fn it_is_case_insensitive() {
      assert_eq!(super::score("a", "A"), 1f64);
      assert_eq!(super::score("A", "a"), 1f64);
    }
}

<commit_msg>Spec for not matching when same letter is repeated in the choice<commit_after>
extern crate regex;
extern crate core;

use std::str;
use std::slice::SliceConcatExt;
use self::core::str::StrExt;
use self::regex::Regex;
use std::num::ToPrimitive;

pub fn score(choice: &str, query: &str) -> f64 {
    if choice == "" || query.char_len() > choice.char_len() {
        0f64
    } else if query == "" {
        1f64
    } else {
        let match_length = compute_match_length(choice, query);

        if match_length > 0 {
            return 1f64 / choice.char_len().to_f64().unwrap();
        } else {
            return 0f64;
        }
    }
}

// Find the length of the shortest substring matching the given characters.
fn compute_match_length(string: &str, query: &str) -> usize {
    let re_string = make_query_regex(query);
    let re = match Regex::new(re_string.as_slice()) {
        Ok(re)   => { println!("RE: {}", re); re},
        Err(err) => panic!("{}", err.msg),
    };

    if re.is_match(string) {
        let caps = re.captures(string).unwrap();
        match caps.at(0) {
            Some(s) => return s.char_len(),
            None    => return 0
        };
    } else {
        return 0;
    }
}

// Creates a regex for performing a case-insensitive non-greedy fuzzy match.
// Turns "abc" into "(?i)a.*?b.*?c.*?".
fn make_query_regex(query: &str) -> String {
    let mut v = query
        .chars()
        .map(|ch| regex::quote(ch.to_string().as_slice()))
        .collect::<Vec<String>>();

    v.insert(0, String::from_str("(?i)"));

    return v.connect(".*?");
}

#[cfg(test)]
mod test {

    use super::core::str::StrExt;
    use std::num::ToPrimitive;

    #[test]
    fn scores_zero_when_the_choice_is_empty() {
        assert_eq!(super::score("", ""), 0f64);
    }

    #[test]
    fn scores_one_when_the_query_is_empty() {
        assert_eq!(super::score("a", ""), 1f64);
    }

    #[test]
    fn scores_zero_when_the_query_is_longer_than_the_choice() {
        assert_eq!(super::score("short", "longer"), 0f64);
    }

    #[test]
    fn scores_zero_when_only_a_prefix_of_the_query_matches() {
        assert_eq!(super::score("ab", "ac"), 0f64);
    }

    #[test]
    fn scores_greater_than_zero_when_it_matches() {
        assert!(super::score("a", "a") > 0f64);
        assert!(super::score("ab", "a") > 0f64);
        assert!(super::score("ba", "a") > 0f64);
        assert!(super::score("bab", "a") > 0f64);
        assert!(super::score("babababab", "aaaa") > 0f64);
    }

    #[test]
    fn scores_one_normalized_to_length_when_the_query_equals_the_choice() {
        assert_eq!(super::score("a", "a"), 1.0f64);
        assert_eq!(super::score("ab", "ab"), 0.5f64);
        assert_eq!(super::score("a long string", "a long string"),
            1.0f64 / ("a long string".char_len().to_f64().unwrap()));

        assert_eq!(super::score("spec/search_spec.rb", "sear"),
            1.0f64 / ("spec/search_spec.rb".char_len().to_f64().unwrap()));
    }

    // Character matching

    #[test]
    fn it_matches_punctuation() {
        assert!(super::score("/! symbols $^", "/!$^") > 0f64);
    }

    #[test]
    fn it_is_case_insensitive() {
        assert_eq!(super::score("a", "A"), 1f64);
        assert_eq!(super::score("A", "a"), 1f64);
    }

    #[test]
    fn it_doesnt_match_when_the_same_letter_is_repeated_in_the_choice() {
        assert_eq!(super::score("a", "aa"), 0f64);
    }
}

<|endoftext|>


<commit_before>#![crate_name = "uu_pr"]

// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

extern crate getopts;
extern crate chrono;

//#[macro_use]
//extern crate uucore;
use std::fs;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::vec::Vec;
use chrono::offset::Local;
use chrono::DateTime;

//use uucore::fs::is_stdin_interactive;

static NAME: &str = "pr";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static LINES_PER_PAGE: usize = 66;
static HEADER_LINES_PER_PAGE: usize = 5;
static TRAILER_LINES_PER_PAGE: usize = 5;
static CONTENT_LINES_PER_PAGE: usize = LINES_PER_PAGE - HEADER_LINES_PER_PAGE - TRAILER_LINES_PER_PAGE;
static NUMBERING_MODE_DEFAULT_SEPARATOR: &str = "\t";
static NUMBERING_MODE_DEFAULT_WIDTH: usize = 5;

struct OutputOptions {
    /// Line numbering mode
    number: Option<NumberingMode>,
    header: String,
}

impl AsRef<OutputOptions> for OutputOptions {
    fn as_ref(&self) -> &OutputOptions {
        self
    }
}

struct NumberingMode {
    /// Line numbering mode
    width: usize,
    separator: String,
}

impl Default for NumberingMode {
    fn default() -> NumberingMode {
        NumberingMode {
            width: NUMBERING_MODE_DEFAULT_WIDTH,
            separator: NUMBERING_MODE_DEFAULT_SEPARATOR.to_string(),
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optopt(
        "h",
        "",
        "Use the string header to replace the file name \
     in the header line.",
        "STRING",
    );

    opts.optflagopt(
        "n",
        "",
        "Provide width digit line numbering.  The default for width, if not specified, is 5.  The number occupies
           the first width column positions of each text column or each line of -m output.  If char (any nondigit
           character) is given, it is appended to the line number to separate it from whatever follows.  The default
           for char is a <tab>.  Line numbers longer than width columns are truncated.",
        "[char][width]",
    );

    opts.optflag("", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => panic!("Invalid options\n{}", e),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") || matches.free.is_empty() {
        println!("{} {} -- print files", NAME, VERSION);
        println!();
        println!("Usage: {} [+page] [-column] [-adFfmprt] [[-e] [char] [gap]]
        [-L locale] [-h header] [[-i] [char] [gap]]
        [-l lines] [-o offset] [[-s] [char]] [[-n] [char]
        [width]] [-w width] [-] [file ...].", NAME);
        println!();
        let usage: &str = "The pr utility is a printing and pagination filter
     for text files.  When multiple input files are spec-
     ified, each is read, formatted, and written to stan-
     dard output.  By default, the input is separated
     into 66-line pages, each with

     o   A 5-line header with the page number, date,
         time, and the pathname of the file.

     o   A 5-line trailer consisting of blank lines.

     If standard output is associated with a terminal,
     diagnostic messages are suppressed until the pr
     utility has completed processing.

     When multiple column output is specified, text col-
     umns are of equal width.  By default text columns
     are separated by at least one <blank>.  Input lines
     that do not fit into a text column are truncated.
     Lines are not truncated under single column output.";
        println!("{}", opts.usage(usage));
        if matches.free.is_empty() {
            return 1;
        }
        return 0;
    }

    let path = &matches.free[0];
    let header: String = matches.opt_str("h").unwrap_or(path.to_string());
    let numbering_options = matches.opt_str("n").map(|i| {
        NumberingMode {
            width: i.parse::<usize>().unwrap_or(NumberingMode::default().width),
            separator: NumberingMode::default().separator,
        }
    }).or_else(|| {
        if matches.opt_present("n") {
            return Some(NumberingMode::default());
        }
        return None;
    });

    let options = OutputOptions {
        number: numbering_options,
        header,
    };

    pr(&path, options);

    0
}

fn pr(path: &str, options: OutputOptions) -> std::io::Result<()> {
    let file = File::open(path)?;
    let file_last_modified_time = file_last_modified_time(path);
    let lines = BufReader::new(file).lines();
    let mut i = 0;
    let mut page: usize = 0;
    let mut buffered_content: Vec<String> = Vec::new();
    for line in lines {
        if i == CONTENT_LINES_PER_PAGE {
            page = page + 1;
            i = 0;
            flush_buffered_page(&file_last_modified_time, &mut buffered_content, &options, page);
        }
        i = i + 1;
        buffered_content.push(line?);
    }
    if i != 0 {
        page = page + 1;
        flush_buffered_page(&file_last_modified_time, &mut buffered_content, &options, page);
    }
    Ok(())
}

fn print_page(header_content: &Vec<String>, lines: &Vec<String>, options: &OutputOptions, page: usize) -> String {
    let mut page_content: Vec<String> = Vec::new();
    let trailer_content = trailer_content();
    assert_eq!(lines.len() <= CONTENT_LINES_PER_PAGE, true, "Only {} lines of content allowed in a pr output page", CONTENT_LINES_PER_PAGE.to_string());
    assert_eq!(header_content.len(), HEADER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr header", HEADER_LINES_PER_PAGE.to_string());
    assert_eq!(trailer_content.len(), TRAILER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr trailer", TRAILER_LINES_PER_PAGE.to_string());
    for x in header_content {
        page_content.push(x.to_string());
    }

    let width: usize = options.as_ref()
        .number.as_ref()
        .map(|i| i.width)
        .unwrap_or(0);
    let separator: String = options.as_ref()
        .number.as_ref()
        .map(|i| i.separator.to_string())
        .unwrap_or(NumberingMode::default().separator);

    let prev_lines = CONTENT_LINES_PER_PAGE * (page - 1);
    let mut i = 1;
    for x in lines {
        if options.number.is_none() {
            page_content.push(x.to_string());
        } else {
            let fmtd_line_number: String = get_fmtd_line_number(width, prev_lines + i, &separator);
            page_content.push(format!("{}{}", fmtd_line_number, x.to_string()));
        }
        i = i + 1;
    }
    page_content.extend(trailer_content);
    page_content.join("\n")
}

fn get_fmtd_line_number(width: usize, line_number: usize, separator: &String) -> String {
    format!("{:>width$}{}", take_last_n(&line_number.to_string(), width), separator, width = width)
}

fn take_last_n(s: &String, n: usize) -> &str {
    if s.len() >= n {
        &s[s.len() - n..]
    } else {
        s
    }
}

fn flush_buffered_page(file_last_modified_time: &String, buffered_content: &mut Vec<String>, options: &OutputOptions, page: usize) {
    let header = header_content(file_last_modified_time, &options.header, page);
    print!("{}", print_page(&header, buffered_content, &options, page));
    buffered_content.clear();
}

fn header_content(last_modified: &String, header: &String, page: usize) -> Vec<String> {
    let first_line: String = format!("{} {} Page {}", last_modified, header, page.to_string());
    vec!["".to_string(), "".to_string(), first_line, "".to_string(), "".to_string()]
}

fn file_last_modified_time(path: &str) -> String {
    let file_metadata = fs::metadata(path);
    return file_metadata.map(|i| {
        return i.modified().map(|x| {
            let datetime: DateTime<Local> = x.into();
            datetime.format("%b %d %H:%M %Y").to_string()
        }).unwrap_or(String::new());
    }).unwrap_or(String::new());
}

fn trailer_content() -> Vec<String> {
    vec!["".to_string(), "".to_string(), "".to_string(), "".to_string(), "".to_string()]
}
<commit_msg>pr: add support for multiple files<commit_after>#![crate_name = "uu_pr"]

// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

extern crate getopts;
extern crate chrono;

//#[macro_use]
//extern crate uucore;
use std::fs;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::vec::Vec;
use chrono::offset::Local;
use chrono::DateTime;
use getopts::Matches;

//use uucore::fs::is_stdin_interactive;

static NAME: &str = "pr";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static LINES_PER_PAGE: usize = 66;
static HEADER_LINES_PER_PAGE: usize = 5;
static TRAILER_LINES_PER_PAGE: usize = 5;
static CONTENT_LINES_PER_PAGE: usize = LINES_PER_PAGE - HEADER_LINES_PER_PAGE - TRAILER_LINES_PER_PAGE;
static NUMBERING_MODE_DEFAULT_SEPARATOR: &str = "\t";
static NUMBERING_MODE_DEFAULT_WIDTH: usize = 5;

struct OutputOptions {
    /// Line numbering mode
    number: Option<NumberingMode>,
    header: String,
}

impl AsRef<OutputOptions> for OutputOptions {
    fn as_ref(&self) -> &OutputOptions {
        self
    }
}

struct NumberingMode {
    /// Line numbering mode
    width: usize,
    separator: String,
}

impl Default for NumberingMode {
    fn default() -> NumberingMode {
        NumberingMode {
            width: NUMBERING_MODE_DEFAULT_WIDTH,
            separator: NUMBERING_MODE_DEFAULT_SEPARATOR.to_string(),
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optopt(
        "h",
        "",
        "Use the string header to replace the file name \
     in the header line.",
        "STRING",
    );

    opts.optflagopt(
        "n",
        "",
        "Provide width digit line numbering.  The default for width, if not specified, is 5.  The number occupies
           the first width column positions of each text column or each line of -m output.  If char (any nondigit
           character) is given, it is appended to the line number to separate it from whatever follows.  The default
           for char is a <tab>.  Line numbers longer than width columns are truncated.",
        "[char][width]",
    );

    opts.optflag("", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => panic!("Invalid options\n{}", e),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") || matches.free.is_empty() {
        println!("{} {} -- print files", NAME, VERSION);
        println!();
        println!("Usage: {} [+page] [-column] [-adFfmprt] [[-e] [char] [gap]]
        [-L locale] [-h header] [[-i] [char] [gap]]
        [-l lines] [-o offset] [[-s] [char]] [[-n] [char]
        [width]] [-w width] [-] [file ...].", NAME);
        println!();
        let usage: &str = "The pr utility is a printing and pagination filter
     for text files.  When multiple input files are spec-
     ified, each is read, formatted, and written to stan-
     dard output.  By default, the input is separated
     into 66-line pages, each with

     o   A 5-line header with the page number, date,
         time, and the pathname of the file.

     o   A 5-line trailer consisting of blank lines.

     If standard output is associated with a terminal,
     diagnostic messages are suppressed until the pr
     utility has completed processing.

     When multiple column output is specified, text col-
     umns are of equal width.  By default text columns
     are separated by at least one <blank>.  Input lines
     that do not fit into a text column are truncated.
     Lines are not truncated under single column output.";
        println!("{}", opts.usage(usage));
        if matches.free.is_empty() {
            return 1;
        }
        return 0;
    }

    let mut files = matches.free.clone();
    if files.is_empty() {
        //For stdin
        files.push("-".to_owned());
    }

    for f in files {
        let header: String = matches.opt_str("h").unwrap_or(f.to_string());
        let options = build_options(&matches, header);
        pr(&f, options);
    }

    0
}

fn build_options(matches: &Matches, header: String) -> OutputOptions {
    let numbering_options = matches.opt_str("n").map(|i| {
        NumberingMode {
            width: i.parse::<usize>().unwrap_or(NumberingMode::default().width),
            separator: NumberingMode::default().separator,
        }
    }).or_else(|| {
        if matches.opt_present("n") {
            return Some(NumberingMode::default());
        }
        return None;
    });
    OutputOptions {
        number: numbering_options,
        header,
    }
}

fn pr(path: &str, options: OutputOptions) -> std::io::Result<()> {
    let file = File::open(path)?;
    let file_last_modified_time = file_last_modified_time(path);
    let lines = BufReader::new(file).lines();
    let mut i = 0;
    let mut page: usize = 0;
    let mut buffered_content: Vec<String> = Vec::new();
    for line in lines {
        if i == CONTENT_LINES_PER_PAGE {
            page = page + 1;
            i = 0;
            flush_buffered_page(&file_last_modified_time, &mut buffered_content, &options, page);
        }
        i = i + 1;
        buffered_content.push(line?);
    }
    if i != 0 {
        page = page + 1;
        flush_buffered_page(&file_last_modified_time, &mut buffered_content, &options, page);
    }
    Ok(())
}

fn print_page(header_content: &Vec<String>, lines: &Vec<String>, options: &OutputOptions, page: usize) -> String {
    let mut page_content: Vec<String> = Vec::new();
    let trailer_content = trailer_content();
    assert_eq!(lines.len() <= CONTENT_LINES_PER_PAGE, true, "Only {} lines of content allowed in a pr output page", CONTENT_LINES_PER_PAGE.to_string());
    assert_eq!(header_content.len(), HEADER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr header", HEADER_LINES_PER_PAGE.to_string());
    assert_eq!(trailer_content.len(), TRAILER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr trailer", TRAILER_LINES_PER_PAGE.to_string());
    for x in header_content {
        page_content.push(x.to_string());
    }

    let width: usize = options.as_ref()
        .number.as_ref()
        .map(|i| i.width)
        .unwrap_or(0);
    let separator: String = options.as_ref()
        .number.as_ref()
        .map(|i| i.separator.to_string())
        .unwrap_or(NumberingMode::default().separator);

    let prev_lines = CONTENT_LINES_PER_PAGE * (page - 1);
    let mut i = 1;
    for x in lines {
        if options.number.is_none() {
            page_content.push(x.to_string());
        } else {
            let fmtd_line_number: String = get_fmtd_line_number(width, prev_lines + i, &separator);
            page_content.push(format!("{}{}", fmtd_line_number, x.to_string()));
        }
        i = i + 1;
    }
    page_content.extend(trailer_content);
    page_content.join("\n")
}

fn get_fmtd_line_number(width: usize, line_number: usize, separator: &String) -> String {
    format!("{:>width$}{}", take_last_n(&line_number.to_string(), width), separator, width = width)
}

fn take_last_n(s: &String, n: usize) -> &str {
    if s.len() >= n {
        &s[s.len() - n..]
    } else {
        s
    }
}

fn flush_buffered_page(file_last_modified_time: &String, buffered_content: &mut Vec<String>, options: &OutputOptions, page: usize) {
    let header = header_content(file_last_modified_time, &options.header, page);
    print!("{}", print_page(&header, buffered_content, &options, page));
    buffered_content.clear();
}

fn header_content(last_modified: &String, header: &String, page: usize) -> Vec<String> {
    let first_line: String = format!("{} {} Page {}", last_modified, header, page.to_string());
    vec!["".to_string(), "".to_string(), first_line, "".to_string(), "".to_string()]
}

fn file_last_modified_time(path: &str) -> String {
    let file_metadata = fs::metadata(path);
    return file_metadata.map(|i| {
        return i.modified().map(|x| {
            let datetime: DateTime<Local> = x.into();
            datetime.format("%b %d %H:%M %Y").to_string()
        }).unwrap_or(String::new());
    }).unwrap_or(String::new());
}

fn trailer_content() -> Vec<String> {
    vec!["".to_string(), "".to_string(), "".to_string(), "".to_string(), "".to_string()]
}
<|endoftext|>


<commit_before>// Hidden internal interface
#![allow(missing_docs)]

use std::io::{self, BufRead, Lines, Read, Write};
use std::collections::BTreeMap;
use std::fmt::Arguments;
use bufstream::BufStream;

use reply::Reply;
use error::{Error, ProtoError, Result};
use convert::FromIter;

pub struct Pairs<I>(pub I);

impl<I> Iterator for Pairs<I>
    where I: Iterator<Item = io::Result<String>>
{
    type Item = Result<(String, String)>;
    fn next(&mut self) -> Option<Result<(String, String)>> {
        let reply: Option<Result<Reply>> = self.0
                                               .next()
                                               .map(|v| v.map_err(Error::Io).and_then(|s| s.parse::<Reply>().map_err(Error::Parse)));
        match reply {
            Some(Ok(Reply::Pair(a, b))) => Some(Ok((a, b))),
            None | Some(Ok(Reply::Ok)) => None,
            Some(Ok(Reply::Ack(e))) => Some(Err(Error::Server(e))),
            Some(Err(e)) => Some(Err(e)),
        }
    }
}

struct Maps<'a, I: 'a> {
    pairs: &'a mut Pairs<I>,
    sep: &'a str,
    value: Option<String>,
    done: bool,
    first: bool,
}

impl<'a, I> Iterator for Maps<'a, I>
    where I: Iterator<Item = io::Result<String>>
{
    type Item = Result<BTreeMap<String, String>>;
    fn next(&mut self) -> Option<Result<BTreeMap<String, String>>> {
        if self.done {
            return None;
        }

        let mut map = BTreeMap::new();

        if let Some(b) = self.value.take() {
            map.insert(self.sep.to_owned(), b);
        }

        loop {
            match self.pairs.next() {
                Some(Ok((a, b))) => {
                    if &*a == self.sep {
                        self.value = Some(b);
                        if self.first {
                            self.first = false;
                            return self.next();
                        }
                        break;
                    } else {
                        map.insert(a, b);
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => {
                    self.done = true;
                    break;
                }
            }
        }

        if map.is_empty() { None } else { Some(Ok(map)) }
    }
}

impl<I> Pairs<I>
    where I: Iterator<Item = io::Result<String>>
{
    pub fn split<'a, 'b: 'a>(&'a mut self, f: &'b str) -> Maps<'a, I> {
        Maps {
            pairs: self,
            sep: f,
            value: None,
            done: false,
            first: true,
        }
    }
}

// Client inner communication methods {{{
#[doc(hidden)]
pub trait Proto {
    type Stream: Read + Write;

    fn read_line(&mut self) -> Result<String>;
    fn read_pairs(&mut self) -> Pairs<Lines<&mut BufStream<Self::Stream>>>;

    fn run_command(&mut self, command: &str) -> Result<()>;
    fn run_command_fmt(&mut self, command: Arguments) -> Result<()>;

    fn read_map(&mut self) -> Result<BTreeMap<String, String>> {
        self.read_pairs().collect()
    }

    fn read_struct<'a, T>(&'a mut self) -> Result<T>
        where T: 'a + FromIter,
              Self::Stream: 'a
    {
        FromIter::from_iter(self.read_pairs())
    }

    fn drain(&mut self) -> Result<()> {
        loop {
            let reply = try!(self.read_line());
            match &*reply {
                "OK" | "list_OK" => break,
                _ => (),
            }
        }
        Ok(())
    }

    fn expect_ok(&mut self) -> Result<()> {
        let line = try!(self.read_line());

        match line.parse::<Reply>() {
            Ok(Reply::Ok) => Ok(()),
            Ok(Reply::Ack(e)) => Err(Error::Server(e)),
            Ok(_) => Err(Error::Proto(ProtoError::NotOk)),
            Err(e) => Err(From::from(e)),
        }
    }

    fn read_pair(&mut self) -> Result<(String, String)> {
        let line = try!(self.read_line());

        match line.parse::<Reply>() {
            Ok(Reply::Pair(a, b)) => Ok((a, b)),
            Ok(Reply::Ok) => Err(Error::Proto(ProtoError::NotPair)),
            Ok(Reply::Ack(e)) => Err(Error::Server(e)),
            Err(e) => Err(Error::Parse(e)),
        }
    }

    fn read_field(&mut self, field: &'static str) -> Result<String> {
        let (a, b) = try!(self.read_pair());
        if &*a == field { Ok(b) } else { Err(Error::Proto(ProtoError::NoField(field))) }
    }
}
// }}}
<commit_msg>fix maps struct visibility<commit_after>// Hidden internal interface
#![allow(missing_docs)]

use std::io::{self, BufRead, Lines, Read, Write};
use std::collections::BTreeMap;
use std::fmt::Arguments;
use bufstream::BufStream;

use reply::Reply;
use error::{Error, ProtoError, Result};
use convert::FromIter;

pub struct Pairs<I>(pub I);

impl<I> Iterator for Pairs<I>
    where I: Iterator<Item = io::Result<String>>
{
    type Item = Result<(String, String)>;
    fn next(&mut self) -> Option<Result<(String, String)>> {
        let reply: Option<Result<Reply>> = self.0
                                               .next()
                                               .map(|v| v.map_err(Error::Io).and_then(|s| s.parse::<Reply>().map_err(Error::Parse)));
        match reply {
            Some(Ok(Reply::Pair(a, b))) => Some(Ok((a, b))),
            None | Some(Ok(Reply::Ok)) => None,
            Some(Ok(Reply::Ack(e))) => Some(Err(Error::Server(e))),
            Some(Err(e)) => Some(Err(e)),
        }
    }
}

pub struct Maps<'a, I: 'a> {
    pairs: &'a mut Pairs<I>,
    sep: &'a str,
    value: Option<String>,
    done: bool,
    first: bool,
}

impl<'a, I> Iterator for Maps<'a, I>
    where I: Iterator<Item = io::Result<String>>
{
    type Item = Result<BTreeMap<String, String>>;
    fn next(&mut self) -> Option<Result<BTreeMap<String, String>>> {
        if self.done {
            return None;
        }

        let mut map = BTreeMap::new();

        if let Some(b) = self.value.take() {
            map.insert(self.sep.to_owned(), b);
        }

        loop {
            match self.pairs.next() {
                Some(Ok((a, b))) => {
                    if &*a == self.sep {
                        self.value = Some(b);
                        if self.first {
                            self.first = false;
                            return self.next();
                        }
                        break;
                    } else {
                        map.insert(a, b);
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => {
                    self.done = true;
                    break;
                }
            }
        }

        if map.is_empty() { None } else { Some(Ok(map)) }
    }
}

impl<I> Pairs<I>
    where I: Iterator<Item = io::Result<String>>
{
    pub fn split<'a, 'b: 'a>(&'a mut self, f: &'b str) -> Maps<'a, I> {
        Maps {
            pairs: self,
            sep: f,
            value: None,
            done: false,
            first: true,
        }
    }
}

// Client inner communication methods {{{
#[doc(hidden)]
pub trait Proto {
    type Stream: Read + Write;

    fn read_line(&mut self) -> Result<String>;
    fn read_pairs(&mut self) -> Pairs<Lines<&mut BufStream<Self::Stream>>>;

    fn run_command(&mut self, command: &str) -> Result<()>;
    fn run_command_fmt(&mut self, command: Arguments) -> Result<()>;

    fn read_map(&mut self) -> Result<BTreeMap<String, String>> {
        self.read_pairs().collect()
    }

    fn read_struct<'a, T>(&'a mut self) -> Result<T>
        where T: 'a + FromIter,
              Self::Stream: 'a
    {
        FromIter::from_iter(self.read_pairs())
    }

    fn drain(&mut self) -> Result<()> {
        loop {
            let reply = try!(self.read_line());
            match &*reply {
                "OK" | "list_OK" => break,
                _ => (),
            }
        }
        Ok(())
    }

    fn expect_ok(&mut self) -> Result<()> {
        let line = try!(self.read_line());

        match line.parse::<Reply>() {
            Ok(Reply::Ok) => Ok(()),
            Ok(Reply::Ack(e)) => Err(Error::Server(e)),
            Ok(_) => Err(Error::Proto(ProtoError::NotOk)),
            Err(e) => Err(From::from(e)),
        }
    }

    fn read_pair(&mut self) -> Result<(String, String)> {
        let line = try!(self.read_line());

        match line.parse::<Reply>() {
            Ok(Reply::Pair(a, b)) => Ok((a, b)),
            Ok(Reply::Ok) => Err(Error::Proto(ProtoError::NotPair)),
            Ok(Reply::Ack(e)) => Err(Error::Server(e)),
            Err(e) => Err(Error::Parse(e)),
        }
    }

    fn read_field(&mut self, field: &'static str) -> Result<String> {
        let (a, b) = try!(self.read_pair());
        if &*a == field { Ok(b) } else { Err(Error::Proto(ProtoError::NoField(field))) }
    }
}
// }}}
<|endoftext|>


<commit_before>use serde;
use serde_derive::{Deserialize, Serialize};
use std::fmt::Debug;
use std::mem;
use std::ops::Deref;

/// An object that can be incrementally updated with events.
pub trait Incremental<E>: Sized {
    /// Try to update the object with an event.
    fn update(self, e: &E) -> Self;
}

/// An incremental object that can fail when updated.
///
/// Use the `Incremental` implementation on a `Result` type with `FailingIncremental` value to use
/// this.
pub trait FailingIncremental<E>: Sized {
    /// Error in case an event couldn't be handled.
    type Error: Debug;

    /// Try to update the object with an event.
    fn update(self, e: &E) -> Result<Self, Self::Error>;
}

impl<T: FailingIncremental<E>, E> Incremental<E> for Result<T, T::Error> {
    fn update(self, e: &E) -> Self {
        match self {
            Ok(state) => state.update(e),
            err => err,
        }
    }
}

/// Handle that stores an `Incremental` object and the event sequence used to build it.
///
/// Serializes itself by only storing the log.
///
/// # Examples
///
/// ```
/// use calx::{Incremental, IncrementalState};
///
/// #[derive(Default)]
/// struct State(u32);
///
/// impl Incremental<u32> for State {
///     fn update(self, e: &u32) -> State { State(self.0 + *e) }
/// }
///
/// impl From<u32> for State {
///     fn from(x: u32) -> Self { State(x) }
/// }
///
/// let mut handle: IncrementalState<State, u32, u32> = Default::default();
/// assert_eq!(handle.0, 0);
///
/// for x in &[1, 2, 3, 4] { handle.push(*x); }
/// assert_eq!(handle.0, 10);
/// handle.pop();
/// assert_eq!(handle.0, 6);
/// ```
pub struct IncrementalState<T: Incremental<E>, U: Into<T> + Clone, E> {
    state: T,
    history: History<U, E>,
}

#[derive(Serialize, Deserialize)]
struct History<U, E> {
    seed: U,
    log: Vec<E>,
}

// Implemented manually instead of derived so that T::Event doesn't need to implement Default.
impl<T: Incremental<E>, U: Into<T> + Clone + Default, E> Default for IncrementalState<T, U, E> {
    fn default() -> Self { IncrementalState::new(U::default()) }
}

impl<T: Incremental<E>, U: Into<T> + Clone, E> IncrementalState<T, U, E> {
    pub fn new(seed: U) -> Self {
        IncrementalState {
            state: seed.clone().into(),
            history: History {
                seed,
                log: Vec::new(),
            },
        }
    }
}

impl<T: Incremental<E>, U: Into<T> + Clone, E> IncrementalState<T, U, E> {
    pub fn push(&mut self, e: E) {
        // XXX: Need to get state away from borrow checker for updating, is there a better way than
        // ugly unsafe tricks?
        let state = mem::replace(&mut self.state, unsafe { mem::uninitialized() }).update(&e);
        self.state = state;
        self.history.log.push(e);
    }
}

impl<T: Incremental<E>, U: Into<T> + Clone, E> IncrementalState<T, U, E> {
    pub fn pop(&mut self) -> Option<E> {
        // TODO: Way to pop several items without O(n) delay for each.
        let ret = self.history.log.pop();
        self.replay();
        ret
    }

    fn replay(&mut self) {
        let mut state: T = self.history.seed.clone().into();

        for e in &self.history.log {
            state = state.update(e);
        }

        self.state = state;
    }
}

impl<T: Incremental<E>, U: Into<T> + Clone, E> Deref for IncrementalState<T, U, E> {
    type Target = T;

    fn deref(&self) -> &T { &self.state }
}

impl<T, U, E> serde::Serialize for IncrementalState<T, U, E>
where
    T: Incremental<E>,
    U: Into<T> + Clone + serde::Serialize,
    E: serde::Serialize,
{
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        self.history.serialize(s)
    }
}

impl<'a, T, U, E> serde::Deserialize<'a> for IncrementalState<T, U, E>
where
    T: Incremental<E>,
    U: Into<T> + Clone + serde::Deserialize<'a>,
    E: serde::Deserialize<'a>,
{
    fn deserialize<D: serde::Deserializer<'a>>(d: D) -> Result<Self, D::Error> {
        let history: History<U, E> = History::deserialize(d)?;
        let state = history.seed.clone().into();
        let mut ret: Self = IncrementalState { state, history };
        ret.replay();
        Ok(ret)
    }
}
<commit_msg>feat: Remove the FailingIncremental type<commit_after>use serde;
use serde_derive::{Deserialize, Serialize};
use std::mem;
use std::ops::Deref;

/// An object that can be incrementally updated with events.
pub trait Incremental<E>: Sized {
    /// Try to update the object with an event.
    fn update(self, e: &E) -> Self;
}

/// Handle that stores an `Incremental` object and the event sequence used to build it.
///
/// Serializes itself by only storing the log.
///
/// # Examples
///
/// ```
/// use calx::{Incremental, IncrementalState};
///
/// #[derive(Default)]
/// struct State(u32);
///
/// impl Incremental<u32> for State {
///     fn update(self, e: &u32) -> State { State(self.0 + *e) }
/// }
///
/// impl From<u32> for State {
///     fn from(x: u32) -> Self { State(x) }
/// }
///
/// let mut handle: IncrementalState<State, u32, u32> = Default::default();
/// assert_eq!(handle.0, 0);
///
/// for x in &[1, 2, 3, 4] { handle.push(*x); }
/// assert_eq!(handle.0, 10);
/// handle.pop();
/// assert_eq!(handle.0, 6);
/// ```
pub struct IncrementalState<T: Incremental<E>, U: Into<T> + Clone, E> {
    state: T,
    history: History<U, E>,
}

#[derive(Serialize, Deserialize)]
struct History<U, E> {
    seed: U,
    log: Vec<E>,
}

// Implemented manually instead of derived so that T::Event doesn't need to implement Default.
impl<T: Incremental<E>, U: Into<T> + Clone + Default, E> Default for IncrementalState<T, U, E> {
    fn default() -> Self { IncrementalState::new(U::default()) }
}

impl<T: Incremental<E>, U: Into<T> + Clone, E> IncrementalState<T, U, E> {
    pub fn new(seed: U) -> Self {
        IncrementalState {
            state: seed.clone().into(),
            history: History {
                seed,
                log: Vec::new(),
            },
        }
    }
}

impl<T: Incremental<E>, U: Into<T> + Clone, E> IncrementalState<T, U, E> {
    pub fn push(&mut self, e: E) {
        // XXX: Need to get state away from borrow checker for updating, is there a better way than
        // ugly unsafe tricks?
        let state = mem::replace(&mut self.state, unsafe { mem::uninitialized() }).update(&e);
        self.state = state;
        self.history.log.push(e);
    }
}

impl<T: Incremental<E>, U: Into<T> + Clone, E> IncrementalState<T, U, E> {
    pub fn pop(&mut self) -> Option<E> {
        // TODO: Way to pop several items without O(n) delay for each.
        let ret = self.history.log.pop();
        self.replay();
        ret
    }

    fn replay(&mut self) {
        let mut state: T = self.history.seed.clone().into();

        for e in &self.history.log {
            state = state.update(e);
        }

        self.state = state;
    }
}

impl<T: Incremental<E>, U: Into<T> + Clone, E> Deref for IncrementalState<T, U, E> {
    type Target = T;

    fn deref(&self) -> &T { &self.state }
}

impl<T, U, E> serde::Serialize for IncrementalState<T, U, E>
where
    T: Incremental<E>,
    U: Into<T> + Clone + serde::Serialize,
    E: serde::Serialize,
{
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        self.history.serialize(s)
    }
}

impl<'a, T, U, E> serde::Deserialize<'a> for IncrementalState<T, U, E>
where
    T: Incremental<E>,
    U: Into<T> + Clone + serde::Deserialize<'a>,
    E: serde::Deserialize<'a>,
{
    fn deserialize<D: serde::Deserializer<'a>>(d: D) -> Result<Self, D::Error> {
        let history: History<U, E> = History::deserialize(d)?;
        let state = history.seed.clone().into();
        let mut ret: Self = IncrementalState { state, history };
        ret.replay();
        Ok(ret)
    }
}
<|endoftext|>


<commit_before>use dirs;
use std::fs;
use std::io::ErrorKind;
use std::process::Command;

pub fn run() {
    // Environment (Unix)

    let password_manager_status = match Command::new("brew")
        .arg("cask")
        .arg("list")
        .arg("1password")
        .output()
    {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if password_manager_status.success() {
        println!("Password manager is already installed.")
    } else {
        println!("Installing password manager.");
        match Command::new("brew")
            .arg("cask")
            .arg("install")
            .arg("1password")
            .output()
        {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let search_tool_status = match Command::new("brew").arg("list").arg("ripgrep").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if search_tool_status.success() {
        println!("Search tool is already installed.")
    } else {
        println!("Installing search tool.");
        match Command::new("brew").arg("install").arg("ripgrep").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    // Version control (Git)

    let version_control_status = match Command::new("brew").arg("list").arg("git").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if version_control_status.success() {
        println!("Version control is already installed.")
    } else {
        println!("Installing version control.");
        match Command::new("brew").arg("install").arg("git").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    // Editor (Vim)

    let editor_status = match Command::new("brew").arg("list").arg("vim").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if editor_status.success() {
        println!("Editor is already installed.")
    } else {
        println!("Installing editor.");
        match Command::new("brew").arg("install").arg("vim").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let home_dir = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    let editor_plugins_path = &home_dir
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start");

    if editor_plugins_path.exists() {
        println!("Editor plugins directory already exists.")
    } else {
        println!("Creating editor plugins directory.");
        match fs::create_dir_all(&editor_plugins_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    let editor_configuration_path = home_dir.join(".vimrc");

    if editor_configuration_path.exists() {
        println!("Editor configuration file already exists.")
    } else {
        println!("Creating editor configuration file.");
        match fs::File::create(&editor_configuration_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    match fs::read_dir(&editor_plugins_path) {
        Ok(_) => println!("Editor plugins are already installed."),
        Err(_) => {
            println!("Installing editor plugin to normalize editor defaults.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/tpope/vim-sensible")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor indentation.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/tpope/vim-sleuth")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor languages.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/sheerun/vim-polyglot")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor ignore patterns.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/octref/RootIgnore")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor static analysis.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/dense-analysis/ale")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Adding editor configuration to enhance editor search.");

            match fs::write(&editor_configuration_path, "set grepprg=rg\\ --vimgrep") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            match fs::write(&editor_configuration_path, "set grepformat=%f:%l:%c:%m") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor colors.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/arcticicestudio/nord-vim")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Adding editor configuration to enhance editor colors.");

            match fs::write(editor_configuration_path, "colorscheme nord") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }
        }
    };

    // Application programming (JavaScript)

    let application_programming_toolchain_status =
        match Command::new("brew").arg("list").arg("node").output() {
            Ok(output) => output.status,
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        };

    if application_programming_toolchain_status.success() {
        println!("Application programming toolchain is already installed.")
    } else {
        println!("Installing application programming toolchain.");
        match Command::new("brew").arg("install").arg("node").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    // Systems programming (Rust)

    let systems_programming_toolchain_status =
        match Command::new("brew").arg("list").arg("rustup-init").output() {
            Ok(output) => output.status,
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        };

    if systems_programming_toolchain_status.success() {
        println!("Systems programming toolchain is already installed.")
    } else {
        println!("Installing systems programming toolchain.");
        match Command::new("brew")
            .arg("install")
            .arg("rustup-init")
            .output()
        {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }

        match Command::new("rustup-init").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `rustup-init` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }
}
<commit_msg>Make sure repos directory is setup as end script expects<commit_after>use dirs;
use std::fs;
use std::io::ErrorKind;
use std::process::Command;

pub fn run() {
    // Environment (Unix)

    let password_manager_status = match Command::new("brew")
        .arg("cask")
        .arg("list")
        .arg("1password")
        .output()
    {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if password_manager_status.success() {
        println!("Password manager is already installed.")
    } else {
        println!("Installing password manager.");
        match Command::new("brew")
            .arg("cask")
            .arg("install")
            .arg("1password")
            .output()
        {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let search_tool_status = match Command::new("brew").arg("list").arg("ripgrep").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if search_tool_status.success() {
        println!("Search tool is already installed.")
    } else {
        println!("Installing search tool.");
        match Command::new("brew").arg("install").arg("ripgrep").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    // Version control (Git)

    let version_control_status = match Command::new("brew").arg("list").arg("git").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if version_control_status.success() {
        println!("Version control is already installed.")
    } else {
        println!("Installing version control.");
        match Command::new("brew").arg("install").arg("git").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let home_dir = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    let repos_path = &home_dir
        .join("repos");

    if repos_path.exists() {
        println!("Repos directory already exists.")
    } else {
        println!("Creating repos directory.");
        match fs::create_dir_all(&repos_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    match fs::read_dir(&repos_path) {
        Ok(_) => println!("Repos are already installed."),
        Err(_) => {
            println!("Cloning scripts repo.");

            match Command::new("git")
                .current_dir(&repos_path)
                .arg("clone")
                .arg("https://github.com/trevordmiller/scripts")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Cloning study repo.");

            match Command::new("git")
                .current_dir(&repos_path)
                .arg("clone")
                .arg("https://github.com/trevordmiller/study")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Cloning trevordmiller.github.io repo.");

            match Command::new("git")
                .current_dir(&repos_path)
                .arg("clone")
                .arg("https://github.com/trevordmiller/trevordmiller.github.io")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }
        }
    };

    // Editor (Vim)

    let editor_status = match Command::new("brew").arg("list").arg("vim").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if editor_status.success() {
        println!("Editor is already installed.")
    } else {
        println!("Installing editor.");
        match Command::new("brew").arg("install").arg("vim").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let editor_plugins_path = &home_dir
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start");

    if editor_plugins_path.exists() {
        println!("Editor plugins directory already exists.")
    } else {
        println!("Creating editor plugins directory.");
        match fs::create_dir_all(&editor_plugins_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    let editor_configuration_path = home_dir.join(".vimrc");

    if editor_configuration_path.exists() {
        println!("Editor configuration file already exists.")
    } else {
        println!("Creating editor configuration file.");
        match fs::File::create(&editor_configuration_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    match fs::read_dir(&editor_plugins_path) {
        Ok(_) => println!("Editor plugins are already installed."),
        Err(_) => {
            println!("Installing editor plugin to normalize editor defaults.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/tpope/vim-sensible")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor indentation.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/tpope/vim-sleuth")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor languages.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/sheerun/vim-polyglot")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor ignore patterns.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/octref/RootIgnore")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor static analysis.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/dense-analysis/ale")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Adding editor configuration to enhance editor search.");

            match fs::write(&editor_configuration_path, "set grepprg=rg\\ --vimgrep") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            match fs::write(&editor_configuration_path, "set grepformat=%f:%l:%c:%m") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor colors.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/arcticicestudio/nord-vim")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Adding editor configuration to enhance editor colors.");

            match fs::write(editor_configuration_path, "colorscheme nord") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }
        }
    };

    // Application programming (JavaScript)

    let application_programming_toolchain_status =
        match Command::new("brew").arg("list").arg("node").output() {
            Ok(output) => output.status,
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        };

    if application_programming_toolchain_status.success() {
        println!("Application programming toolchain is already installed.")
    } else {
        println!("Installing application programming toolchain.");
        match Command::new("brew").arg("install").arg("node").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    // Systems programming (Rust)

    let systems_programming_toolchain_status =
        match Command::new("brew").arg("list").arg("rustup-init").output() {
            Ok(output) => output.status,
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        };

    if systems_programming_toolchain_status.success() {
        println!("Systems programming toolchain is already installed.")
    } else {
        println!("Installing systems programming toolchain.");
        match Command::new("brew")
            .arg("install")
            .arg("rustup-init")
            .output()
        {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }

        match Command::new("rustup-init").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `rustup-init` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2014 Y. T. CHUNG <zonyitoo@gmail.com>

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! TcpRelay server that running on the server side

use std::io;
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::rc::Rc;
use std::collections::HashSet;

use config::{Config, ServerConfig};

use relay::socks5::Address;
use relay::{BoxIoFuture, boxed_future};
use relay::dns_resolver::DnsResolver;

use futures::{self, Future};
use futures::stream::Stream;

use tokio_core::reactor::Handle;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::io::{Io, ReadHalf, WriteHalf};
use tokio_core::io::copy;

use net2::TcpBuilder;

use ip::IpAddr;

use super::{tunnel, proxy_handshake, DecryptedHalf, EncryptedHalfFut};

/// Context for doing handshake with client
pub struct TcpRelayClientHandshake {
    handle: Handle,
    s: TcpStream,
    svr_cfg: Rc<ServerConfig>,
    forbidden_ip: Rc<HashSet<IpAddr>>,
}

impl TcpRelayClientHandshake {
    /// Doing handshake with client
    pub fn handshake(self) -> BoxIoFuture<TcpRelayClientPending> {
        let TcpRelayClientHandshake { handle, forbidden_ip, s, svr_cfg } = self;

        let fut = proxy_handshake(s, svr_cfg).and_then(|(r_fut, w_fut)| {
            r_fut.and_then(|r| Address::read_from(r).map_err(From::from))
                .map(move |(r, addr)| {
                    TcpRelayClientPending {
                        handle: handle,
                        r: r,
                        addr: addr,
                        w: w_fut,
                        forbidden_ip: forbidden_ip,
                    }
                })
        });
        boxed_future(fut)
    }
}

/// Context for connecting remote
pub struct TcpRelayClientPending {
    handle: Handle,
    r: DecryptedHalf,
    addr: Address,
    w: EncryptedHalfFut,
    forbidden_ip: Rc<HashSet<IpAddr>>,
}

impl TcpRelayClientPending {
    /// Resolve Address to SocketAddr
    fn resolve_address(addr: Address) -> BoxIoFuture<SocketAddr> {
        match addr {
            Address::SocketAddress(addr) => Box::new(futures::finished(addr)),
            Address::DomainNameAddress(dname, port) => {
                let fut = DnsResolver::resolve(&dname[..]).and_then(move |ipaddr| {
                    Ok(match ipaddr {
                        IpAddr::V4(v4) => SocketAddr::V4(SocketAddrV4::new(v4, port)),
                        IpAddr::V6(v6) => SocketAddr::V6(SocketAddrV6::new(v6, port, 0, 0)),
                    })
                });
                Box::new(fut)
            }
        }
    }

    /// Resolve remote address to SocketAddr
    /// Report failure if the SocketAddr is forbidden by `forbidden_ip`
    fn resolve_remote(addr: Address, forbidden_ip: Rc<HashSet<IpAddr>>) -> BoxIoFuture<SocketAddr> {
        let fut = TcpRelayClientPending::resolve_address(addr).and_then(move |addr| {
            trace!("Resolved address as {}", addr);
            let ipaddr = match addr.clone() {
                SocketAddr::V4(v4) => IpAddr::V4(v4.ip().clone()),
                SocketAddr::V6(v6) => IpAddr::V6(v6.ip().clone()),
            };

            if forbidden_ip.contains(&ipaddr) {
                info!("{} has been forbidden", ipaddr);
                let err = io::Error::new(io::ErrorKind::Other, "Forbidden IP");
                Err(err)
            } else {
                Ok(addr)
            }
        });
        Box::new(fut)
    }

    /// Connect to the remote server
    fn connect_remote(handle: Handle, addr: Address, forbidden_ip: Rc<HashSet<IpAddr>>) -> BoxIoFuture<TcpStream> {
        info!("Connecting to remote {}", addr);
        Box::new(TcpRelayClientPending::resolve_remote(addr, forbidden_ip)
            .and_then(move |addr| TcpStream::connect(&addr, &handle)))
    }

    /// Connect to the remote server
    pub fn connect(self) -> BoxIoFuture<TcpRelayClientConnected> {
        let addr = self.addr.clone();
        let client_pair = (self.r, self.w);
        let fut = TcpRelayClientPending::connect_remote(self.handle, self.addr, self.forbidden_ip).map(|stream| {
            TcpRelayClientConnected {
                server: stream.split(),
                client: client_pair,
                addr: addr,
            }
        });
        Box::new(fut)
    }
}

/// Context for extablishing tunnel
pub struct TcpRelayClientConnected {
    server: (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
    client: (DecryptedHalf, EncryptedHalfFut),
    addr: Address,
}

impl TcpRelayClientConnected {
    /// Establish tunnel
    pub fn tunnel(self) -> BoxIoFuture<()> {
        let (svr_r, svr_w) = self.server;
        let (r, w_fut) = self.client;
        tunnel(self.addr,
               copy(r, svr_w),
               w_fut.and_then(|w| w.copy_from_encrypted(svr_r)))
    }
}

/// Runs the server
pub fn run(config: Rc<Config>, handle: Handle) -> Box<Future<Item = (), Error = io::Error>> {
    let mut fut: Option<Box<Future<Item = (), Error = io::Error>>> = None;

    let ref forbidden_ip = config.forbidden_ip;
    let forbidden_ip = Rc::new(forbidden_ip.clone());

    for svr_cfg in &config.server {
        let listener = {
            let addr = svr_cfg.addr();
            let addr = addr.listen_addr();

            let tcp_builder = match addr {
                    &SocketAddr::V4(..) => TcpBuilder::new_v4(),
                    &SocketAddr::V6(..) => TcpBuilder::new_v6(),
                }
                .unwrap_or_else(|err| panic!("Failed to create listener, {}", err));

            super::reuse_port(&tcp_builder)
                .and_then(|builder| builder.reuse_address(true))
                .and_then(|builder| builder.bind(addr))
                .unwrap_or_else(|err| panic!("Failed to bind {}, {}", addr, err));

            let listener = tcp_builder.listen(1024)
                .and_then(|l| TcpListener::from_listener(l, addr, &handle))
                .unwrap_or_else(|err| panic!("Failed to listen, {}", err));

            info!("ShadowSocks TCP Listening on {}", addr);
            listener
        };

        let svr_cfg = Rc::new(svr_cfg.clone());
        let handle = handle.clone();
        let forbidden_ip = forbidden_ip.clone();
        let listening = listener.incoming()
            .for_each(move |(socket, addr)| {
                let server_cfg = svr_cfg.clone();
                let forbidden_ip = forbidden_ip.clone();

                trace!("Got connection, addr: {}", addr);
                trace!("Picked proxy server: {:?}", server_cfg);

                let client = TcpRelayClientHandshake {
                    handle: handle.clone(),
                    s: socket,
                    svr_cfg: server_cfg,
                    forbidden_ip: forbidden_ip,
                };

                let fut = client.handshake()
                    .and_then(|c| c.connect())
                    .and_then(|c| c.tunnel())
                    .map_err(move |err| {
                        error!("Failed to handle client ({}): {}", addr, err);
                    });

                handle.spawn(fut);
                Ok(())
            })
            .map_err(|err| {
                error!("Server run failed: {}", err);
                err
            });

        fut = Some(match fut.take() {
            Some(fut) => Box::new(fut.join(listening).map(|_| ())) as Box<Future<Item = (), Error = io::Error>>,
            None => Box::new(listening) as Box<Future<Item = (), Error = io::Error>>,
        })
    }

    fut.expect("Must have at least one server")
}
<commit_msg>better error message<commit_after>// The MIT License (MIT)

// Copyright (c) 2014 Y. T. CHUNG <zonyitoo@gmail.com>

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! TcpRelay server that running on the server side

use std::io;
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::rc::Rc;
use std::collections::HashSet;

use config::{Config, ServerConfig};

use relay::socks5::Address;
use relay::{BoxIoFuture, boxed_future};
use relay::dns_resolver::DnsResolver;

use futures::{self, Future};
use futures::stream::Stream;

use tokio_core::reactor::Handle;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::io::{Io, ReadHalf, WriteHalf};
use tokio_core::io::copy;

use net2::TcpBuilder;

use ip::IpAddr;

use super::{tunnel, proxy_handshake, DecryptedHalf, EncryptedHalfFut};

/// Context for doing handshake with client
pub struct TcpRelayClientHandshake {
    handle: Handle,
    s: TcpStream,
    svr_cfg: Rc<ServerConfig>,
    forbidden_ip: Rc<HashSet<IpAddr>>,
}

impl TcpRelayClientHandshake {
    /// Doing handshake with client
    pub fn handshake(self) -> BoxIoFuture<TcpRelayClientPending> {
        let TcpRelayClientHandshake { handle, forbidden_ip, s, svr_cfg } = self;

        let fut = proxy_handshake(s, svr_cfg).and_then(|(r_fut, w_fut)| {
            r_fut.and_then(|r| {
                    Address::read_from(r).map_err(|_| {
                        io::Error::new(io::ErrorKind::Other,
                                       "failed to decode Address, may be wrong method or key")
                    })
                })
                .map(move |(r, addr)| {
                    TcpRelayClientPending {
                        handle: handle,
                        r: r,
                        addr: addr,
                        w: w_fut,
                        forbidden_ip: forbidden_ip,
                    }
                })
        });
        boxed_future(fut)
    }
}

/// Context for connecting remote
pub struct TcpRelayClientPending {
    handle: Handle,
    r: DecryptedHalf,
    addr: Address,
    w: EncryptedHalfFut,
    forbidden_ip: Rc<HashSet<IpAddr>>,
}

impl TcpRelayClientPending {
    /// Resolve Address to SocketAddr
    fn resolve_address(addr: Address) -> BoxIoFuture<SocketAddr> {
        match addr {
            Address::SocketAddress(addr) => Box::new(futures::finished(addr)),
            Address::DomainNameAddress(dname, port) => {
                let fut = DnsResolver::resolve(&dname[..]).and_then(move |ipaddr| {
                    Ok(match ipaddr {
                        IpAddr::V4(v4) => SocketAddr::V4(SocketAddrV4::new(v4, port)),
                        IpAddr::V6(v6) => SocketAddr::V6(SocketAddrV6::new(v6, port, 0, 0)),
                    })
                });
                Box::new(fut)
            }
        }
    }

    /// Resolve remote address to SocketAddr
    /// Report failure if the SocketAddr is forbidden by `forbidden_ip`
    fn resolve_remote(addr: Address, forbidden_ip: Rc<HashSet<IpAddr>>) -> BoxIoFuture<SocketAddr> {
        let fut = TcpRelayClientPending::resolve_address(addr).and_then(move |addr| {
            trace!("Resolved address as {}", addr);
            let ipaddr = match addr.clone() {
                SocketAddr::V4(v4) => IpAddr::V4(v4.ip().clone()),
                SocketAddr::V6(v6) => IpAddr::V6(v6.ip().clone()),
            };

            if forbidden_ip.contains(&ipaddr) {
                info!("{} has been forbidden", ipaddr);
                let err = io::Error::new(io::ErrorKind::Other, "Forbidden IP");
                Err(err)
            } else {
                Ok(addr)
            }
        });
        Box::new(fut)
    }

    /// Connect to the remote server
    fn connect_remote(handle: Handle, addr: Address, forbidden_ip: Rc<HashSet<IpAddr>>) -> BoxIoFuture<TcpStream> {
        info!("Connecting to remote {}", addr);
        Box::new(TcpRelayClientPending::resolve_remote(addr, forbidden_ip)
            .and_then(move |addr| TcpStream::connect(&addr, &handle)))
    }

    /// Connect to the remote server
    pub fn connect(self) -> BoxIoFuture<TcpRelayClientConnected> {
        let addr = self.addr.clone();
        let client_pair = (self.r, self.w);
        let fut = TcpRelayClientPending::connect_remote(self.handle, self.addr, self.forbidden_ip).map(|stream| {
            TcpRelayClientConnected {
                server: stream.split(),
                client: client_pair,
                addr: addr,
            }
        });
        Box::new(fut)
    }
}

/// Context for extablishing tunnel
pub struct TcpRelayClientConnected {
    server: (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
    client: (DecryptedHalf, EncryptedHalfFut),
    addr: Address,
}

impl TcpRelayClientConnected {
    /// Establish tunnel
    pub fn tunnel(self) -> BoxIoFuture<()> {
        let (svr_r, svr_w) = self.server;
        let (r, w_fut) = self.client;
        tunnel(self.addr,
               copy(r, svr_w),
               w_fut.and_then(|w| w.copy_from_encrypted(svr_r)))
    }
}

/// Runs the server
pub fn run(config: Rc<Config>, handle: Handle) -> Box<Future<Item = (), Error = io::Error>> {
    let mut fut: Option<Box<Future<Item = (), Error = io::Error>>> = None;

    let ref forbidden_ip = config.forbidden_ip;
    let forbidden_ip = Rc::new(forbidden_ip.clone());

    for svr_cfg in &config.server {
        let listener = {
            let addr = svr_cfg.addr();
            let addr = addr.listen_addr();

            let tcp_builder = match addr {
                    &SocketAddr::V4(..) => TcpBuilder::new_v4(),
                    &SocketAddr::V6(..) => TcpBuilder::new_v6(),
                }
                .unwrap_or_else(|err| panic!("Failed to create listener, {}", err));

            super::reuse_port(&tcp_builder)
                .and_then(|builder| builder.reuse_address(true))
                .and_then(|builder| builder.bind(addr))
                .unwrap_or_else(|err| panic!("Failed to bind {}, {}", addr, err));

            let listener = tcp_builder.listen(1024)
                .and_then(|l| TcpListener::from_listener(l, addr, &handle))
                .unwrap_or_else(|err| panic!("Failed to listen, {}", err));

            info!("ShadowSocks TCP Listening on {}", addr);
            listener
        };

        let svr_cfg = Rc::new(svr_cfg.clone());
        let handle = handle.clone();
        let forbidden_ip = forbidden_ip.clone();
        let listening = listener.incoming()
            .for_each(move |(socket, addr)| {
                let server_cfg = svr_cfg.clone();
                let forbidden_ip = forbidden_ip.clone();

                trace!("Got connection, addr: {}", addr);
                trace!("Picked proxy server: {:?}", server_cfg);

                let client = TcpRelayClientHandshake {
                    handle: handle.clone(),
                    s: socket,
                    svr_cfg: server_cfg,
                    forbidden_ip: forbidden_ip,
                };

                let fut = client.handshake()
                    .and_then(|c| c.connect())
                    .and_then(|c| c.tunnel())
                    .map_err(move |err| {
                        error!("Failed to handle client ({}): {}", addr, err);
                    });

                handle.spawn(fut);
                Ok(())
            })
            .map_err(|err| {
                error!("Server run failed: {}", err);
                err
            });

        fut = Some(match fut.take() {
            Some(fut) => Box::new(fut.join(listening).map(|_| ())) as Box<Future<Item = (), Error = io::Error>>,
            None => Box::new(listening) as Box<Future<Item = (), Error = io::Error>>,
        })
    }

    fut.expect("Must have at least one server")
}
<|endoftext|>