<commit_before>/// The Toml Read extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueReadExt<'doc> {

    /// Extension function for reading a value from the current toml::Value document
    /// using a custom seperator
    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>>;

    /// Extension function for reading a value from the current toml::Value document mutably
    /// using a custom seperator
    fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>>;

    /// Extension function for reading a value from the current toml::Value document
    fn read(&'doc self, query: &str) -> Result<Option<&'doc Value>> {
        self.read_with_seperator(query, '.')
    }

    /// Extension function for reading a value from the current toml::Value document mutably
    fn read_mut(&'doc mut self, query: &str) -> Result<Option<&'doc mut Value>> {
        self.read_mut_with_seperator(query, '.')
    }

}

impl<'doc> TomlValueReadExt<'doc> for Value {

    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>> {
        use resolver::non_mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

    fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>> {
        use resolver::mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

}

pub trait TomlValueReadTypeExt<'doc> {
    fn read_string(&'doc self, query: &str) -> Result<String>;
    fn read_int(&'doc self, query: &str) -> Result<i64>;
    fn read_float(&'doc self, query: &str) -> Result<f64>;
    fn read_bool(&'doc self, query: &str) -> Result<bool>;
}

macro_rules! make_type_getter {
    ($fnname:ident, $type:ty, $typename:expr, $matcher:pat => $impl:expr) => {
        fn $fnname(&'doc self, query: &str) -> Result<$type> {
            self.read_with_seperator(query, '.').and_then(|o| match o {
                $matcher => $impl,
                Some(o)  => Err(ErrorKind::TypeError($typename, ::util::name_of_val(&o)).into()),
                None     => Err(ErrorKind::NotAvailable(String::from(query)).into()),
            })
        }
    };
}

impl<'doc, T> TomlValueReadTypeExt<'doc> for T
    where T: TomlValueReadExt<'doc>
{
    make_type_getter!(read_string, String, "String",
                      Some(&Value::String(ref obj)) => Ok(obj.clone()));

    make_type_getter!(read_int, i64, "Integer",
                      Some(&Value::Integer(obj)) => Ok(obj));

    make_type_getter!(read_float, f64, "Float",
                      Some(&Value::Float(obj)) => Ok(obj));

    make_type_getter!(read_bool, bool, "Boolean",
                      Some(&Value::Boolean(obj)) => Ok(obj));
}

#[cfg(test)]
mod test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_empty() {
        let toml : Value = toml_from_str("").unwrap();

        let val  = toml.read_with_seperator(&String::from("a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            &Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.a"), '.');
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.[0]"), '.');
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
    }

    ///
    ///
    /// Querying without specifying the seperator
    ///
    ///

    #[test]
    fn test_read_empty_without_seperator() {
        let toml : Value = toml_from_str("").unwrap();

        let val  = toml.read(&String::from("a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            &Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read(&String::from("table.a"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table.a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table.[0]"));
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
    }

}

#[cfg(test)]
mod high_level_fn_test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read_int(&String::from("table.a"));

        assert!(val.is_ok());
        assert_eq!(val.unwrap(), 1);
    }

}

<commit_msg>Change variable names to be compatible with older rustc versions<commit_after>/// The Toml Read extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueReadExt<'doc> {

    /// Extension function for reading a value from the current toml::Value document
    /// using a custom seperator
    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>>;

    /// Extension function for reading a value from the current toml::Value document mutably
    /// using a custom seperator
    fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>>;

    /// Extension function for reading a value from the current toml::Value document
    fn read(&'doc self, query: &str) -> Result<Option<&'doc Value>> {
        self.read_with_seperator(query, '.')
    }

    /// Extension function for reading a value from the current toml::Value document mutably
    fn read_mut(&'doc mut self, query: &str) -> Result<Option<&'doc mut Value>> {
        self.read_mut_with_seperator(query, '.')
    }

}

impl<'doc> TomlValueReadExt<'doc> for Value {

    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>> {
        use resolver::non_mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

    fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>> {
        use resolver::mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

}

pub trait TomlValueReadTypeExt<'doc> {
    fn read_string(&'doc self, query: &str) -> Result<String>;
    fn read_int(&'doc self, query: &str) -> Result<i64>;
    fn read_float(&'doc self, query: &str) -> Result<f64>;
    fn read_bool(&'doc self, query: &str) -> Result<bool>;
}

macro_rules! make_type_getter {
    ($fnname:ident, $rettype:ty, $typename:expr, $matcher:pat => $implementation:expr) => {
        fn $fnname(&'doc self, query: &str) -> Result<$rettype> {
            self.read_with_seperator(query, '.').and_then(|o| match o {
                $matcher => $implementation,
                Some(o)  => Err(ErrorKind::TypeError($typename, ::util::name_of_val(&o)).into()),
                None     => Err(ErrorKind::NotAvailable(String::from(query)).into()),
            })
        }
    };
}

impl<'doc, T> TomlValueReadTypeExt<'doc> for T
    where T: TomlValueReadExt<'doc>
{
    make_type_getter!(read_string, String, "String",
                      Some(&Value::String(ref obj)) => Ok(obj.clone()));

    make_type_getter!(read_int, i64, "Integer",
                      Some(&Value::Integer(obj)) => Ok(obj));

    make_type_getter!(read_float, f64, "Float",
                      Some(&Value::Float(obj)) => Ok(obj));

    make_type_getter!(read_bool, bool, "Boolean",
                      Some(&Value::Boolean(obj)) => Ok(obj));
}

#[cfg(test)]
mod test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_empty() {
        let toml : Value = toml_from_str("").unwrap();

        let val  = toml.read_with_seperator(&String::from("a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            &Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.a"), '.');
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.[0]"), '.');
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
    }

    ///
    ///
    /// Querying without specifying the seperator
    ///
    ///

    #[test]
    fn test_read_empty_without_seperator() {
        let toml : Value = toml_from_str("").unwrap();

        let val  = toml.read(&String::from("a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            &Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read(&String::from("table.a"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table.a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table.[0]"));
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
    }

}

#[cfg(test)]
mod high_level_fn_test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read_int(&String::from("table.a"));

        assert!(val.is_ok());
        assert_eq!(val.unwrap(), 1);
    }

}

<|endoftext|>


<commit_before>use direction::{Direction, NUM_DIRECTIONS};

#[derive(Debug, Copy, Clone)]
pub struct Room<T: Copy, C: Copy> {
  exits: [Option<T>; NUM_DIRECTIONS],
  pub name: &'static str,
  pub description: &'static str,
  pub contents: Option<C>,
}

impl<T: Copy, C: Copy> Room<T, C> {
  pub fn new() -> Self {
    Self {
      exits: [None; NUM_DIRECTIONS],
      name: "",
      description: "",
      contents: None,
    }
  }

  pub fn get_exit(self, d: Direction) -> Option<T> {
    self.exits[d as usize]
  }

  pub fn set_exit(&mut self, d: Direction, r: T) -> &mut Self {
    assert!(self.exits[d as usize].is_none());
    self.exits[d as usize] = Some(r);
    self
  }

  pub fn describe(&mut self, name: &'static str, desc: &'static str) -> &mut Self {
    self.name = name;
    self.description = desc;
    self
  }
}
<commit_msg>Assert that describe() is only called on rooms that don't yet have a name.<commit_after>use direction::{Direction, NUM_DIRECTIONS};

#[derive(Debug, Copy, Clone)]
pub struct Room<T: Copy, C: Copy> {
  exits: [Option<T>; NUM_DIRECTIONS],
  pub name: &'static str,
  pub description: &'static str,
  pub contents: Option<C>,
}

impl<T: Copy, C: Copy> Room<T, C> {
  pub fn new() -> Self {
    Self {
      exits: [None; NUM_DIRECTIONS],
      name: "",
      description: "",
      contents: None,
    }
  }

  pub fn get_exit(self, d: Direction) -> Option<T> {
    self.exits[d as usize]
  }

  pub fn set_exit(&mut self, d: Direction, r: T) -> &mut Self {
    assert!(self.exits[d as usize].is_none());
    self.exits[d as usize] = Some(r);
    self
  }

  pub fn describe(&mut self, name: &'static str, desc: &'static str) -> &mut Self {
    assert_eq!(self.name, "");
    self.name = name;
    self.description = desc;
    self
  }
}
<|endoftext|>


<commit_before>fn hex_string_to_bytes(hex_str: &str) -> Option<Vec<u8>> {
    let mut bytes: Vec<u8> = Vec::new();
    let mut byte = 0u8;

    for (i, b) in hex_str.chars().enumerate() {
        match b.to_digit(16) {
            Some(n) => byte += (n << (4 * (1 - (i % 2)))) as u8,
            None => return None,
        }

        if i % 2 == 1 || i == hex_str.len() - 1 {
            bytes.push(byte);
            byte = 0;
        }
    }

    Some(bytes)
}

fn hex_to_base64(hex_str: &str) -> String {
    let bytes = hex_string_to_bytes(hex_str).unwrap();

}

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

    #[test]
    fn test_hex_string_to_bytes() {
        assert_eq!(vec![1u8], hex_string_to_bytes("01").unwrap());
        assert_eq!(None, hex_string_to_bytes("x"));
        assert_eq!(vec![255u8, 220u8, 15u8], hex_string_to_bytes("ffdc0f").unwrap());
    }

}
<commit_msg>Implement challenge 1: hex to base64<commit_after>use std::collections::HashMap;

fn hex_string_to_bytes(hex_str: &str) -> Option<Vec<u8>> {
    let mut bytes: Vec<u8> = Vec::new();
    let mut byte = 0u8;

    let data = if hex_str.len() % 2 == 0 {
        hex_str.to_string()
    } else {
        "0".to_string() + &hex_str
    };

    for (i, b) in data.chars().enumerate() {
        match b.to_digit(16) {
            Some(n) => byte += if i % 2 == 0 {
                n << 4
            } else {
                n
            } as u8,
            None => return None,
        }

        if i % 2 == 1 {
            bytes.push(byte);
            byte = 0;
        }
    }

    Some(bytes)
}

// there has to be a better way to do this
fn base64_keys() -> HashMap<u8, char> {
    (('A' as u8)..('Z' as u8 + 1))
        .chain(('a' as u8)..('z' as u8 + 1))
        .chain(('0' as u8)..('9' as u8 + 1))
        .chain(('+' as u8)..('+' as u8 + 1))
        .chain(('/' as u8)..('/' as u8 + 1))
        .enumerate()
        .map(|(k, v)| (k as u8, v as char))
        .collect()
}

fn triplet_to_base64(triplet: &mut u32) -> Vec<char> {
    let keys = base64_keys();
    let mut chars: Vec<char> = Vec::new();

    // haha who likes readable code anyway xd
    while *triplet & 0xffffff != 0u32 {
        chars.push(keys.get(&(((*triplet >> 18) & 0x3f) as u8)).unwrap().clone());
        *triplet <<= 6;
    }

    chars
}

pub fn hex_to_base64(hex_str: &str) -> String {
    let bytes = hex_string_to_bytes(hex_str).unwrap();
    let mut chars: Vec<char> = Vec::new();

    let mut triplet = 0u32;

    for i in 0..bytes.len() {
        triplet = (triplet << 8) + bytes.get(i).unwrap().clone() as u32;

        if i % 3 == 2 {
            for c in triplet_to_base64(&mut triplet).iter() {
                chars.push(c.clone());
            }
        }
    }

    for c in triplet_to_base64(&mut triplet).iter() {
        chars.push(c.clone());
    }

    chars.into_iter().collect()
}

#[cfg(test)]
mod test {
    use super::{hex_string_to_bytes, hex_to_base64};

    #[test]
    fn test_hex_string_to_bytes() {
        assert_eq!(vec![1u8], hex_string_to_bytes("01").unwrap());
        assert_eq!(vec![12u8], hex_string_to_bytes("c").unwrap());
        assert_eq!(None, hex_string_to_bytes("x"));
        assert_eq!(vec![255u8, 220u8, 15u8], hex_string_to_bytes("ffdc0f").unwrap());
    }

    #[test]
    fn test_hex_to_base64() {
        let input = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
        let expected = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t".to_string();
        assert_eq!(expected, hex_to_base64(input));
    }
}
<|endoftext|>


<commit_before>use std;
use std::ops::Add;
use std::io::{self, Write, Read};
use time::{self, Timespec, Duration};
use tty::{Width, Height, terminal_size};

macro_rules! printfl {
    ($($tt:tt)*) => {{
        use std::io::{self, Write};
        print!($($tt)*);
        io::stdout().flush().ok().expect("flush() fail");
    }}
}

macro_rules! kb_fmt {
    ($n: ident) => {{
        let kb = 1024f64;
        match $n {
            $n if $n > kb.powf(4_f64) => format!("{:.*} TG", 2, $n / kb.powf(4_f64)),
            $n if $n > kb.powf(3_f64) => format!("{:.*} GB", 2, $n / kb.powf(3_f64)),
            $n if $n > kb => format!("{:.*} KB", 2, $n / kb),
            _ => format!("{:.*} B", 0, $n)
        }
    }}
}

macro_rules! repeat {
    ($s: expr, $n: expr) => {{
        &std::iter::repeat($s).take($n).collect::<String>()
    }}
}

static FORMAT: &'static str = "[=>-]";

// Output type format, indicate which format wil be used in
// the speed box.
#[derive(Debug)]
pub enum Units {
    Default,
    Bytes,
}

#[derive(Debug)]
pub struct ProgressBar {
    start_time: Timespec,
    units: Units,
    total: usize,
    current: usize,
    is_finish: bool,
    show_bar: bool,
    show_speed: bool,
    show_percent: bool,
    show_counter: bool,
    show_time_left: bool,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_remain: String,
    bar_end: String,
}

impl ProgressBar {
    /// Create a new ProgressBar with default configuration.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use std::thread;
    /// use pb::{ProgressBar, Units};
    ///
    /// let count = 1000;
    /// let mut pb = ProgressBar::new(count);
    /// pb.set_units(Units::Bytes);
    ///
    /// for _ in 0..count {
    ///    pb.inc();
    ///    thread::sleep_ms(100);
    /// }
    /// ```
    pub fn new(total: usize) -> ProgressBar {
        let mut pb = ProgressBar {
            total: total,
            current: 0,
            start_time: time::get_time(),
            units: Units::Default,
            is_finish: false,
            show_bar: true,
            show_speed: false,
            show_percent: true,
            show_counter: true,
            show_time_left: true,
            bar_start: String::new(),
            bar_current: String::new(),
            bar_current_n: String::new(),
            bar_remain: String::new(),
            bar_end: String::new(),
        };
        pb.format(FORMAT);
        pb
    }

    /// set units, default is simple numbers
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use pb::{ProgressBar, Units};
    ///
    /// let mut pb = ProgressBar::new(n_bytes);
    /// pb.set_units(Units::Bytes);
    /// ```
    pub fn set_units(&mut self, u: Units) {
        self.units = u;
    }

    /// Set custom format to the drawing bar, default is "[=>-]"
    ///
    /// # Examples
    ///
    /// ```no_run
    /// pb.format("[=>_]")
    /// ```
    pub fn format(&mut self, fmt: &str) {
        if fmt.len() >= 5 {
            let v: Vec<&str> = fmt.split("").collect();
            self.bar_start = v[1].to_string();
            self.bar_current = v[2].to_string();
            self.bar_current_n = v[3].to_string();
            self.bar_remain = v[4].to_string();
            self.bar_end = v[5].to_string();
        }
    }

    /// Add to current value
    pub fn add(&mut self, i: usize) -> usize {
        self.current += i;
        if self.current <= self.total {
            self.draw()
        };
        self.current
    }

    /// Increment current value
    pub fn inc(&mut self) -> usize {
        return self.add(1);
    }

    fn draw(&self) {
        let tty_size = terminal_size();
        let width = if let Some((Width(w), _)) = tty_size {
            w as usize
        } else {
            80
        };
        let mut base = String::new();
        let mut suffix = String::new();
        let mut prefix = String::new();
        let mut out;
        // precent box
        if self.show_percent {
            let percent = self.current as f64 / (self.total as f64 / 100f64);
            suffix = suffix + &format!(" {:.*} % ", 2, percent);
        }
        // speed box
        if !self.show_speed {
            let from_start = (time::get_time() - self.start_time).num_nanoseconds().unwrap() as f64;
            let sec_nano = Duration::seconds(1).num_nanoseconds().unwrap() as f64;
            let speed = self.current as f64 / (from_start / sec_nano);
            suffix = match self.units {
                Units::Default => suffix + &format!("{}/s ", speed),
                Units::Bytes => suffix + &format!("{}/s ", kb_fmt!(speed)),
            };
        }
        // time left box
        if self.show_time_left {
            let from_start = time::get_time() - self.start_time;
            let sec_nano = Duration::seconds(1).num_nanoseconds().unwrap() as i32;
            let per_entry = from_start / self.current as i32;
            let mut left = per_entry * (self.total - self.current) as i32;
            left = (left / sec_nano) * sec_nano;
            if left.num_seconds() > 0 {
                if left.num_seconds() < Duration::minutes(1).num_seconds() {
                    suffix = suffix + &format!("{}s", left.num_seconds());
                } else {
                    suffix = suffix + &format!("{}m", left.num_minutes());
                }
            }
        }
        // counter box
        if self.show_counter {
            let (c, t) = (self.current as f64, self.total as f64);
            prefix = match self.units {
                Units::Default => format!("{} / {} ", c, t),
                Units::Bytes => format!("{} / {} ", kb_fmt!(c), kb_fmt!(t)),
            };
        }
        // bar box
        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let curr_count =
                    ((self.current as f64 / self.total as f64) * size as f64).ceil() as usize;
                let rema_count = size - curr_count;
                base = self.bar_start.to_string();
                if rema_count > 0 {
                    base = base + repeat!(self.bar_current.as_ref(), curr_count - 1) +
                           &self.bar_current_n;
                } else {
                    base = base + repeat!(self.bar_current.as_ref(), curr_count);
                }
                base = base + repeat!(self.bar_remain.as_ref(), rema_count) + &self.bar_end;
            }
        }
        out = prefix + &base + &suffix;
        // pad
        if out.len() < width {
            let gap = width - out.len();
            out = out + repeat!(" ", gap);
        }
        // print
        printfl!("\r{}", out);
    }

    /// Calling finish manually will set current to total and draw
    /// the last time
    pub fn finish(&mut self) {
        if self.current < self.total {
            self.current = self.total;
            self.draw();
        }
        println!("");
        self.is_finish = true;
    }
}

// Implement io::Writer
impl Write for ProgressBar {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = buf.len();
        self.add(n);
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

<commit_msg>test(pb): add pb basic tests<commit_after>use std::iter::{repeat};
use std::io::{self, Write};
use time::{self, Timespec, Duration};
use tty::{Width, terminal_size};

macro_rules! printfl {
    ($($tt:tt)*) => {{
        print!($($tt)*);
        io::stdout().flush().ok().expect("flush() fail");
    }}
}

macro_rules! kb_fmt {
    ($n: ident) => {{
        let kb = 1024f64;
        match $n {
            $n if $n > kb.powf(4_f64) => format!("{:.*} TG", 2, $n / kb.powf(4_f64)),
            $n if $n > kb.powf(3_f64) => format!("{:.*} GB", 2, $n / kb.powf(3_f64)),
            $n if $n > kb => format!("{:.*} KB", 2, $n / kb),
            _ => format!("{:.*} B", 0, $n)
        }
    }}
}

macro_rules! repeat {
    ($s: expr, $n: expr) => {{
        &repeat($s).take($n).collect::<String>()
    }}
}

static FORMAT: &'static str = "[=>-]";

// Output type format, indicate which format wil be used in
// the speed box.
#[derive(Debug)]
pub enum Units {
    Default,
    Bytes,
}

#[derive(Debug)]
pub struct ProgressBar {
    start_time: Timespec,
    units: Units,
    total: usize,
    current: usize,
    is_finish: bool,
    show_bar: bool,
    show_speed: bool,
    show_percent: bool,
    show_counter: bool,
    show_time_left: bool,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_remain: String,
    bar_end: String,
}

impl ProgressBar {
    /// Create a new ProgressBar with default configuration.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use std::thread;
    /// use pb::{ProgressBar, Units};
    ///
    /// let count = 1000;
    /// let mut pb = ProgressBar::new(count);
    /// pb.set_units(Units::Bytes);
    ///
    /// for _ in 0..count {
    ///    pb.inc();
    ///    thread::sleep_ms(100);
    /// }
    /// ```
    pub fn new(total: usize) -> ProgressBar {
        let mut pb = ProgressBar {
            total: total,
            current: 0,
            start_time: time::get_time(),
            units: Units::Default,
            is_finish: false,
            show_bar: true,
            show_speed: false,
            show_percent: true,
            show_counter: true,
            show_time_left: true,
            bar_start: String::new(),
            bar_current: String::new(),
            bar_current_n: String::new(),
            bar_remain: String::new(),
            bar_end: String::new(),
        };
        pb.format(FORMAT);
        pb
    }

    /// set units, default is simple numbers
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use pb::{ProgressBar, Units};
    ///
    /// let mut pb = ProgressBar::new(n_bytes);
    /// pb.set_units(Units::Bytes);
    /// ```
    pub fn set_units(&mut self, u: Units) {
        self.units = u;
    }

    /// Set custom format to the drawing bar, default is "[=>-]"
    ///
    /// # Examples
    ///
    /// ```no_run
    /// pb.format("[=>_]")
    /// ```
    pub fn format(&mut self, fmt: &str) {
        if fmt.len() >= 5 {
            let v: Vec<&str> = fmt.split("").collect();
            self.bar_start = v[1].to_string();
            self.bar_current = v[2].to_string();
            self.bar_current_n = v[3].to_string();
            self.bar_remain = v[4].to_string();
            self.bar_end = v[5].to_string();
        }
    }

    /// Add to current value
    pub fn add(&mut self, i: usize) -> usize {
        self.current += i;
        if self.current <= self.total {
            self.draw()
        };
        self.current
    }

    /// Increment current value
    pub fn inc(&mut self) -> usize {
        return self.add(1);
    }

    fn draw(&self) {
        let tty_size = terminal_size();
        let width = if let Some((Width(w), _)) = tty_size {
            w as usize
        } else {
            80
        };
        let mut base = String::new();
        let mut suffix = String::new();
        let mut prefix = String::new();
        let mut out;
        // precent box
        if self.show_percent {
            let percent = self.current as f64 / (self.total as f64 / 100f64);
            suffix = suffix + &format!(" {:.*} % ", 2, percent);
        }
        // speed box
        if !self.show_speed {
            let from_start = (time::get_time() - self.start_time).num_nanoseconds().unwrap() as f64;
            let sec_nano = Duration::seconds(1).num_nanoseconds().unwrap() as f64;
            let speed = self.current as f64 / (from_start / sec_nano);
            suffix = match self.units {
                Units::Default => suffix + &format!("{}/s ", speed),
                Units::Bytes => suffix + &format!("{}/s ", kb_fmt!(speed)),
            };
        }
        // time left box
        if self.show_time_left {
            let from_start = time::get_time() - self.start_time;
            let sec_nano = Duration::seconds(1).num_nanoseconds().unwrap() as i32;
            let per_entry = from_start / self.current as i32;
            let mut left = per_entry * (self.total - self.current) as i32;
            left = (left / sec_nano) * sec_nano;
            if left.num_seconds() > 0 {
                if left.num_seconds() < Duration::minutes(1).num_seconds() {
                    suffix = suffix + &format!("{}s", left.num_seconds());
                } else {
                    suffix = suffix + &format!("{}m", left.num_minutes());
                }
            }
        }
        // counter box
        if self.show_counter {
            let (c, t) = (self.current as f64, self.total as f64);
            prefix = match self.units {
                Units::Default => format!("{} / {} ", c, t),
                Units::Bytes => format!("{} / {} ", kb_fmt!(c), kb_fmt!(t)),
            };
        }
        // bar box
        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let curr_count =
                    ((self.current as f64 / self.total as f64) * size as f64).ceil() as usize;
                let rema_count = size - curr_count;
                base = self.bar_start.to_string();
                if rema_count > 0 {
                    base = base + repeat!(self.bar_current.as_ref(), curr_count - 1) +
                           &self.bar_current_n;
                } else {
                    base = base + repeat!(self.bar_current.as_ref(), curr_count);
                }
                base = base + repeat!(self.bar_remain.as_ref(), rema_count) + &self.bar_end;
            }
        }
        out = prefix + &base + &suffix;
        // pad
        if out.len() < width {
            let gap = width - out.len();
            out = out + repeat!(" ", gap);
        }
        // print
        printfl!("\r{}", out);
    }

    /// Calling finish manually will set current to total and draw
    /// the last time
    pub fn finish(&mut self) {
        if self.current < self.total {
            self.current = self.total;
            self.draw();
        }
        println!("");
        self.is_finish = true;
    }
}

// Implement io::Writer
impl Write for ProgressBar {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = buf.len();
        self.add(n);
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use pb::{ProgressBar};

    #[test]
    fn add() {
        let mut pb = ProgressBar::new(10);
        pb.add(2);
        assert!(pb.current == 2, "should add the given `n` to current");
        assert!(pb.add(2) == pb.current, "add should return the current value");
    }

    #[test]
    fn inc() {
        let mut pb = ProgressBar::new(10);
        pb.inc();
        assert!(pb.current == 1, "should increment current by 1");
    }

    #[test]
    fn format() {
        let FORMAT = "[~> ]";
        let mut pb = ProgressBar::new(1);
        pb.format(FORMAT);
        assert!(pb.bar_start + &pb.bar_current + &pb.bar_current_n + &pb.bar_remain + &pb.bar_end == FORMAT);
    }
}
<|endoftext|>


<commit_before>extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap,MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: u32 = 0x20000000;
pub const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4 * 1024);

#[allow(dead_code)]
pub struct Bcm2835Peripheral {
    pub addr_p: *const u8,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut u32
}

impl Bcm2835Peripheral {
    pub fn map_peripheral( & mut self) {
        self.mem_fd = OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = & [
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            // MapOption::MapAddr(self.addr_p),
            MapOption::MapFd(self.mem_fd.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
        self.map = mmap;
        self.addr = self.map.data() as *mut u32;
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= (7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: u32) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<commit_msg>silence warnings for dead code<commit_after>#![allow(dead_code)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: u32 = 0x20000000;
pub const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4 * 1024);

pub struct Bcm2835Peripheral {
    pub addr_p: *const u8,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut u32
}

impl Bcm2835Peripheral {
    pub fn map_peripheral( & mut self) {
        self.mem_fd = OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = & [
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            // MapOption::MapAddr(self.addr_p),
            MapOption::MapFd(self.mem_fd.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
        self.map = mmap;
        self.addr = self.map.data() as *mut u32;
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= 7 << (((y) % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: u32) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<|endoftext|>


<commit_before>use core::ops::Neg;
use core::num::Wrapping;

use Num;
use float::FloatCore;

/// Useful functions for signed numbers (i.e. numbers that can be negative).
pub trait Signed: Sized + Num + Neg<Output = Self> {
    /// Computes the absolute value.
    ///
    /// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`.
    ///
    /// For signed integers, `::MIN` will be returned if the number is `::MIN`.
    fn abs(&self) -> Self;

    /// The positive difference of two numbers.
    ///
    /// Returns `zero` if the number is less than or equal to `other`, otherwise the difference
    /// between `self` and `other` is returned.
    fn abs_sub(&self, other: &Self) -> Self;

    /// Returns the sign of the number.
    ///
    /// For `f32` and `f64`:
    ///
    /// * `1.0` if the number is positive, `+0.0` or `INFINITY`
    /// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
    /// * `NaN` if the number is `NaN`
    ///
    /// For signed integers:
    ///
    /// * `0` if the number is zero
    /// * `1` if the number is positive
    /// * `-1` if the number is negative
    fn signum(&self) -> Self;

    /// Returns true if the number is positive and false if the number is zero or negative.
    fn is_positive(&self) -> bool;

    /// Returns true if the number is negative and false if the number is zero or positive.
    fn is_negative(&self) -> bool;
}

macro_rules! signed_impl {
    ($($t:ty)*) => ($(
        impl Signed for $t {
            #[inline]
            fn abs(&self) -> $t {
                if self.is_negative() { -*self } else { *self }
            }

            #[inline]
            fn abs_sub(&self, other: &$t) -> $t {
                if *self <= *other { 0 } else { *self - *other }
            }

            #[inline]
            fn signum(&self) -> $t {
                match *self {
                    n if n > 0 => 1,
                    0 => 0,
                    _ => -1,
                }
            }

            #[inline]
            fn is_positive(&self) -> bool { *self > 0 }

            #[inline]
            fn is_negative(&self) -> bool { *self < 0 }
        }
    )*)
}

signed_impl!(isize i8 i16 i32 i64);

#[cfg(feature = "i128")]
signed_impl!(i128);

impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Wrapping<T>>
{
    #[inline]
    fn abs(&self) -> Self {
        Wrapping(self.0.abs())
    }

    #[inline]
    fn abs_sub(&self, other: &Self) -> Self {
        Wrapping(self.0.abs_sub(&other.0))
    }

    #[inline]
    fn signum(&self) -> Self {
        Wrapping(self.0.signum())
    }

    #[inline]
    fn is_positive(&self) -> bool { self.0.is_positive() }

    #[inline]
    fn is_negative(&self) -> bool { self.0.is_negative() }
}

macro_rules! signed_float_impl {
    ($t:ty) => {
        impl Signed for $t {
            /// Computes the absolute value. Returns `NAN` if the number is `NAN`.
            #[inline]
            fn abs(&self) -> $t {
                FloatCore::abs(*self)
            }

            /// The positive difference of two numbers. Returns `0.0` if the number is
            /// less than or equal to `other`, otherwise the difference between`self`
            /// and `other` is returned.
            #[inline]
            fn abs_sub(&self, other: &$t) -> $t {
                if *self <= *other { 0. } else { *self - *other }
            }

            /// # Returns
            ///
            /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
            /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
            /// - `NAN` if the number is NaN
            #[inline]
            fn signum(&self) -> $t {
                FloatCore::signum(*self)
            }

            /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
            #[inline]
            fn is_positive(&self) -> bool { FloatCore::is_sign_positive(*self) }

            /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
            #[inline]
            fn is_negative(&self) -> bool { FloatCore::is_sign_negative(*self) }
        }
    }
}

signed_float_impl!(f32);
signed_float_impl!(f64);

/// Computes the absolute value.
///
/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`
///
/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
#[inline(always)]
pub fn abs<T: Signed>(value: T) -> T {
    value.abs()
}

/// The positive difference of two numbers.
///
/// Returns zero if `x` is less than or equal to `y`, otherwise the difference
/// between `x` and `y` is returned.
#[inline(always)]
pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
    x.abs_sub(&y)
}

/// Returns the sign of the number.
///
/// For `f32` and `f64`:
///
/// * `1.0` if the number is positive, `+0.0` or `INFINITY`
/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// * `NaN` if the number is `NaN`
///
/// For signed integers:
///
/// * `0` if the number is zero
/// * `1` if the number is positive
/// * `-1` if the number is negative
#[inline(always)] pub fn signum<T: Signed>(value: T) -> T { value.signum() }

/// A trait for values which cannot be negative
pub trait Unsigned: Num {}

macro_rules! empty_trait_impl {
    ($name:ident for $($t:ty)*) => ($(
        impl $name for $t {}
    )*)
}

empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
#[cfg(feature = "i128")]
empty_trait_impl!(Unsigned for u128 i128);

impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}

#[test]
fn unsigned_wrapping_is_unsigned() {
    fn require_unsigned<T: Unsigned>(_: &T) {}
    require_unsigned(&Wrapping(42_u32));
}
/*
// Commenting this out since it doesn't compile on Rust 1.8,
// because on this version Wrapping doesn't implement Neg and therefore can't
// implement Signed.
#[test]
fn signed_wrapping_is_signed() {
    fn require_signed<T: Signed>(_: &T) {}
    require_signed(&Wrapping(-42));
}
*/
<commit_msg>i128 is not Unsigned<commit_after>use core::ops::Neg;
use core::num::Wrapping;

use Num;
use float::FloatCore;

/// Useful functions for signed numbers (i.e. numbers that can be negative).
pub trait Signed: Sized + Num + Neg<Output = Self> {
    /// Computes the absolute value.
    ///
    /// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`.
    ///
    /// For signed integers, `::MIN` will be returned if the number is `::MIN`.
    fn abs(&self) -> Self;

    /// The positive difference of two numbers.
    ///
    /// Returns `zero` if the number is less than or equal to `other`, otherwise the difference
    /// between `self` and `other` is returned.
    fn abs_sub(&self, other: &Self) -> Self;

    /// Returns the sign of the number.
    ///
    /// For `f32` and `f64`:
    ///
    /// * `1.0` if the number is positive, `+0.0` or `INFINITY`
    /// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
    /// * `NaN` if the number is `NaN`
    ///
    /// For signed integers:
    ///
    /// * `0` if the number is zero
    /// * `1` if the number is positive
    /// * `-1` if the number is negative
    fn signum(&self) -> Self;

    /// Returns true if the number is positive and false if the number is zero or negative.
    fn is_positive(&self) -> bool;

    /// Returns true if the number is negative and false if the number is zero or positive.
    fn is_negative(&self) -> bool;
}

macro_rules! signed_impl {
    ($($t:ty)*) => ($(
        impl Signed for $t {
            #[inline]
            fn abs(&self) -> $t {
                if self.is_negative() { -*self } else { *self }
            }

            #[inline]
            fn abs_sub(&self, other: &$t) -> $t {
                if *self <= *other { 0 } else { *self - *other }
            }

            #[inline]
            fn signum(&self) -> $t {
                match *self {
                    n if n > 0 => 1,
                    0 => 0,
                    _ => -1,
                }
            }

            #[inline]
            fn is_positive(&self) -> bool { *self > 0 }

            #[inline]
            fn is_negative(&self) -> bool { *self < 0 }
        }
    )*)
}

signed_impl!(isize i8 i16 i32 i64);

#[cfg(feature = "i128")]
signed_impl!(i128);

impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Wrapping<T>>
{
    #[inline]
    fn abs(&self) -> Self {
        Wrapping(self.0.abs())
    }

    #[inline]
    fn abs_sub(&self, other: &Self) -> Self {
        Wrapping(self.0.abs_sub(&other.0))
    }

    #[inline]
    fn signum(&self) -> Self {
        Wrapping(self.0.signum())
    }

    #[inline]
    fn is_positive(&self) -> bool { self.0.is_positive() }

    #[inline]
    fn is_negative(&self) -> bool { self.0.is_negative() }
}

macro_rules! signed_float_impl {
    ($t:ty) => {
        impl Signed for $t {
            /// Computes the absolute value. Returns `NAN` if the number is `NAN`.
            #[inline]
            fn abs(&self) -> $t {
                FloatCore::abs(*self)
            }

            /// The positive difference of two numbers. Returns `0.0` if the number is
            /// less than or equal to `other`, otherwise the difference between`self`
            /// and `other` is returned.
            #[inline]
            fn abs_sub(&self, other: &$t) -> $t {
                if *self <= *other { 0. } else { *self - *other }
            }

            /// # Returns
            ///
            /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
            /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
            /// - `NAN` if the number is NaN
            #[inline]
            fn signum(&self) -> $t {
                FloatCore::signum(*self)
            }

            /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
            #[inline]
            fn is_positive(&self) -> bool { FloatCore::is_sign_positive(*self) }

            /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
            #[inline]
            fn is_negative(&self) -> bool { FloatCore::is_sign_negative(*self) }
        }
    }
}

signed_float_impl!(f32);
signed_float_impl!(f64);

/// Computes the absolute value.
///
/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`
///
/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
#[inline(always)]
pub fn abs<T: Signed>(value: T) -> T {
    value.abs()
}

/// The positive difference of two numbers.
///
/// Returns zero if `x` is less than or equal to `y`, otherwise the difference
/// between `x` and `y` is returned.
#[inline(always)]
pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
    x.abs_sub(&y)
}

/// Returns the sign of the number.
///
/// For `f32` and `f64`:
///
/// * `1.0` if the number is positive, `+0.0` or `INFINITY`
/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// * `NaN` if the number is `NaN`
///
/// For signed integers:
///
/// * `0` if the number is zero
/// * `1` if the number is positive
/// * `-1` if the number is negative
#[inline(always)] pub fn signum<T: Signed>(value: T) -> T { value.signum() }

/// A trait for values which cannot be negative
pub trait Unsigned: Num {}

macro_rules! empty_trait_impl {
    ($name:ident for $($t:ty)*) => ($(
        impl $name for $t {}
    )*)
}

empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
#[cfg(feature = "i128")]
empty_trait_impl!(Unsigned for u128);

impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}

#[test]
fn unsigned_wrapping_is_unsigned() {
    fn require_unsigned<T: Unsigned>(_: &T) {}
    require_unsigned(&Wrapping(42_u32));
}
/*
// Commenting this out since it doesn't compile on Rust 1.8,
// because on this version Wrapping doesn't implement Neg and therefore can't
// implement Signed.
#[test]
fn signed_wrapping_is_signed() {
    fn require_signed<T: Signed>(_: &T) {}
    require_signed(&Wrapping(-42));
}
*/
<|endoftext|>


<commit_before>use crate::result::{ZipError, ZipResult};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io;
use std::io::prelude::*;

pub const LOCAL_FILE_HEADER_SIGNATURE: u32 = 0x04034b50;
pub const CENTRAL_DIRECTORY_HEADER_SIGNATURE: u32 = 0x02014b50;
const CENTRAL_DIRECTORY_END_SIGNATURE: u32 = 0x06054b50;
pub const ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE: u32 = 0x06064b50;
const ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE: u32 = 0x07064b50;

pub struct CentralDirectoryEnd {
    pub disk_number: u16,
    pub disk_with_central_directory: u16,
    pub number_of_files_on_this_disk: u16,
    pub number_of_files: u16,
    pub central_directory_size: u32,
    pub central_directory_offset: u32,
    pub zip_file_comment: Vec<u8>,
}

impl CentralDirectoryEnd {
    pub fn parse<T: Read>(reader: &mut T) -> ZipResult<CentralDirectoryEnd> {
        let magic = reader.read_u32::<LittleEndian>()?;
        if magic != CENTRAL_DIRECTORY_END_SIGNATURE {
            return Err(ZipError::InvalidArchive("Invalid digital signature header"));
        }
        let disk_number = reader.read_u16::<LittleEndian>()?;
        let disk_with_central_directory = reader.read_u16::<LittleEndian>()?;
        let number_of_files_on_this_disk = reader.read_u16::<LittleEndian>()?;
        let number_of_files = reader.read_u16::<LittleEndian>()?;
        let central_directory_size = reader.read_u32::<LittleEndian>()?;
        let central_directory_offset = reader.read_u32::<LittleEndian>()?;
        let zip_file_comment_length = reader.read_u16::<LittleEndian>()? as usize;
        let mut zip_file_comment = vec![0; zip_file_comment_length];
        reader.read_exact(&mut zip_file_comment)?;

        Ok(CentralDirectoryEnd {
            disk_number,
            disk_with_central_directory,
            number_of_files_on_this_disk,
            number_of_files,
            central_directory_size,
            central_directory_offset,
            zip_file_comment,
        })
    }

    pub fn find_and_parse<T: Read + io::Seek>(
        reader: &mut T,
    ) -> ZipResult<(CentralDirectoryEnd, u64)> {
        const HEADER_SIZE: u64 = 22;
        const BYTES_BETWEEN_MAGIC_AND_COMMENT_SIZE: u64 = HEADER_SIZE - 6;
        let file_length = reader.seek(io::SeekFrom::End(0))?;

        let search_upper_bound = file_length.saturating_sub(HEADER_SIZE + ::std::u16::MAX as u64);

        if file_length < HEADER_SIZE {
            return Err(ZipError::InvalidArchive("Invalid zip header"));
        }

        let mut pos = file_length - HEADER_SIZE;
        while pos >= search_upper_bound {
            reader.seek(io::SeekFrom::Start(pos as u64))?;
            if reader.read_u32::<LittleEndian>()? == CENTRAL_DIRECTORY_END_SIGNATURE {
                reader.seek(io::SeekFrom::Current(
                    BYTES_BETWEEN_MAGIC_AND_COMMENT_SIZE as i64,
                ))?;
                let comment_length = reader.read_u16::<LittleEndian>()? as u64;
                if file_length - pos - HEADER_SIZE == comment_length {
                    let cde_start_pos = reader.seek(io::SeekFrom::Start(pos as u64))?;
                    return CentralDirectoryEnd::parse(reader).map(|cde| (cde, cde_start_pos));
                }
            }
            pos = match pos.checked_sub(1) {
                Some(p) => p,
                None => break,
            };
        }
        Err(ZipError::InvalidArchive(
            "Could not find central directory end",
        ))
    }

    pub fn write<T: Write>(&self, writer: &mut T) -> ZipResult<()> {
        writer.write_u32::<LittleEndian>(CENTRAL_DIRECTORY_END_SIGNATURE)?;
        writer.write_u16::<LittleEndian>(self.disk_number)?;
        writer.write_u16::<LittleEndian>(self.disk_with_central_directory)?;
        writer.write_u16::<LittleEndian>(self.number_of_files_on_this_disk)?;
        writer.write_u16::<LittleEndian>(self.number_of_files)?;
        writer.write_u32::<LittleEndian>(self.central_directory_size)?;
        writer.write_u32::<LittleEndian>(self.central_directory_offset)?;
        writer.write_u16::<LittleEndian>(self.zip_file_comment.len() as u16)?;
        writer.write_all(&self.zip_file_comment)?;
        Ok(())
    }
}

pub struct Zip64CentralDirectoryEndLocator {
    pub disk_with_central_directory: u32,
    pub end_of_central_directory_offset: u64,
    pub number_of_disks: u32,
}

impl Zip64CentralDirectoryEndLocator {
    pub fn parse<T: Read>(reader: &mut T) -> ZipResult<Zip64CentralDirectoryEndLocator> {
        let magic = reader.read_u32::<LittleEndian>()?;
        if magic != ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE {
            return Err(ZipError::InvalidArchive(
                "Invalid zip64 locator digital signature header",
            ));
        }
        let disk_with_central_directory = reader.read_u32::<LittleEndian>()?;
        let end_of_central_directory_offset = reader.read_u64::<LittleEndian>()?;
        let number_of_disks = reader.read_u32::<LittleEndian>()?;

        Ok(Zip64CentralDirectoryEndLocator {
            disk_with_central_directory,
            end_of_central_directory_offset,
            number_of_disks,
        })
    }
}

pub struct Zip64CentralDirectoryEnd {
    pub version_made_by: u16,
    pub version_needed_to_extract: u16,
    pub disk_number: u32,
    pub disk_with_central_directory: u32,
    pub number_of_files_on_this_disk: u64,
    pub number_of_files: u64,
    pub central_directory_size: u64,
    pub central_directory_offset: u64,
    //pub extensible_data_sector: Vec<u8>, <-- We don't do anything with this at the moment.
}

impl Zip64CentralDirectoryEnd {
    pub fn find_and_parse<T: Read + io::Seek>(
        reader: &mut T,
        nominal_offset: u64,
        search_upper_bound: u64,
    ) -> ZipResult<(Zip64CentralDirectoryEnd, u64)> {
        let mut pos = nominal_offset;

        while pos <= search_upper_bound {
            reader.seek(io::SeekFrom::Start(pos))?;

            if reader.read_u32::<LittleEndian>()? == ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE {
                let archive_offset = pos - nominal_offset;

                let _record_size = reader.read_u64::<LittleEndian>()?;
                // We would use this value if we did anything with the "zip64 extensible data sector".

                let version_made_by = reader.read_u16::<LittleEndian>()?;
                let version_needed_to_extract = reader.read_u16::<LittleEndian>()?;
                let disk_number = reader.read_u32::<LittleEndian>()?;
                let disk_with_central_directory = reader.read_u32::<LittleEndian>()?;
                let number_of_files_on_this_disk = reader.read_u64::<LittleEndian>()?;
                let number_of_files = reader.read_u64::<LittleEndian>()?;
                let central_directory_size = reader.read_u64::<LittleEndian>()?;
                let central_directory_offset = reader.read_u64::<LittleEndian>()?;

                return Ok((
                    Zip64CentralDirectoryEnd {
                        version_made_by,
                        version_needed_to_extract,
                        disk_number,
                        disk_with_central_directory,
                        number_of_files_on_this_disk,
                        number_of_files,
                        central_directory_size,
                        central_directory_offset,
                    },
                    archive_offset,
                ));
            }

            pos += 1;
        }

        Err(ZipError::InvalidArchive(
            "Could not find ZIP64 central directory end",
        ))
    }
}
<commit_msg>allow for garbage after comment data<commit_after>use crate::result::{ZipError, ZipResult};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io;
use std::io::prelude::*;

pub const LOCAL_FILE_HEADER_SIGNATURE: u32 = 0x04034b50;
pub const CENTRAL_DIRECTORY_HEADER_SIGNATURE: u32 = 0x02014b50;
const CENTRAL_DIRECTORY_END_SIGNATURE: u32 = 0x06054b50;
pub const ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE: u32 = 0x06064b50;
const ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE: u32 = 0x07064b50;

pub struct CentralDirectoryEnd {
    pub disk_number: u16,
    pub disk_with_central_directory: u16,
    pub number_of_files_on_this_disk: u16,
    pub number_of_files: u16,
    pub central_directory_size: u32,
    pub central_directory_offset: u32,
    pub zip_file_comment: Vec<u8>,
}

impl CentralDirectoryEnd {
    pub fn parse<T: Read>(reader: &mut T) -> ZipResult<CentralDirectoryEnd> {
        let magic = reader.read_u32::<LittleEndian>()?;
        if magic != CENTRAL_DIRECTORY_END_SIGNATURE {
            return Err(ZipError::InvalidArchive("Invalid digital signature header"));
        }
        let disk_number = reader.read_u16::<LittleEndian>()?;
        let disk_with_central_directory = reader.read_u16::<LittleEndian>()?;
        let number_of_files_on_this_disk = reader.read_u16::<LittleEndian>()?;
        let number_of_files = reader.read_u16::<LittleEndian>()?;
        let central_directory_size = reader.read_u32::<LittleEndian>()?;
        let central_directory_offset = reader.read_u32::<LittleEndian>()?;
        let zip_file_comment_length = reader.read_u16::<LittleEndian>()? as usize;
        let mut zip_file_comment = vec![0; zip_file_comment_length];
        reader.read_exact(&mut zip_file_comment)?;

        Ok(CentralDirectoryEnd {
            disk_number,
            disk_with_central_directory,
            number_of_files_on_this_disk,
            number_of_files,
            central_directory_size,
            central_directory_offset,
            zip_file_comment,
        })
    }

    pub fn find_and_parse<T: Read + io::Seek>(
        reader: &mut T,
    ) -> ZipResult<(CentralDirectoryEnd, u64)> {
        const HEADER_SIZE: u64 = 22;
        const BYTES_BETWEEN_MAGIC_AND_COMMENT_SIZE: u64 = HEADER_SIZE - 6;
        let file_length = reader.seek(io::SeekFrom::End(0))?;

        let search_upper_bound = file_length.saturating_sub(HEADER_SIZE + ::std::u16::MAX as u64);

        if file_length < HEADER_SIZE {
            return Err(ZipError::InvalidArchive("Invalid zip header"));
        }

        let mut pos = file_length - HEADER_SIZE;
        while pos >= search_upper_bound {
            reader.seek(io::SeekFrom::Start(pos as u64))?;
            if reader.read_u32::<LittleEndian>()? == CENTRAL_DIRECTORY_END_SIGNATURE {
                reader.seek(io::SeekFrom::Current(
                    BYTES_BETWEEN_MAGIC_AND_COMMENT_SIZE as i64,
                ))?;

                let cde_start_pos = reader.seek(io::SeekFrom::Start(pos as u64))?;
                return CentralDirectoryEnd::parse(reader).map(|cde| (cde, cde_start_pos));
            }
            pos = match pos.checked_sub(1) {
                Some(p) => p,
                None => break,
            };
        }
        Err(ZipError::InvalidArchive(
            "Could not find central directory end",
        ))
    }

    pub fn write<T: Write>(&self, writer: &mut T) -> ZipResult<()> {
        writer.write_u32::<LittleEndian>(CENTRAL_DIRECTORY_END_SIGNATURE)?;
        writer.write_u16::<LittleEndian>(self.disk_number)?;
        writer.write_u16::<LittleEndian>(self.disk_with_central_directory)?;
        writer.write_u16::<LittleEndian>(self.number_of_files_on_this_disk)?;
        writer.write_u16::<LittleEndian>(self.number_of_files)?;
        writer.write_u32::<LittleEndian>(self.central_directory_size)?;
        writer.write_u32::<LittleEndian>(self.central_directory_offset)?;
        writer.write_u16::<LittleEndian>(self.zip_file_comment.len() as u16)?;
        writer.write_all(&self.zip_file_comment)?;
        Ok(())
    }
}

pub struct Zip64CentralDirectoryEndLocator {
    pub disk_with_central_directory: u32,
    pub end_of_central_directory_offset: u64,
    pub number_of_disks: u32,
}

impl Zip64CentralDirectoryEndLocator {
    pub fn parse<T: Read>(reader: &mut T) -> ZipResult<Zip64CentralDirectoryEndLocator> {
        let magic = reader.read_u32::<LittleEndian>()?;
        if magic != ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE {
            return Err(ZipError::InvalidArchive(
                "Invalid zip64 locator digital signature header",
            ));
        }
        let disk_with_central_directory = reader.read_u32::<LittleEndian>()?;
        let end_of_central_directory_offset = reader.read_u64::<LittleEndian>()?;
        let number_of_disks = reader.read_u32::<LittleEndian>()?;

        Ok(Zip64CentralDirectoryEndLocator {
            disk_with_central_directory,
            end_of_central_directory_offset,
            number_of_disks,
        })
    }
}

pub struct Zip64CentralDirectoryEnd {
    pub version_made_by: u16,
    pub version_needed_to_extract: u16,
    pub disk_number: u32,
    pub disk_with_central_directory: u32,
    pub number_of_files_on_this_disk: u64,
    pub number_of_files: u64,
    pub central_directory_size: u64,
    pub central_directory_offset: u64,
    //pub extensible_data_sector: Vec<u8>, <-- We don't do anything with this at the moment.
}

impl Zip64CentralDirectoryEnd {
    pub fn find_and_parse<T: Read + io::Seek>(
        reader: &mut T,
        nominal_offset: u64,
        search_upper_bound: u64,
    ) -> ZipResult<(Zip64CentralDirectoryEnd, u64)> {
        let mut pos = nominal_offset;

        while pos <= search_upper_bound {
            reader.seek(io::SeekFrom::Start(pos))?;

            if reader.read_u32::<LittleEndian>()? == ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE {
                let archive_offset = pos - nominal_offset;

                let _record_size = reader.read_u64::<LittleEndian>()?;
                // We would use this value if we did anything with the "zip64 extensible data sector".

                let version_made_by = reader.read_u16::<LittleEndian>()?;
                let version_needed_to_extract = reader.read_u16::<LittleEndian>()?;
                let disk_number = reader.read_u32::<LittleEndian>()?;
                let disk_with_central_directory = reader.read_u32::<LittleEndian>()?;
                let number_of_files_on_this_disk = reader.read_u64::<LittleEndian>()?;
                let number_of_files = reader.read_u64::<LittleEndian>()?;
                let central_directory_size = reader.read_u64::<LittleEndian>()?;
                let central_directory_offset = reader.read_u64::<LittleEndian>()?;

                return Ok((
                    Zip64CentralDirectoryEnd {
                        version_made_by,
                        version_needed_to_extract,
                        disk_number,
                        disk_with_central_directory,
                        number_of_files_on_this_disk,
                        number_of_files,
                        central_directory_size,
                        central_directory_offset,
                    },
                    archive_offset,
                ));
            }

            pos += 1;
        }

        Err(ZipError::InvalidArchive(
            "Could not find ZIP64 central directory end",
        ))
    }
}
<|endoftext|>


<commit_before>use parse::{self, Ast};
use collapse;

#[derive(Debug)]
pub struct Regex(Vec<Ast>);

impl Regex {
    pub fn new(s: &str) -> Regex {
        let vec = parse::parse(s).unwrap();
        let vec = collapse::collapse(vec);

        Regex(vec)
    }
    /// Returns true if and only if the regex matches the string given.
    ///
    /// # Example
    ///
    /// ```rust
    /// # extern crate rules; use rules::re::Regex;
    /// # fn main() {
    /// let pineapple = Regex::new(r"pine
    ///                              apple");
    /// assert!(pineapple.is_match("I bought a pineapple."));
    ///
    /// // Digit or `a`. `-` is set difference.
    /// let char_class = Regex::new(r"<[ 0 .. 9 a .. z] - [ b .. z ]>");
    /// assert!(char_class.is_match("3"));
    /// assert!(char_class.is_match("a"));
    ///
    /// assert!(!char_class.is_match("b"));
    /// }
    /// ```
    pub fn is_match(&self, s: &str) -> bool {
        let match_start = MatchStart { ast: &self.0[0], chars: s, cur: 0 };
        let mut matches = false;

        // Iterates over the substrings which could *possibly* match based
        // only on the first Ast.
        for substr in match_start {
            let mut substr = substr;

            for ast in &self.0 {
                // No way to return a result based on if the loop doesn't break. This
                // is the workaround.
                matches = true;

                if let Some(trimmed) = ast.matches(substr) {
                    substr = trimmed;
                } else {
                    matches = false;
                    break
                }
            }

            if matches { return true }
        }

        false
    }
}

// A struct to allow an Iterator to be created which will return substrings
// which start where a single Ast matches.
struct MatchStart<'a> {
    ast: &'a Ast,
    chars: &'a str,
    cur:  usize,
}

impl<'a> Iterator for MatchStart<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if let Some(pos) = self.ast.find(&self.chars[self.cur..]) {
            self.cur += pos + 1;

            Some(&self.chars[self.cur-1..])
        } else { None }
    }
}
<commit_msg>Hide `}` in example<commit_after>use parse::{self, Ast};
use collapse;

#[derive(Debug)]
pub struct Regex(Vec<Ast>);

impl Regex {
    pub fn new(s: &str) -> Regex {
        let vec = parse::parse(s).unwrap();
        let vec = collapse::collapse(vec);

        Regex(vec)
    }
    /// Returns true if and only if the regex matches the string given.
    ///
    /// # Example
    ///
    /// ```rust
    /// # extern crate rules; use rules::re::Regex;
    /// # fn main() {
    /// let pineapple = Regex::new(r"pine
    ///                              apple");
    /// assert!(pineapple.is_match("I bought a pineapple."));
    ///
    /// // Digit or `a`. `-` is set difference.
    /// let char_class = Regex::new(r"<[ 0 .. 9 a .. z] - [ b .. z ]>");
    /// assert!(char_class.is_match("3"));
    /// assert!(char_class.is_match("a"));
    ///
    /// assert!(!char_class.is_match("b"));
    /// # }
    /// ```
    pub fn is_match(&self, s: &str) -> bool {
        let match_start = MatchStart { ast: &self.0[0], chars: s, cur: 0 };
        let mut matches = false;

        // Iterates over the substrings which could *possibly* match based
        // only on the first Ast.
        for substr in match_start {
            let mut substr = substr;

            for ast in &self.0 {
                // No way to return a result based on if the loop doesn't break. This
                // is the workaround.
                matches = true;

                if let Some(trimmed) = ast.matches(substr) {
                    substr = trimmed;
                } else {
                    matches = false;
                    break
                }
            }

            if matches { return true }
        }

        false
    }
}

// A struct to allow an Iterator to be created which will return substrings
// which start where a single Ast matches.
struct MatchStart<'a> {
    ast: &'a Ast,
    chars: &'a str,
    cur:  usize,
}

impl<'a> Iterator for MatchStart<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if let Some(pos) = self.ast.find(&self.chars[self.cur..]) {
            self.cur += pos + 1;

            Some(&self.chars[self.cur-1..])
        } else { None }
    }
}
<|endoftext|>


<commit_before>use std;
use std::path::Path;
use std::fmt::{
  Display,
  Formatter,
};

use ::{
  KVStore,
  ValueType,
};

use ::cmd::Command;

pub enum UiError {
  KvStoreNotExisting(String, String),
  NoValueForKey(String),
  AlreadyValuePresent(String),
  KvError(::KVError),
  CmdError(::cmd::Error),
  UnknownError(String),
}

impl Display for UiError {
  fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
    match *self {
      UiError::KvStoreNotExisting(ref path, ref program) => write!(f, "kv store at {} not existing. Create with '{} init' command", path, program),
      UiError::NoValueForKey(ref key) => write!(f, "no value for key {}", key),
      UiError::AlreadyValuePresent(ref key) => write!(f, "there is already a value at {}", key),
      UiError::KvError(ref e) => e.fmt(f),
      UiError::CmdError(ref e) => e.fmt(f),
      UiError::UnknownError(ref msg) => write!(f, "unknown error: {}", msg),
    }
  }
}

impl From<::cmd::Error> for UiError {
  fn from(e: ::cmd::Error) -> Self {
    UiError::CmdError(e)
  }
}

impl From<::KVError> for UiError {
  fn from(e: ::KVError) -> Self {
    UiError::KvError(e)
  }
}

pub enum UiResult {
  StringValueResult(String),
  StringListResult(Vec<String>),
  Ok,
}

impl Display for UiResult {
  fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
    match *self {
      UiResult::StringValueResult(ref value) => write!(f, "{}", value),
      UiResult::StringListResult(ref strings) => {
        if strings.len() == 0 {
          write!(f, "(empty list)")
        } else {
          write!(f, "{}", strings.join("\n"))
        }
      },
      UiResult::Ok => write!(f, "ok"),
    }
  }
}

impl UiResult {
  pub fn ok(_: ()) -> Result<UiResult> {
    Ok(UiResult::Ok)
  }
}

type Result<T> = std::result::Result<T, UiError>;

#[derive(Debug)]
pub struct Ui {
  program: String,
  store_file: String,
  enumerate_list: bool,
}

impl Ui {
  pub fn new(program: String, store_file: String, enumerate_list: bool) -> Ui {
    Ui {
      program: program,
      store_file: store_file,
      enumerate_list: enumerate_list,
    }
  }

  fn load_or_create_kvstore(&self, store_path: &Path, is_init: bool) -> Result<KVStore> {
    if !store_path.exists() {
      if !is_init {
        return Err(UiError::KvStoreNotExisting(store_path.to_str().unwrap_or("<invalid path>").to_string(), self.program.clone()));
      }

      return Ok(KVStore::new());
    }

    return Ok(::KVStore::read_from_file(store_path)?);
  }

  pub fn run(&self, args: Vec<String>) -> Result<UiResult> {
    let store_path = Path::new(&self.store_file);

    let command = Command::from_strings(args)?;

    let mut kvs = self.load_or_create_kvstore(store_path, command == Command::Init)?;

    let result = self.interpret(&mut kvs, &command)?;

    kvs.write_to_file(store_path)?;

    Ok(result)
  }

  fn interpret(&self, kvs: &mut KVStore, command: &Command) -> Result<UiResult> {
    match *command {
      Command::Init => Ok(UiResult::Ok),
      Command::PutString(ref key, ref value) => self.put_string(key, value, kvs),
      Command::Get(ref key) => self.get(key, kvs),
      Command::ListKeys => self.list_keys(kvs),
      Command::CreateEmptyList(ref key) => self.create_empty_list(key, kvs),
      Command::PushListValue(ref key, ref value) => UiResult::ok(kvs.push_value(key, value)?),
      Command::PopListValue(ref key) => Ok(UiResult::StringValueResult(kvs.pop_value(key)?)),
      Command::Drop(ref key) => self.drop(key, kvs),
      Command::ClearList(ref key) => self.clear_list(key, kvs),
    }
  }

  fn put_string(&self, key: &String, value: &String, kvs: &mut KVStore) -> Result<UiResult> {
    match kvs.get_value_type(key) {
      Some(ValueType::String) => UiResult::ok(kvs.put(key, value)),
      _ => Err(UiError::AlreadyValuePresent(key.to_string()))
    }
  }

  fn create_empty_list(&self, key: &String, kvs: &mut KVStore) -> Result<UiResult> {
    if kvs.has_key(key) {
      Err(UiError::AlreadyValuePresent(key.to_string()))
    } else {
      self.clear_list(key, kvs)?;
      Ok(UiResult::Ok)
    }
  }

  fn clear_list(&self, key: &String, kvs: &mut KVStore) -> Result<UiResult> {
    match kvs.put_empty_list(key) {
      Some(v) => Ok(self.to_result(&v)),
      None => Ok(UiResult::Ok),
    }
  }

  fn drop(&self, key: &String, kvs: &mut KVStore) -> Result<UiResult> {
    match kvs.drop(key) {
      Some(v) => Ok(self.to_result(&v)),
      None => Ok(UiResult::Ok),
    }
  }

  fn list_keys(&self, kvs: &KVStore) -> Result<UiResult> {
    Ok(UiResult::StringListResult(kvs.get_keys().iter().map(|x| x.to_string()).collect()))
  }

  fn get(&self, key: &String, kvs: &KVStore) -> Result<UiResult> {
    let value = kvs.get(key).ok_or(UiError::NoValueForKey(key.clone()))?;

    Ok(self.to_result(value))
  }

  fn to_result(&self, value: &::Value) -> UiResult {
    match *value {
      ::Value::StringValue(ref val) => UiResult::StringValueResult(val.clone()),
      ::Value::ListValue(ref list) => UiResult::StringListResult(self.prepare_list_result(list)),
    }
  }

  fn prepare_list_result(&self, list: &Vec<String>) -> Vec<String> {
    if self.enumerate_list {
      let mut i = 0;
      list.iter().map(|x| {
        i += 1;
        format!("{}: {}", i, x)
      }).collect()
    } else {
      list.clone()
    }
  }
}

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

  #[test]
  fn test_construct() {
    Ui::new("program".to_string(), "test".to_string(), false);
  }
}
<commit_msg>minor fix<commit_after>use std;
use std::path::Path;
use std::fmt::{
  Display,
  Formatter,
};

use ::{
  KVStore,
  ValueType,
};

use ::cmd::Command;

pub enum UiError {
  KvStoreNotExisting(String, String),
  InitWithExistingKvStore(String),
  NoValueForKey(String),
  AlreadyValuePresent(String),
  KvError(::KVError),
  CmdError(::cmd::Error),
  UnknownError(String),
}

impl Display for UiError {
  fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
    match *self {
      UiError::KvStoreNotExisting(ref path, ref program) => write!(f, "kv store at {} not existing. Create with '{} init' command", path, program),
      UiError::InitWithExistingKvStore(ref path) => write!(f, "kv store at {} already initialized", path),
      UiError::NoValueForKey(ref key) => write!(f, "no value for key {}", key),
      UiError::AlreadyValuePresent(ref key) => write!(f, "there is already a value at {}", key),
      UiError::KvError(ref e) => e.fmt(f),
      UiError::CmdError(ref e) => e.fmt(f),
      UiError::UnknownError(ref msg) => write!(f, "unknown error: {}", msg),
    }
  }
}

impl From<::cmd::Error> for UiError {
  fn from(e: ::cmd::Error) -> Self {
    UiError::CmdError(e)
  }
}

impl From<::KVError> for UiError {
  fn from(e: ::KVError) -> Self {
    UiError::KvError(e)
  }
}

pub enum UiResult {
  StringValueResult(String),
  StringListResult(Vec<String>),
  Ok,
}

impl Display for UiResult {
  fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
    match *self {
      UiResult::StringValueResult(ref value) => write!(f, "{}", value),
      UiResult::StringListResult(ref strings) => {
        if strings.len() == 0 {
          write!(f, "(empty list)")
        } else {
          write!(f, "{}", strings.join("\n"))
        }
      },
      UiResult::Ok => write!(f, "ok"),
    }
  }
}

impl UiResult {
  pub fn ok(_: ()) -> Result<UiResult> {
    Ok(UiResult::Ok)
  }
}

type Result<T> = std::result::Result<T, UiError>;

#[derive(Debug)]
pub struct Ui {
  program: String,
  store_file: String,
  enumerate_list: bool,
}

impl Ui {
  pub fn new(program: String, store_file: String, enumerate_list: bool) -> Ui {
    Ui {
      program: program,
      store_file: store_file,
      enumerate_list: enumerate_list,
    }
  }

  fn load_or_create_kvstore(&self, store_path: &Path, is_init: bool) -> Result<KVStore> {
    if !store_path.exists() {
      if !is_init {
        return Err(UiError::KvStoreNotExisting(store_path.to_str().unwrap_or("<invalid path>").to_string(), self.program.clone()));
      }

      return Ok(::init(store_path)?);
    }

    if is_init {
      Err(UiError::InitWithExistingKvStore(store_path.to_str().unwrap_or("<invalied path>").to_string()))
    } else {
      Ok(::KVStore::read_from_file(store_path)?)
    }
  }

  pub fn run(&self, args: Vec<String>) -> Result<UiResult> {
    let store_path = Path::new(&self.store_file);

    let command = Command::from_strings(args)?;

    let mut kvs = self.load_or_create_kvstore(store_path, command == Command::Init)?;

    let result = self.interpret(&mut kvs, &command)?;

    kvs.write_to_file(store_path)?;

    Ok(result)
  }

  fn interpret(&self, kvs: &mut KVStore, command: &Command) -> Result<UiResult> {
    match *command {
      Command::Init => Ok(UiResult::Ok),
      Command::PutString(ref key, ref value) => self.put_string(key, value, kvs),
      Command::Get(ref key) => self.get(key, kvs),
      Command::ListKeys => self.list_keys(kvs),
      Command::CreateEmptyList(ref key) => self.create_empty_list(key, kvs),
      Command::PushListValue(ref key, ref value) => UiResult::ok(kvs.push_value(key, value)?),
      Command::PopListValue(ref key) => Ok(UiResult::StringValueResult(kvs.pop_value(key)?)),
      Command::Drop(ref key) => self.drop(key, kvs),
      Command::ClearList(ref key) => self.clear_list(key, kvs),
    }
  }

  fn put_string(&self, key: &String, value: &String, kvs: &mut KVStore) -> Result<UiResult> {
    match kvs.get_value_type(key) {
      Some(ValueType::String) => UiResult::ok(kvs.put(key, value)),
      _ => Err(UiError::AlreadyValuePresent(key.to_string()))
    }
  }

  fn create_empty_list(&self, key: &String, kvs: &mut KVStore) -> Result<UiResult> {
    if kvs.has_key(key) {
      Err(UiError::AlreadyValuePresent(key.to_string()))
    } else {
      self.clear_list(key, kvs)?;
      Ok(UiResult::Ok)
    }
  }

  fn clear_list(&self, key: &String, kvs: &mut KVStore) -> Result<UiResult> {
    match kvs.put_empty_list(key) {
      Some(v) => Ok(self.to_result(&v)),
      None => Ok(UiResult::Ok),
    }
  }

  fn drop(&self, key: &String, kvs: &mut KVStore) -> Result<UiResult> {
    match kvs.drop(key) {
      Some(v) => Ok(self.to_result(&v)),
      None => Err(UiError::NoValueForKey(key.to_string())),
    }
  }

  fn list_keys(&self, kvs: &KVStore) -> Result<UiResult> {
    Ok(UiResult::StringListResult(kvs.get_keys().iter().map(|x| x.to_string()).collect()))
  }

  fn get(&self, key: &String, kvs: &KVStore) -> Result<UiResult> {
    let value = kvs.get(key).ok_or(UiError::NoValueForKey(key.clone()))?;

    Ok(self.to_result(value))
  }

  fn to_result(&self, value: &::Value) -> UiResult {
    match *value {
      ::Value::StringValue(ref val) => UiResult::StringValueResult(val.clone()),
      ::Value::ListValue(ref list) => UiResult::StringListResult(self.prepare_list_result(list)),
    }
  }

  fn prepare_list_result(&self, list: &Vec<String>) -> Vec<String> {
    if self.enumerate_list {
      let mut i = 0;
      list.iter().map(|x| {
        i += 1;
        format!("{}: {}", i, x)
      }).collect()
    } else {
      list.clone()
    }
  }
}

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

  #[test]
  fn test_construct() {
    Ui::new("program".to_string(), "test".to_string(), false);
  }
}
<|endoftext|>


<commit_before>use errors::SendgridResult;

use std::collections::HashMap;

use reqwest::{Client, StatusCode};
use reqwest::header::{Authorization, Bearer, ContentType, Headers, UserAgent};

use data_encoding::base64;

use serde_json;

const V3_API_URL: &'static str = "https://api.sendgrid.com/v3/mail/send";

/// Just a redefinition of a map to store string keys and values.
pub type SGMap = HashMap<String, String>;

/// Used to send a V3 message body.
pub struct V3Sender {
    api_key: String,
}

/// The main structure for a V3 API mail send call. This is composed of many other smaller
/// structures used to add lots of customization to your message.
#[derive(Serialize)]
pub struct SGMailV3 {
    from: Email,
    subject: String,
    content: Vec<Content>,
    personalizations: Vec<Personalization>,

    #[serde(skip_serializing_if = "check_encode")]
    attachments: Option<Vec<Attachment>>,
}

/// An email with a required address and an optional name field.
#[derive(Clone, Serialize)]
pub struct Email {
    email: String,

    #[serde(skip_serializing_if = "check_encode")]
    name: Option<String>,
}

/// The body of an email with the content type and the message.
#[derive(Clone, Serialize)]
pub struct Content {
    #[serde(rename = "type")]
    content_type: String,
    value: String,
}

/// A personalization block for a V3 message. It has to at least contain one email as a to
/// address. All other fields are optional.
#[derive(Serialize)]
pub struct Personalization {
    to: Vec<Email>,

    #[serde(skip_serializing_if = "check_encode")]
    cc: Option<Vec<Email>>,

    #[serde(skip_serializing_if = "check_encode")]
    bcc: Option<Vec<Email>>,

    #[serde(skip_serializing_if = "check_encode")]
    subject: Option<String>,

    #[serde(skip_serializing_if = "check_encode")]
    headers: Option<SGMap>,

    #[serde(skip_serializing_if = "check_encode")]
    substitutions: Option<SGMap>,

    #[serde(skip_serializing_if = "check_encode")]
    custom_args: Option<SGMap>,

    #[serde(skip_serializing_if = "check_encode")]
    send_at: Option<u64>,
}

/// An attachment block for a V3 message. Content and filename are required. If the
/// mime_type is unspecified, the email will use Sendgrid's default for attachments
/// which is 'application/octet-stream'.
#[derive(Serialize)]
pub struct Attachment {
    content: String,

    filename: String,

    #[serde(rename = "type", skip_serializing_if = "check_encode")]
    mime_type: Option<String>,

    #[serde(skip_serializing_if = "check_encode")]
    disposition: Option<String>,

    #[serde(skip_serializing_if = "check_encode")]
    content_id: Option<String>,
}

// Checks if a value in the V3 message should be added to the JSON or not.
fn check_encode<T>(value: &Option<T>) -> bool {
    match *value {
        Some(_) => false,
        None => true,
    }
}

impl V3Sender {
    /// Construct a new V3 message sender.
    pub fn new(api_key: String) -> V3Sender {
        V3Sender { api_key: api_key }
    }

    /// Send a V3 message and return the status code or an error from the request.
    pub fn send(&self, mail: &SGMailV3) -> SendgridResult<StatusCode> {
        let client = Client::new()?;
        let mut headers = Headers::new();
        headers.set(Authorization(Bearer { token: self.api_key.to_owned() }));
        headers.set(ContentType::json());
        headers.set(UserAgent::new("sendgrid-rs"));

        let body = mail.gen_json();
        let res = client.post(V3_API_URL)?.headers(headers).body(body).send()?;
        Ok(res.status())
    }
}

impl SGMailV3 {
    /// Construct a new V3 message.
    pub fn new() -> SGMailV3 {
        SGMailV3 {
            from: Email::new(),
            subject: String::new(),
            content: Vec::new(),
            personalizations: Vec::new(),
            attachments: None,
        }
    }

    /// Set the from address.
    pub fn set_from(&mut self, from: Email) {
        self.from = from;
    }

    /// Set the subject.
    pub fn set_subject(&mut self, subject: &str) {
        self.subject = String::from(subject);
    }

    /// Add content to the message.
    pub fn add_content(&mut self, content: Content) {
        self.content.push(content);
    }

    /// Add a personalization to the message.
    pub fn add_personalization(&mut self, p: Personalization) {
        self.personalizations.push(p);
    }

    /// Add an attachment to the message.
    pub fn add_attachment(&mut self, a: Attachment) {
        match self.attachments {
            None => {
                let mut attachments = Vec::new();
                attachments.push(a);
                self.attachments = Some(attachments);
            }
            Some(ref mut attachments) => attachments.push(a),
        };
    }

    fn gen_json(&self) -> String {
        serde_json::to_string(self).unwrap()
    }
}

impl Email {
    /// Construct a new email type.
    pub fn new() -> Email {
        Email {
            email: String::new(),
            name: None,
        }
    }

    /// Set the address for this email.
    pub fn set_email(&mut self, email: &str) {
        self.email = String::from(email);
    }

    /// Set an optional name.
    pub fn set_name(&mut self, name: &str) {
        self.name = Some(String::from(name));
    }
}

impl Content {
    /// Construct a new content type.
    pub fn new() -> Content {
        Content {
            content_type: String::new(),
            value: String::new(),
        }
    }

    /// Set the type of this content.
    pub fn set_content_type(&mut self, content_type: &str) {
        self.content_type = String::from(content_type);
    }

    /// Set the corresponding message for this content.
    pub fn set_value(&mut self, value: &str) {
        self.value = String::from(value);
    }
}

impl Personalization {
    /// Construct a new personalization block for this message.
    pub fn new() -> Personalization {
        Personalization {
            to: Vec::new(),
            cc: None,
            bcc: None,
            subject: None,
            headers: None,
            substitutions: None,
            custom_args: None,
            send_at: None,
        }
    }

    /// Add a to field.
    pub fn add_to(&mut self, to: Email) {
        self.to.push(to);
    }

    /// Add a CC field.
    pub fn add_cc(&mut self, cc: Email) {
        match self.cc {
            None => {
                let mut ccs = Vec::new();
                ccs.push(cc);
                self.cc = Some(ccs);
            }
            Some(ref mut c) => {
                c.push(cc);
            }
        }
    }
}

impl Attachment {
    /// Construct a new attachment for this message.
    pub fn new() -> Attachment {
        Attachment {
            content: String::new(),
            filename: String::new(),
            mime_type: None,
            disposition: None,
            content_id: None,
        }
    }

    /// The raw body of the attachment.
    pub fn set_content(&mut self, c: &[u8]) {
        self.content = base64::encode(c);
    }

    /// Sets the filename for the attachment.
    pub fn set_filename(&mut self, filename: &str) {
        self.filename = filename.into();
    }

    /// Set an optional mime type. Sendgrid will default to 'application/octet-stream'
    /// if unspecified.
    pub fn set_mime_type(&mut self, mime: &str) {
        self.mime_type = Some(String::from(mime));
    }
}
<commit_msg>add an add_bcc() function to allow bcc use (#21)<commit_after>use errors::SendgridResult;

use std::collections::HashMap;

use reqwest::{Client, StatusCode};
use reqwest::header::{Authorization, Bearer, ContentType, Headers, UserAgent};

use data_encoding::base64;

use serde_json;

const V3_API_URL: &'static str = "https://api.sendgrid.com/v3/mail/send";

/// Just a redefinition of a map to store string keys and values.
pub type SGMap = HashMap<String, String>;

/// Used to send a V3 message body.
pub struct V3Sender {
    api_key: String,
}

/// The main structure for a V3 API mail send call. This is composed of many other smaller
/// structures used to add lots of customization to your message.
#[derive(Serialize)]
pub struct SGMailV3 {
    from: Email,
    subject: String,
    content: Vec<Content>,
    personalizations: Vec<Personalization>,

    #[serde(skip_serializing_if = "check_encode")]
    attachments: Option<Vec<Attachment>>,
}

/// An email with a required address and an optional name field.
#[derive(Clone, Serialize)]
pub struct Email {
    email: String,

    #[serde(skip_serializing_if = "check_encode")]
    name: Option<String>,
}

/// The body of an email with the content type and the message.
#[derive(Clone, Serialize)]
pub struct Content {
    #[serde(rename = "type")]
    content_type: String,
    value: String,
}

/// A personalization block for a V3 message. It has to at least contain one email as a to
/// address. All other fields are optional.
#[derive(Serialize)]
pub struct Personalization {
    to: Vec<Email>,

    #[serde(skip_serializing_if = "check_encode")]
    cc: Option<Vec<Email>>,

    #[serde(skip_serializing_if = "check_encode")]
    bcc: Option<Vec<Email>>,

    #[serde(skip_serializing_if = "check_encode")]
    subject: Option<String>,

    #[serde(skip_serializing_if = "check_encode")]
    headers: Option<SGMap>,

    #[serde(skip_serializing_if = "check_encode")]
    substitutions: Option<SGMap>,

    #[serde(skip_serializing_if = "check_encode")]
    custom_args: Option<SGMap>,

    #[serde(skip_serializing_if = "check_encode")]
    send_at: Option<u64>,
}

/// An attachment block for a V3 message. Content and filename are required. If the
/// mime_type is unspecified, the email will use Sendgrid's default for attachments
/// which is 'application/octet-stream'.
#[derive(Serialize)]
pub struct Attachment {
    content: String,

    filename: String,

    #[serde(rename = "type", skip_serializing_if = "check_encode")]
    mime_type: Option<String>,

    #[serde(skip_serializing_if = "check_encode")]
    disposition: Option<String>,

    #[serde(skip_serializing_if = "check_encode")]
    content_id: Option<String>,
}

// Checks if a value in the V3 message should be added to the JSON or not.
fn check_encode<T>(value: &Option<T>) -> bool {
    match *value {
        Some(_) => false,
        None => true,
    }
}

impl V3Sender {
    /// Construct a new V3 message sender.
    pub fn new(api_key: String) -> V3Sender {
        V3Sender { api_key: api_key }
    }

    /// Send a V3 message and return the status code or an error from the request.
    pub fn send(&self, mail: &SGMailV3) -> SendgridResult<StatusCode> {
        let client = Client::new()?;
        let mut headers = Headers::new();
        headers.set(Authorization(Bearer { token: self.api_key.to_owned() }));
        headers.set(ContentType::json());
        headers.set(UserAgent::new("sendgrid-rs"));

        let body = mail.gen_json();
        let res = client.post(V3_API_URL)?.headers(headers).body(body).send()?;
        Ok(res.status())
    }
}

impl SGMailV3 {
    /// Construct a new V3 message.
    pub fn new() -> SGMailV3 {
        SGMailV3 {
            from: Email::new(),
            subject: String::new(),
            content: Vec::new(),
            personalizations: Vec::new(),
            attachments: None,
        }
    }

    /// Set the from address.
    pub fn set_from(&mut self, from: Email) {
        self.from = from;
    }

    /// Set the subject.
    pub fn set_subject(&mut self, subject: &str) {
        self.subject = String::from(subject);
    }

    /// Add content to the message.
    pub fn add_content(&mut self, content: Content) {
        self.content.push(content);
    }

    /// Add a personalization to the message.
    pub fn add_personalization(&mut self, p: Personalization) {
        self.personalizations.push(p);
    }

    /// Add an attachment to the message.
    pub fn add_attachment(&mut self, a: Attachment) {
        match self.attachments {
            None => {
                let mut attachments = Vec::new();
                attachments.push(a);
                self.attachments = Some(attachments);
            }
            Some(ref mut attachments) => attachments.push(a),
        };
    }

    fn gen_json(&self) -> String {
        serde_json::to_string(self).unwrap()
    }
}

impl Email {
    /// Construct a new email type.
    pub fn new() -> Email {
        Email {
            email: String::new(),
            name: None,
        }
    }

    /// Set the address for this email.
    pub fn set_email(&mut self, email: &str) {
        self.email = String::from(email);
    }

    /// Set an optional name.
    pub fn set_name(&mut self, name: &str) {
        self.name = Some(String::from(name));
    }
}

impl Content {
    /// Construct a new content type.
    pub fn new() -> Content {
        Content {
            content_type: String::new(),
            value: String::new(),
        }
    }

    /// Set the type of this content.
    pub fn set_content_type(&mut self, content_type: &str) {
        self.content_type = String::from(content_type);
    }

    /// Set the corresponding message for this content.
    pub fn set_value(&mut self, value: &str) {
        self.value = String::from(value);
    }
}

impl Personalization {
    /// Construct a new personalization block for this message.
    pub fn new() -> Personalization {
        Personalization {
            to: Vec::new(),
            cc: None,
            bcc: None,
            subject: None,
            headers: None,
            substitutions: None,
            custom_args: None,
            send_at: None,
        }
    }

    /// Add a to field.
    pub fn add_to(&mut self, to: Email) {
        self.to.push(to);
    }

    /// Add a CC field.
    pub fn add_cc(&mut self, cc: Email) {
        match self.cc {
            None => {
                let mut ccs = Vec::new();
                ccs.push(cc);
                self.cc = Some(ccs);
            }
            Some(ref mut c) => {
                c.push(cc);
            }
        }
    }

    /// Add a BCC field.
    pub fn add_bcc(&mut self, bcc: Email) {
        match self.bcc {
            None => {
                let mut bccs = Vec::new();
                bccs.push(bcc);
                self.bcc = Some(bccs);
            }
            Some(ref mut b) => {
                b.push(bcc);
            }
        }
    }
}

impl Attachment {
    /// Construct a new attachment for this message.
    pub fn new() -> Attachment {
        Attachment {
            content: String::new(),
            filename: String::new(),
            mime_type: None,
            disposition: None,
            content_id: None,
        }
    }

    /// The raw body of the attachment.
    pub fn set_content(&mut self, c: &[u8]) {
        self.content = base64::encode(c);
    }

    /// Sets the filename for the attachment.
    pub fn set_filename(&mut self, filename: &str) {
        self.filename = filename.into();
    }

    /// Set an optional mime type. Sendgrid will default to 'application/octet-stream'
    /// if unspecified.
    pub fn set_mime_type(&mut self, mime: &str) {
        self.mime_type = Some(String::from(mime));
    }
}
<|endoftext|>