<commit_before>use std::borrow::Borrow;
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::hash::{Hash,Hasher};
use std::rc::Rc;

#[derive(Clone, Debug, Eq, PartialEq)]
/// The parameter styles for short, e.g. `-s`,
/// and for long, e.g. `--long`
pub enum Param {
    Short(char),
    Long(String),
}

impl Borrow<str> for Param {
    fn borrow(&self) -> &str {
        if let Param::Long(ref string) = *self {
            string
        } else {
            ""
        }
    }
}

impl Borrow<char> for Param {
    fn borrow(&self) -> &char {
        if let Param::Short(ref ch) = *self {
            ch
        } else {
            const CH: &'static char = &'\0';
            CH
        }
    }
}

impl Hash for Param {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match *self {
            Param::Short(ref c) => c.hash(state),
            Param::Long(ref s) => s.hash(state)
        }
    }
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
/// The Right Hand Side type
struct Rhs<T> {
    /// The RHS value
    value: T,
    /// Counts the number of times a flag/opt has been in use on the command
    occurrences: usize,
}

impl<T> Rhs<T> {
    fn new(value: T) -> Self {
        Rhs { value: value, occurrences: 0 }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
/// The Value for each parameter
enum Value {
    Flag(Rhs<Rc<RefCell<bool>>>),
    /// The RHS String value is shared between both short and long parameters
    Opt {
        rhs: Rhs<Rc<RefCell<String>>>,
        found: bool,
    },
}

impl Value {
    fn new_opt(value: Rc<RefCell<String>>) -> Self {
        Value::Opt { rhs: Rhs::new(value), found: false }
    }
}

/// Our homebrewed Arg Parser
#[derive(Clone, Debug, Default)]
pub struct ArgParser {
    params: HashMap<Param, Value>,
    invalid: Vec<Param>,
    garbage: (RefCell<bool>, RefCell<String>),
    pub args: Vec<String>,
}

impl ArgParser {
    /// Create a new ArgParser object
    ///
    /// The capacity specifies the initial capacity of the number parameters.
    /// Always good to set it at the number of flags and opts total.
    pub fn new(capacity: usize) -> Self {
        ArgParser {
            params: HashMap::with_capacity(capacity),
            invalid: Vec::new(),
            garbage: (RefCell::new(false), RefCell::new(String::with_capacity(0))),
            args: Vec::new(),
        }
    }

    /// Builder method for adding both short and long flags
    ///
    /// Flags are just parameters that have no assigned values. They are used
    /// for when certain features or options have been enabled for the application
    ///
    /// For example
    /// > ls -l --human-readable
    ///   ^  ^  ^
    ///   |  |  |
    ///   |  |  `-- A long flag to enable human readable numbers.
    ///   |  `-- A short flag to enable the long format.
    ///   `-- The command to list files.
    pub fn add_flag(mut self, flags: &[&str]) -> Self {
        let value = Rc::new(RefCell::new(bool::default()));
        for flag in flags.iter() {
            if flag.len() == 1 {
                if let Some(short) = flag.chars().next() {
                    self.params.insert(Param::Short(short), Value::Flag(Rhs::new(value.clone())));
                }
            }
            else {
                self.params.insert(Param::Long((*flag).to_owned()), Value::Flag(Rhs::new(value.clone())));
            }
        }
        self
    }

    /// Builder method for adding both short and long opts
    ///
    /// Opts are parameters that hold assigned values. They are used
    /// for when certain features or options have been enabled for the application
    ///
    /// For example
    /// > ls -T 4 --color=always
    ///   ^  ^    ^
    ///   |  |    |
    ///   |  |    `-- A long opt to enable the use of color with value `always`.
    ///   |  `-- A short opt to set tab size to the value `4`.
    ///   `-- The command to list files.
    pub fn add_opt(mut self, short: &str, long: &str) -> Self {
        let value = Rc::new(RefCell::new("".to_owned()));
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::new_opt(value.clone()));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::new_opt(value));
        }
        self
    }

    pub fn add_opt_default(mut self, short: &str, long: &str, default: &str) -> Self {
        let value = Rc::new(RefCell::new(default.to_owned()));
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::new_opt(value.clone()));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::new_opt(value));
        }
        self
    }

    /// Start parsing user inputted args for which flags and opts are used at
    /// runtime. The rest of the args that are not associated to opts get added
    /// to `ArgParser.args`.
    pub fn parse<A: Iterator<Item=String>>(&mut self, args: A) {
        let mut args = args.skip(1);
        while let Some(arg) = args.next() {
            if arg.starts_with("--") {
                // Remove both dashes
                let arg = &arg[2..];
                if arg.is_empty() {
                    //Arg `--` means we are done parsing args, collect the rest
                    self.args.extend(args);
                    break;
                }
                if let Some(i) = arg.find('=') {
                    let (lhs, rhs) = arg.split_at(i);
                    let rhs = &rhs[1..]; // slice off the `=` char
                    match self.params.get_mut(lhs) {
                        Some(&mut Value::Opt { rhs: ref mut opt_rhs, ref mut found }) => {
                            if (*opt_rhs.value).borrow().is_empty() {
                                opt_rhs.occurrences = 1;
                            }
                            else {
                                opt_rhs.occurrences += 1;
                            }
                            (*opt_rhs.value).borrow_mut().clear();
                            (*opt_rhs.value).borrow_mut().push_str(rhs);
                            *found = true;
                        }
                        _ => self.invalid.push(Param::Long(lhs.to_owned())),
                    }
                }
                else {
                    match self.params.get_mut(arg) {
                        Some(&mut Value::Flag(ref mut rhs)) => {
                            *(*rhs.value).borrow_mut() = true;
                            rhs.occurrences += 1;
                        }
                        Some(&mut Value::Opt { ref mut rhs, ref mut found }) => {
                            rhs.occurrences += 1;
                            *found = true;
                        }
                        _ => self.invalid.push(Param::Long(arg.to_owned())),
                    }
                }
            }
            else if arg.starts_with("-") {
                let mut chars = arg[1..].chars();
                while let Some(ch) = chars.next() {
                    match self.params.get_mut(&ch) {
                        Some(&mut Value::Flag(ref mut rhs)) => {
                            *(*rhs.value).borrow_mut() = true;
                            rhs.occurrences += 1;
                        }
                        Some(&mut Value::Opt { ref mut rhs, ref mut found }) => {
                            let rest: String = chars.collect();
                            if !rest.is_empty() {
                                *(*rhs.value).borrow_mut() = rest;
                                *found = true;
                            } else {
                                *(*rhs.value).borrow_mut() = args.next().map(|a| {*found = true; a}).unwrap_or("".to_owned());
                            }
                            break;
                        }
                        None => self.invalid.push(Param::Short(ch)),
                    }
                }
            }
            else {
                self.args.push(arg);
            }
        }
    }

    /// Get the number of times a flag or opt has been found after parsing.
    pub fn count
(&self, name: &P) -> usize
        where Param: Borrow

    {
        match self.params.get(name) {
            Some(&Value::Flag(ref rhs)) => rhs.occurrences,
            Some(&Value::Opt { ref rhs, .. }) => rhs.occurrences,
            _ => 0,
        }
    }

    /// Check if a flag or opt has been found after initialization.
    pub fn found
(&self, name: &P) -> bool
        where Param: Borrow

    {
        match self.params.get(name) {
            Some(&Value::Flag(ref rhs)) => *(*rhs.value).borrow_mut(),
            Some(&Value::Opt { found, .. }) => found,
            _ => false,
        }
    }

    /// Modify the state of a flag. Use `true` if the flag is to be enabled. Use `false` to
    /// disable its use.
    pub fn flag<F: Hash + Eq + ?Sized>(&mut self, flag: &F) -> RefMut<bool>
        where Param: Borrow<F>
    {
        if let Some(&mut Value::Flag(ref mut rhs)) = self.params.get_mut(flag) {
            return (*rhs.value).borrow_mut();
        }
        self.garbage.0.borrow_mut()
    }

    /// Modify the state value of an opt. Use `Some(String)` to set if the opt is to be enabled and
    /// has been assigned a value from `String`. Use `None` to disable the opt's use.
    pub fn opt<O: Hash + Eq + ?Sized>(&mut self, opt: &O) -> RefMut<String>
        where Param: Borrow<O>
    {
        if let Some(&mut Value::Opt { ref mut rhs, .. }) = self.params.get_mut(opt) {
            return (*rhs.value).borrow_mut();
        }
        self.garbage.1.borrow_mut()
    }

    /// Get the value of an Opt. If it has been set or defaulted, it will return a `Some(String)`
    /// value otherwise it will return None.
    pub fn get_opt<O: Hash + Eq + ?Sized>(&self, opt: &O) -> Option<String>
        where Param: Borrow<O>
    {
        if let Some(&Value::Opt { ref rhs, .. }) = self.params.get(opt) {
            return Some((*rhs.value).borrow().clone());
        }
        None
    }

    pub fn found_invalid(&self) -> Result<(), String> {
        if self.invalid.is_empty() {
            return Ok(());
        }

        let mut and: bool = false;
        let mut output =
            if self.invalid.len() == 1 {
                "Invalid parameter"
            } else {
                and = true;
                "Invalid parameters"
            }.to_owned();

        let mut iter = self.invalid.iter().peekable();
        while let Some(param) = iter.next() {
            match param {
                &Param::Short(ch) => {
                    output += " '-";
                    output.push(ch);
                    output.push('\'');
                }
                &Param::Long(ref s) => {
                    output += " '--";
                    output += s;
                    output.push('\'');
                }
            }
            if and && iter.peek().is_some() {
                output += " and";
            }
        }
        output.push('\n');
        Err(output)
    }
}

pub fn to_human_readable_string(size: u64) -> String {
    if size < 1024 {
        return format!("{}", size);
    }

    static UNITS: [&'static str; 7] = ["", "K", "M", "G", "T", "P", "E"];

    let sizef = size as f64;
    let digit_groups = (sizef.log10() / 1024f64.log10()) as i32;
    format!("{:.1}{}",
            sizef / 1024f64.powf(digit_groups as f64),
            UNITS[digit_groups as usize])
}

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

    #[test]
    fn stop_parsing() {
        let args = vec![String::from("binname"), String::from("-a"), String::from("--"), String::from("-v")];
        let mut parser = ArgParser::new(2);
        parser = parser.add_flag("a", "")
                       .add_flag("v", "");
        parser.parse(args.into_iter());
        assert!(parser.found(&'a'));
        assert!(!parser.found(&'v'));
        assert!(parser.args[0] == "-v");
    }

    #[test]
    fn short_opts() {
        let args = vec![String::from("binname"), String::from("-asdf"), String::from("-f"), String::from("foo")];
        let mut parser = ArgParser::new(4);
        parser = parser.add_flag("a", "")
                       .add_flag("d", "")
                       .add_opt("s", "")
                       .add_opt("f", "");
        parser.parse(args.into_iter());
        assert!(parser.found(&'a'));
        assert!(!parser.found(&'d'));
        assert!(parser.get_opt(&'s') == Some(String::from("df")));
        assert!(parser.get_opt(&'f') == Some(String::from("foo")));
    }

    #[test]
    fn long_opts() {
        let args = vec![String::from("binname"), String::from("--foo=bar")];
        let mut parser = ArgParser::new(4);
        parser = parser.add_opt("", "foo");
        parser.parse(args.into_iter());
        assert!(parser.get_opt("foo") == Some(String::from("bar")));
    }
}
<commit_msg>Apply a small change to `add_flag()`<commit_after>use std::borrow::Borrow;
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::hash::{Hash,Hasher};
use std::rc::Rc;

#[derive(Clone, Debug, Eq, PartialEq)]
/// The parameter styles for short, e.g. `-s`,
/// and for long, e.g. `--long`
pub enum Param {
    Short(char),
    Long(String),
}

impl Borrow<str> for Param {
    fn borrow(&self) -> &str {
        if let Param::Long(ref string) = *self {
            string
        } else {
            ""
        }
    }
}

impl Borrow<char> for Param {
    fn borrow(&self) -> &char {
        if let Param::Short(ref ch) = *self {
            ch
        } else {
            const CH: &'static char = &'\0';
            CH
        }
    }
}

impl Hash for Param {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match *self {
            Param::Short(ref c) => c.hash(state),
            Param::Long(ref s) => s.hash(state)
        }
    }
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
/// The Right Hand Side type
struct Rhs<T> {
    /// The RHS value
    value: T,
    /// Counts the number of times a flag/opt has been in use on the command
    occurrences: usize,
}

impl<T> Rhs<T> {
    fn new(value: T) -> Self {
        Rhs { value: value, occurrences: 0 }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
/// The Value for each parameter
enum Value {
    Flag(Rhs<Rc<RefCell<bool>>>),
    /// The RHS String value is shared between both short and long parameters
    Opt {
        rhs: Rhs<Rc<RefCell<String>>>,
        found: bool,
    },
}

impl Value {
    fn new_opt(value: Rc<RefCell<String>>) -> Self {
        Value::Opt { rhs: Rhs::new(value), found: false }
    }
}

/// Our homebrewed Arg Parser
#[derive(Clone, Debug, Default)]
pub struct ArgParser {
    params: HashMap<Param, Value>,
    invalid: Vec<Param>,
    garbage: (RefCell<bool>, RefCell<String>),
    pub args: Vec<String>,
}

impl ArgParser {
    /// Create a new ArgParser object
    ///
    /// The capacity specifies the initial capacity of the number parameters.
    /// Always good to set it at the number of flags and opts total.
    pub fn new(capacity: usize) -> Self {
        ArgParser {
            params: HashMap::with_capacity(capacity),
            invalid: Vec::new(),
            garbage: (RefCell::new(false), RefCell::new(String::with_capacity(0))),
            args: Vec::new(),
        }
    }

    /// Builder method for adding both short and long flags
    ///
    /// Flags are just parameters that have no assigned values. They are used
    /// for when certain features or options have been enabled for the application
    ///
    /// For example
    /// > ls -l --human-readable
    ///   ^  ^  ^
    ///   |  |  |
    ///   |  |  `-- A long flag to enable human readable numbers.
    ///   |  `-- A short flag to enable the long format.
    ///   `-- The command to list files.
    pub fn add_flag(mut self, flags: &[&str]) -> Self {
        let value = Rc::new(RefCell::new(bool::default()));
        for flag in flags.iter() {
            if flag.len() == 1 {
                if let Some(short) = flag.chars().next() {
                    self.params.insert(Param::Short(short), Value::Flag(Rhs::new(value.clone())));
                }
            }
            else if !flag.is_empty() {
                self.params.insert(Param::Long((*flag).to_owned()), Value::Flag(Rhs::new(value.clone())));
            }
        }
        self
    }

    /// Builder method for adding both short and long opts
    ///
    /// Opts are parameters that hold assigned values. They are used
    /// for when certain features or options have been enabled for the application
    ///
    /// For example
    /// > ls -T 4 --color=always
    ///   ^  ^    ^
    ///   |  |    |
    ///   |  |    `-- A long opt to enable the use of color with value `always`.
    ///   |  `-- A short opt to set tab size to the value `4`.
    ///   `-- The command to list files.
    pub fn add_opt(mut self, short: &str, long: &str) -> Self {
        let value = Rc::new(RefCell::new("".to_owned()));
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::new_opt(value.clone()));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::new_opt(value));
        }
        self
    }

    pub fn add_opt_default(mut self, short: &str, long: &str, default: &str) -> Self {
        let value = Rc::new(RefCell::new(default.to_owned()));
        if let Some(short) = short.chars().next() {
            self.params.insert(Param::Short(short), Value::new_opt(value.clone()));
        }
        if !long.is_empty() {
            self.params.insert(Param::Long(long.to_owned()), Value::new_opt(value));
        }
        self
    }

    /// Start parsing user inputted args for which flags and opts are used at
    /// runtime. The rest of the args that are not associated to opts get added
    /// to `ArgParser.args`.
    pub fn parse<A: Iterator<Item=String>>(&mut self, args: A) {
        let mut args = args.skip(1);
        while let Some(arg) = args.next() {
            if arg.starts_with("--") {
                // Remove both dashes
                let arg = &arg[2..];
                if arg.is_empty() {
                    //Arg `--` means we are done parsing args, collect the rest
                    self.args.extend(args);
                    break;
                }
                if let Some(i) = arg.find('=') {
                    let (lhs, rhs) = arg.split_at(i);
                    let rhs = &rhs[1..]; // slice off the `=` char
                    match self.params.get_mut(lhs) {
                        Some(&mut Value::Opt { rhs: ref mut opt_rhs, ref mut found }) => {
                            if (*opt_rhs.value).borrow().is_empty() {
                                opt_rhs.occurrences = 1;
                            }
                            else {
                                opt_rhs.occurrences += 1;
                            }
                            (*opt_rhs.value).borrow_mut().clear();
                            (*opt_rhs.value).borrow_mut().push_str(rhs);
                            *found = true;
                        }
                        _ => self.invalid.push(Param::Long(lhs.to_owned())),
                    }
                }
                else {
                    match self.params.get_mut(arg) {
                        Some(&mut Value::Flag(ref mut rhs)) => {
                            *(*rhs.value).borrow_mut() = true;
                            rhs.occurrences += 1;
                        }
                        Some(&mut Value::Opt { ref mut rhs, ref mut found }) => {
                            rhs.occurrences += 1;
                            *found = true;
                        }
                        _ => self.invalid.push(Param::Long(arg.to_owned())),
                    }
                }
            }
            else if arg.starts_with("-") {
                let mut chars = arg[1..].chars();
                while let Some(ch) = chars.next() {
                    match self.params.get_mut(&ch) {
                        Some(&mut Value::Flag(ref mut rhs)) => {
                            *(*rhs.value).borrow_mut() = true;
                            rhs.occurrences += 1;
                        }
                        Some(&mut Value::Opt { ref mut rhs, ref mut found }) => {
                            let rest: String = chars.collect();
                            if !rest.is_empty() {
                                *(*rhs.value).borrow_mut() = rest;
                                *found = true;
                            } else {
                                *(*rhs.value).borrow_mut() = args.next().map(|a| {*found = true; a}).unwrap_or("".to_owned());
                            }
                            break;
                        }
                        None => self.invalid.push(Param::Short(ch)),
                    }
                }
            }
            else {
                self.args.push(arg);
            }
        }
    }

    /// Get the number of times a flag or opt has been found after parsing.
    pub fn count
(&self, name: &P) -> usize
        where Param: Borrow

    {
        match self.params.get(name) {
            Some(&Value::Flag(ref rhs)) => rhs.occurrences,
            Some(&Value::Opt { ref rhs, .. }) => rhs.occurrences,
            _ => 0,
        }
    }

    /// Check if a flag or opt has been found after initialization.
    pub fn found
(&self, name: &P) -> bool
        where Param: Borrow

    {
        match self.params.get(name) {
            Some(&Value::Flag(ref rhs)) => *(*rhs.value).borrow_mut(),
            Some(&Value::Opt { found, .. }) => found,
            _ => false,
        }
    }

    /// Modify the state of a flag. Use `true` if the flag is to be enabled. Use `false` to
    /// disable its use.
    pub fn flag<F: Hash + Eq + ?Sized>(&mut self, flag: &F) -> RefMut<bool>
        where Param: Borrow<F>
    {
        if let Some(&mut Value::Flag(ref mut rhs)) = self.params.get_mut(flag) {
            return (*rhs.value).borrow_mut();
        }
        self.garbage.0.borrow_mut()
    }

    /// Modify the state value of an opt. Use `Some(String)` to set if the opt is to be enabled and
    /// has been assigned a value from `String`. Use `None` to disable the opt's use.
    pub fn opt<O: Hash + Eq + ?Sized>(&mut self, opt: &O) -> RefMut<String>
        where Param: Borrow<O>
    {
        if let Some(&mut Value::Opt { ref mut rhs, .. }) = self.params.get_mut(opt) {
            return (*rhs.value).borrow_mut();
        }
        self.garbage.1.borrow_mut()
    }

    /// Get the value of an Opt. If it has been set or defaulted, it will return a `Some(String)`
    /// value otherwise it will return None.
    pub fn get_opt<O: Hash + Eq + ?Sized>(&self, opt: &O) -> Option<String>
        where Param: Borrow<O>
    {
        if let Some(&Value::Opt { ref rhs, .. }) = self.params.get(opt) {
            return Some((*rhs.value).borrow().clone());
        }
        None
    }

    pub fn found_invalid(&self) -> Result<(), String> {
        if self.invalid.is_empty() {
            return Ok(());
        }

        let mut and: bool = false;
        let mut output =
            if self.invalid.len() == 1 {
                "Invalid parameter"
            } else {
                and = true;
                "Invalid parameters"
            }.to_owned();

        let mut iter = self.invalid.iter().peekable();
        while let Some(param) = iter.next() {
            match param {
                &Param::Short(ch) => {
                    output += " '-";
                    output.push(ch);
                    output.push('\'');
                }
                &Param::Long(ref s) => {
                    output += " '--";
                    output += s;
                    output.push('\'');
                }
            }
            if and && iter.peek().is_some() {
                output += " and";
            }
        }
        output.push('\n');
        Err(output)
    }
}

pub fn to_human_readable_string(size: u64) -> String {
    if size < 1024 {
        return format!("{}", size);
    }

    static UNITS: [&'static str; 7] = ["", "K", "M", "G", "T", "P", "E"];

    let sizef = size as f64;
    let digit_groups = (sizef.log10() / 1024f64.log10()) as i32;
    format!("{:.1}{}",
            sizef / 1024f64.powf(digit_groups as f64),
            UNITS[digit_groups as usize])
}

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

    #[test]
    fn stop_parsing() {
        let args = vec![String::from("binname"), String::from("-a"), String::from("--"), String::from("-v")];
        let mut parser = ArgParser::new(2);
        parser = parser.add_flag("a", "")
                       .add_flag("v", "");
        parser.parse(args.into_iter());
        assert!(parser.found(&'a'));
        assert!(!parser.found(&'v'));
        assert!(parser.args[0] == "-v");
    }

    #[test]
    fn short_opts() {
        let args = vec![String::from("binname"), String::from("-asdf"), String::from("-f"), String::from("foo")];
        let mut parser = ArgParser::new(4);
        parser = parser.add_flag("a", "")
                       .add_flag("d", "")
                       .add_opt("s", "")
                       .add_opt("f", "");
        parser.parse(args.into_iter());
        assert!(parser.found(&'a'));
        assert!(!parser.found(&'d'));
        assert!(parser.get_opt(&'s') == Some(String::from("df")));
        assert!(parser.get_opt(&'f') == Some(String::from("foo")));
    }

    #[test]
    fn long_opts() {
        let args = vec![String::from("binname"), String::from("--foo=bar")];
        let mut parser = ArgParser::new(4);
        parser = parser.add_opt("", "foo");
        parser.parse(args.into_iter());
        assert!(parser.get_opt("foo") == Some(String::from("bar")));
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2013-2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![crate_name = "glib_2_0_sys"]
#![crate_type = "lib"]

#![allow(missing_copy_implementations)]

extern crate libc;

pub mod types;

use types::{gboolean, gchar, gint, gpointer};

#[repr(C)]
pub struct GError {
    pub domain: GQuark,
    pub code: gint,
    pub message: *const gchar
}

#[repr(C)]
pub struct GMainContext;

#[repr(C)]
pub struct GMainLoop;

pub type GQuark = u32;

#[repr(C)]
pub struct GList {
    pub data: gpointer,
    pub next: *mut GList,
    pub prev: *mut GList
}

extern {
    pub fn g_free(mem: gpointer);
    pub fn g_error_copy(error: *const GError) -> *mut GError;
    pub fn g_error_free(error: *mut GError);
    pub fn g_error_new_literal(domain: GQuark, code: gint, message: *const gchar) -> *mut GError;
    pub fn g_main_context_new() -> *mut GMainContext;
    pub fn g_main_context_ref(context: *mut GMainContext) -> *mut GMainContext;
    pub fn g_main_context_unref(context: *mut GMainContext);
    pub fn g_main_context_default() -> *mut GMainContext;
    pub fn g_main_context_push_thread_default(context: *mut GMainContext);
    pub fn g_main_context_pop_thread_default(context: *mut GMainContext);
    pub fn g_main_loop_new(ctx: *mut GMainContext, is_running: gboolean) -> *mut GMainLoop;
    pub fn g_main_loop_ref(l: *mut GMainLoop) -> *mut GMainLoop;
    pub fn g_main_loop_unref(l: *mut GMainLoop);
    pub fn g_main_loop_get_context(l: *mut GMainLoop) -> *mut GMainContext;
    pub fn g_main_loop_run(l: *mut GMainLoop);
    pub fn g_main_loop_quit(l: *mut GMainLoop);
    pub fn g_quark_from_static_string(string: *const gchar) -> GQuark;
    pub fn g_quark_to_string(quark: GQuark) -> *const gchar;
    pub fn g_strdup(str: *const gchar) -> *mut gchar;
}
<commit_msg>Add g_main_context_invoke_full, related types, and priority constants<commit_after>// Copyright (C) 2013-2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![crate_name = "glib_2_0_sys"]
#![crate_type = "lib"]

#![allow(missing_copy_implementations)]

extern crate libc;

pub mod types;

use types::{gboolean, gchar, gint, gpointer};

#[repr(C)]
pub struct GError {
    pub domain: GQuark,
    pub code: gint,
    pub message: *const gchar
}

#[repr(C)]
pub struct GMainContext;

#[repr(C)]
pub struct GMainLoop;

pub type GQuark = u32;

#[repr(C)]
pub struct GList {
    pub data: gpointer,
    pub next: *mut GList,
    pub prev: *mut GList
}

pub type GDestroyNotify = extern "C" fn (gpointer);
pub type GSourceFunc = extern "C" fn (gpointer) -> gboolean;

pub const G_PRIORITY_DEFAULT: gint = 0;
pub const G_PRIORITY_DEFAULT_IDLE: gint = 200;
pub const G_PRIORITY_HIGH: gint = -100;
pub const G_PRIORITY_HIGH_IDLE: gint = 100;
pub const G_PRIORITY_LOW: gint = 300;

extern {
    pub fn g_free(mem: gpointer);
    pub fn g_error_copy(error: *const GError) -> *mut GError;
    pub fn g_error_free(error: *mut GError);
    pub fn g_error_new_literal(domain: GQuark, code: gint, message: *const gchar) -> *mut GError;
    pub fn g_main_context_new() -> *mut GMainContext;
    pub fn g_main_context_ref(context: *mut GMainContext) -> *mut GMainContext;
    pub fn g_main_context_unref(context: *mut GMainContext);
    pub fn g_main_context_default() -> *mut GMainContext;
    pub fn g_main_context_invoke_full(context: *mut GMainContext, priority: gint, function: GSourceFunc, data: gpointer, notify: Option<GDestroyNotify>);
    pub fn g_main_context_push_thread_default(context: *mut GMainContext);
    pub fn g_main_context_pop_thread_default(context: *mut GMainContext);
    pub fn g_main_loop_new(ctx: *mut GMainContext, is_running: gboolean) -> *mut GMainLoop;
    pub fn g_main_loop_ref(l: *mut GMainLoop) -> *mut GMainLoop;
    pub fn g_main_loop_unref(l: *mut GMainLoop);
    pub fn g_main_loop_get_context(l: *mut GMainLoop) -> *mut GMainContext;
    pub fn g_main_loop_run(l: *mut GMainLoop);
    pub fn g_main_loop_quit(l: *mut GMainLoop);
    pub fn g_quark_from_static_string(string: *const gchar) -> GQuark;
    pub fn g_quark_to_string(quark: GQuark) -> *const gchar;
    pub fn g_strdup(str: *const gchar) -> *mut gchar;
}
<|endoftext|>


<commit_before>#![experimental]
#![feature(slicing_syntax)]

use std::mem;

/// Calculate the crc64 checksum of the given data, starting with the given crc.
///
/// Implements the CRC64 used by Redis, which is the variant with "Jones" coefficients and init value of 0.
///
/// Specification of this CRC64 variant follows:
///
/// ```text
/// Name: crc-64-jones
/// Width: 64 bites
/// Poly: 0xad93d23594c935a9
/// Reflected In: True
/// Xor_In: 0xffffffffffffffff
/// Reflected_Out: True
/// Xor_Out: 0x0
/// Check("123456789"): 0xe9c6d914c4b8d9ca
/// ```
///
/// Example:
///
/// ```rust
/// crc64::crc64(0, "123456789".as_bytes());
/// ```

use crc_table::CRC64_TAB;
mod crc_table;

fn crc_reflect(data: u64, len: usize) -> u64 {
    let mut data = data;
    let mut ret = data & 0x01;

    let mut i = 1us;
    while i < len {
        data >>= 1;
        ret = (ret << 1) | (data & 0x01);
        i+=1;
    }

    ret
}

fn crc64_trivial(crc: u64, in_data: &[u8]) -> u64 {
    let mut crc = crc;
    let len = in_data.len();

    let poly : u64 = 0xad93d23594c935a9;

    let mut bit : bool;

    let mut offset = 0us;

    while offset < len {
        let c = in_data[offset];
        let mut i = 0x01;
        while i & 0xff != 0x0 {
            bit = crc & 0x8000000000000000 != 0x0;
            if c & i != 0x0 {
                bit = !bit;
            }
            crc <<= 1;
            if bit {
                crc ^= poly;
            }
            i <<= 1;
        }
        crc &= 0xffffffffffffffff;
        offset+=1;
    }
    crc = crc & 0xffffffffffffffff;

    return crc_reflect(crc, 64) ^ 0x0000000000000000;
}

pub fn crc64_init() -> Vec<Vec<u64>> {
    let mut crc : u64;

    let mut table : Vec<Vec<u64>> = Vec::with_capacity(8);

    for _ in (0..8) {
        table.push(Vec::with_capacity(256));
    };

    for n in (0..256) {
        table[0].push(crc64_trivial(0, vec![n as u8].as_slice()));
        table[1].push(0);
        table[2].push(0);
        table[3].push(0);
        table[4].push(0);
        table[5].push(0);
        table[6].push(0);
        table[7].push(0);
    }

    for n in (0..256) {
        crc = table[0][n];
        for k in (1..8) {
            let idx  = (crc as usize) & 0xff;
            crc = table[0][idx] ^ (crc >> 8);
            table[k][n] = crc;
        }
    };

    table
}

// transmute slice of 8 u8 values to one u64 (drop the length)
macro_rules! slice_to_long {
    ($curVec:expr) => {
        {
            unsafe {
                let (tmp, _) : (*const u64, u64) = mem::transmute(&$curVec);
                *tmp
            }
        }
    }
}

pub fn crc64(crc: u64, data: &[u8]) -> u64 {
    let mut crc = crc;
    let mut len = data.len();
    let mut offset = 0us;

    while len >= 8 {
        crc ^= slice_to_long!(data[offset..(offset+8)]);
        crc = CRC64_TAB[7][(crc & 0xff) as usize] ^
              CRC64_TAB[6][((crc >> 8) & 0xff) as usize] ^
              CRC64_TAB[5][((crc >> 16) & 0xff) as usize] ^
              CRC64_TAB[4][((crc >> 24) & 0xff) as usize] ^
              CRC64_TAB[3][((crc >> 32) & 0xff) as usize] ^
              CRC64_TAB[2][((crc >> 40) & 0xff) as usize] ^
              CRC64_TAB[1][((crc >> 48) & 0xff) as usize] ^
              CRC64_TAB[0][(crc >> 56) as usize];

        offset += 8;
        len -= 8;
    }

    while len > 0 {
        crc = CRC64_TAB[0][((crc ^ data[offset] as u64) & 0xff) as usize] ^ (crc >> 8);
        offset += 1;
        len -= 1;
    }

    crc
}

#[test]
fn test_crc64_works() {
    assert_eq!(0xe9c6d914c4b8d9ca, crc64(0, "123456789".as_bytes()))
}
<commit_msg>Make type explicit<commit_after>#![experimental]
#![feature(slicing_syntax)]

use std::mem;

/// Calculate the crc64 checksum of the given data, starting with the given crc.
///
/// Implements the CRC64 used by Redis, which is the variant with "Jones" coefficients and init value of 0.
///
/// Specification of this CRC64 variant follows:
///
/// ```text
/// Name: crc-64-jones
/// Width: 64 bites
/// Poly: 0xad93d23594c935a9
/// Reflected In: True
/// Xor_In: 0xffffffffffffffff
/// Reflected_Out: True
/// Xor_Out: 0x0
/// Check("123456789"): 0xe9c6d914c4b8d9ca
/// ```
///
/// Example:
///
/// ```rust
/// crc64::crc64(0, "123456789".as_bytes());
/// ```

use crc_table::CRC64_TAB;
mod crc_table;

fn crc_reflect(data: u64, len: usize) -> u64 {
    let mut data = data;
    let mut ret = data & 0x01;

    let mut i = 1us;
    while i < len {
        data >>= 1;
        ret = (ret << 1) | (data & 0x01);
        i+=1;
    }

    ret
}

fn crc64_trivial(crc: u64, in_data: &[u8]) -> u64 {
    let mut crc = crc;
    let len = in_data.len();

    let poly : u64 = 0xad93d23594c935a9;

    let mut bit : bool;

    let mut offset = 0us;

    while offset < len {
        let c = in_data[offset];
        let mut i = 0x01;
        while i & 0xff != 0x0 {
            bit = crc & 0x8000000000000000 != 0x0;
            if c & i != 0x0 {
                bit = !bit;
            }
            crc <<= 1;
            if bit {
                crc ^= poly;
            }
            i <<= 1;
        }
        crc &= 0xffffffffffffffff;
        offset+=1;
    }
    crc = crc & 0xffffffffffffffff;

    return crc_reflect(crc, 64) ^ 0x0000000000000000;
}

pub fn crc64_init() -> Vec<Vec<u64>> {
    let mut crc : u64;

    let mut table : Vec<Vec<u64>> = Vec::with_capacity(8);

    for _ in (0..8) {
        table.push(Vec::with_capacity(256));
    };

    for n in (0us..256) {
        table[0].push(crc64_trivial(0, vec![n as u8].as_slice()));
        table[1].push(0);
        table[2].push(0);
        table[3].push(0);
        table[4].push(0);
        table[5].push(0);
        table[6].push(0);
        table[7].push(0);
    }

    for n in (0us..256) {
        crc = table[0][n];
        for k in (1us..8) {
            let idx  = (crc as usize) & 0xff;
            crc = table[0][idx] ^ (crc >> 8);
            table[k][n] = crc;
        }
    };

    table
}

// transmute slice of 8 u8 values to one u64 (drop the length)
macro_rules! slice_to_long {
    ($curVec:expr) => {
        {
            unsafe {
                let (tmp, _) : (*const u64, u64) = mem::transmute(&$curVec);
                *tmp
            }
        }
    }
}

pub fn crc64(crc: u64, data: &[u8]) -> u64 {
    let mut crc = crc;
    let mut len = data.len();
    let mut offset = 0us;

    while len >= 8 {
        crc ^= slice_to_long!(data[offset..(offset+8)]);
        crc = CRC64_TAB[7][(crc & 0xff) as usize] ^
              CRC64_TAB[6][((crc >> 8) & 0xff) as usize] ^
              CRC64_TAB[5][((crc >> 16) & 0xff) as usize] ^
              CRC64_TAB[4][((crc >> 24) & 0xff) as usize] ^
              CRC64_TAB[3][((crc >> 32) & 0xff) as usize] ^
              CRC64_TAB[2][((crc >> 40) & 0xff) as usize] ^
              CRC64_TAB[1][((crc >> 48) & 0xff) as usize] ^
              CRC64_TAB[0][(crc >> 56) as usize];

        offset += 8;
        len -= 8;
    }

    while len > 0 {
        crc = CRC64_TAB[0][((crc ^ data[offset] as u64) & 0xff) as usize] ^ (crc >> 8);
        offset += 1;
        len -= 1;
    }

    crc
}

#[test]
fn test_crc64_works() {
    assert_eq!(0xe9c6d914c4b8d9ca, crc64(0, "123456789".as_bytes()))
}
<|endoftext|>


<commit_before>//! A wrapper around the uchardet library.  Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

#![license = "Public domain (Unlicense)"]
#![unstable]
#![deny(missing_docs)]

extern crate libc;
extern crate "uchardet-sys" as ffi;

use libc::size_t;
use std::error::Error;
use std::result::Result;
use std::c_str::CString;

/// An error occurred while trying to detect the character encoding.
#[unstable = "Needs review"]
#[deriving(Show)]
pub struct EncodingDetectorError {
    message: String
}

#[unstable = "Needs review"]
impl Error for EncodingDetectorError {
    fn description(&self) -> &str { "encoding detector error" }
    fn detail(&self) -> Option<String> { Some(self.message.clone()) }
    fn cause(&self) -> Option<&Error> { None }
}

/// Either a return value, or an encoding detection error.
#[unstable = "Needs review"]
pub type EncodingDetectorResult<T> = Result<T, EncodingDetectorError>;

/// Detects the encoding of text using the uchardet library.
#[unstable = "Needs review"]
pub struct EncodingDetector {
    ptr: ffi::uchardet_t
}

impl EncodingDetector {
    /// Return the name of the charset used in `data`, or `None` if the
    /// charset is ASCII or if the encoding can't be detected. (Yes, this
    /// API is weird, and we may offer a better alternative in the future.)
    ///
    /// ```
    /// use uchardet::EncodingDetector;
    ///
    /// assert_eq!(None, EncodingDetector::detect("ascii".as_bytes()).unwrap());
    /// assert_eq!(Some("UTF-8".to_string()),
    ///            EncodingDetector::detect("français".as_bytes()).unwrap());
    /// assert_eq!(Some("windows-1252".to_string()),
    ///            EncodingDetector::detect(&[0x66u8, 0x72, 0x61, 0x6e, 0xe7,
    ///                                       0x61, 0x69, 0x73]).unwrap());
    /// ```
    #[unstable = "Needs review"]
    pub fn detect(data: &[u8]) -> EncodingDetectorResult<Option<String>> {
        let mut detector = EncodingDetector::new();
        try!(detector.handle_data(data));
        detector.data_end();
        Ok(detector.charset())
    }

    /// Create a new EncodingDetector.
    #[unstable = "Needs review"]
    pub fn new() -> EncodingDetector {
        let ptr = unsafe { ffi::uchardet_new() };
        assert!(ptr.is_not_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector.  This is a no-op if a
    /// charset has been detected.
    #[unstable = "The underlying API is poorly documented."]
    pub fn handle_data(&mut self, data: &[u8]) -> EncodingDetectorResult<()> {
        let result = unsafe {
            ffi::uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                      data.len() as size_t)
        };
        match result {
            0 => Ok(()),
            _ => {
                let msg =  "Error handling data".to_string();
                Err(EncodingDetectorError{message: msg})
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding.  This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain.  From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    #[unstable = "The underlying API is poorly documented."]
    pub fn data_end(&mut self) {
        unsafe { ffi::uchardet_data_end(self.ptr); }
    }

    /// Reset the detector's internal state.
    #[unstable = "The underlying API is poorly documented."]
    pub fn reset(&mut self) {
        unsafe { ffi::uchardet_reset(self.ptr); }
    }

    /// Get the decoder's current best guess as to the encoding.  Returns
    /// `None` on error, or if the data appears to be ASCII.
    #[unstable = "The underlying API is poorly documented."]
    pub fn charset(&self) -> Option<String> {
        unsafe {
            let internal_str = ffi::uchardet_get_charset(self.ptr);
            assert!(internal_str.is_not_null());
            let c_str = CString::new(internal_str, false);
            match c_str.as_str() {
                None =>
                    panic!("uchardet_get_charset returned invalid value"),
                Some("") => None,
                Some(encoding) => Some(encoding.to_string())
            }
        }
    }
}

#[unstable = "Needs review"]
impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { ffi::uchardet_delete(self.ptr) };
    }
}
<commit_msg>Update stability and license metadata<commit_after>//! A wrapper around the uchardet library.  Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

#![license = "Public domain (Unlicense) + Mozilla Public License 1.1"]
#![unstable = "Needs review"]
#![deny(missing_docs)]

extern crate libc;
extern crate "uchardet-sys" as ffi;

use libc::size_t;
use std::error::Error;
use std::result::Result;
use std::c_str::CString;

/// An error occurred while trying to detect the character encoding.
#[deriving(Show)]
pub struct EncodingDetectorError {
    message: String
}

impl Error for EncodingDetectorError {
    fn description(&self) -> &str { "encoding detector error" }
    fn detail(&self) -> Option<String> { Some(self.message.clone()) }
    fn cause(&self) -> Option<&Error> { None }
}

/// Either a return value, or an encoding detection error.
pub type EncodingDetectorResult<T> = Result<T, EncodingDetectorError>;

/// Detects the encoding of text using the uchardet library.
pub struct EncodingDetector {
    ptr: ffi::uchardet_t
}

impl EncodingDetector {
    /// Return the name of the charset used in `data`, or `None` if the
    /// charset is ASCII or if the encoding can't be detected. (Yes, this
    /// API is weird, and we may offer a better alternative in the future.)
    ///
    /// ```
    /// use uchardet::EncodingDetector;
    ///
    /// assert_eq!(None, EncodingDetector::detect("ascii".as_bytes()).unwrap());
    /// assert_eq!(Some("UTF-8".to_string()),
    ///            EncodingDetector::detect("français".as_bytes()).unwrap());
    /// assert_eq!(Some("windows-1252".to_string()),
    ///            EncodingDetector::detect(&[0x66u8, 0x72, 0x61, 0x6e, 0xe7,
    ///                                       0x61, 0x69, 0x73]).unwrap());
    /// ```
    pub fn detect(data: &[u8]) -> EncodingDetectorResult<Option<String>> {
        let mut detector = EncodingDetector::new();
        try!(detector.handle_data(data));
        detector.data_end();
        Ok(detector.charset())
    }

    /// Create a new EncodingDetector.
    pub fn new() -> EncodingDetector {
        let ptr = unsafe { ffi::uchardet_new() };
        assert!(ptr.is_not_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector.  This is a no-op if a
    /// charset has been detected.
    #[experimental = "The underlying API is poorly documented."]
    pub fn handle_data(&mut self, data: &[u8]) -> EncodingDetectorResult<()> {
        let result = unsafe {
            ffi::uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                      data.len() as size_t)
        };
        match result {
            0 => Ok(()),
            _ => {
                let msg =  "Error handling data".to_string();
                Err(EncodingDetectorError{message: msg})
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding.  This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain.  From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    #[experimental = "The underlying API is poorly documented."]
    pub fn data_end(&mut self) {
        unsafe { ffi::uchardet_data_end(self.ptr); }
    }

    /// Reset the detector's internal state.
    #[experimental = "The underlying API is poorly documented."]
    pub fn reset(&mut self) {
        unsafe { ffi::uchardet_reset(self.ptr); }
    }

    /// Get the decoder's current best guess as to the encoding.  Returns
    /// `None` on error, or if the data appears to be ASCII.
    #[experimental = "The underlying API is poorly documented."]
    pub fn charset(&self) -> Option<String> {
        unsafe {
            let internal_str = ffi::uchardet_get_charset(self.ptr);
            assert!(internal_str.is_not_null());
            let c_str = CString::new(internal_str, false);
            match c_str.as_str() {
                None =>
                    panic!("uchardet_get_charset returned invalid value"),
                Some("") => None,
                Some(encoding) => Some(encoding.to_string())
            }
        }
    }
}

impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { ffi::uchardet_delete(self.ptr) };
    }
}
<|endoftext|>


<commit_before>//! A TOML-parsing library
//!
//! This library is an implementation in Rust of a parser for TOML configuration
//! files [1]. It is focused around high quality errors including specific spans
//! and detailed error messages when things go wrong.
//!
//! This implementation currently passes the language agnostic [test suite][2].
//!
//! # Example
//!
//! ```
//! let toml = r#"
//!     [test]
//!     foo = "bar"
//! "#;
//!
//! let value = toml::Parser::new(toml).parse().unwrap();
//! println!("{:?}", value);
//! ```
//!
//! # Conversions
//!
//! This library also supports using the standard `Encodable` and `Decodable`
//! traits with TOML values. This library provides the following conversion
//! capabilities:
//!
//! * `String` => `toml::Value` - via `Parser`
//! * `toml::Value` => `String` - via `Display`
//! * `toml::Value` => rust object - via `Decoder`
//! * rust object => `toml::Value` - via `Encoder`
//!
//! Convenience functions for performing multiple conversions at a time are also
//! provided.
//!
//! [1]: https://github.com/mojombo/toml
//! [2]: https://github.com/BurntSushi/toml-test

#![doc(html_root_url = "http://alexcrichton.com/toml-rs")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;

use std::collections::BTreeMap;
use std::str::FromStr;

pub use parser::{Parser, ParserError};

#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::encoder::{Encoder, Error, encode, encode_str};
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::decoder::{Decoder, DecodeError, DecodeErrorKind, decode, decode_str};

mod parser;
mod display;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod encoder;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod decoder;

/// Representation of a TOML value.
#[derive(PartialEq, Clone, Debug)]
#[allow(missing_docs)]
pub enum Value {
    String(String),
    Integer(i64),
    Float(f64),
    Boolean(bool),
    Datetime(String),
    Array(Array),
    Table(Table),
}

/// Type representing a TOML array, payload of the Value::Array variant
pub type Array = Vec<Value>;

/// Type representing a TOML table, payload of the Value::Table variant
pub type Table = BTreeMap<String, Value>;

impl Value {
    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::String(..), &Value::String(..)) |
            (&Value::Integer(..), &Value::Integer(..)) |
            (&Value::Float(..), &Value::Float(..)) |
            (&Value::Boolean(..), &Value::Boolean(..)) |
            (&Value::Datetime(..), &Value::Datetime(..)) |
            (&Value::Array(..), &Value::Array(..)) |
            (&Value::Table(..), &Value::Table(..)) => true,

            _ => false,
        }
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            Value::String(..) => "string",
            Value::Integer(..) => "integer",
            Value::Float(..) => "float",
            Value::Boolean(..) => "boolean",
            Value::Datetime(..) => "datetime",
            Value::Array(..) => "array",
            Value::Table(..) => "table",
        }
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str(&self) -> Option<&str> {
        match *self { Value::String(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self { Value::Integer(i) => Some(i), _ => None }
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self { Value::Float(f) => Some(f), _ => None }
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self { Value::Boolean(b) => Some(b), _ => None }
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime(&self) -> Option<&str> {
        match *self { Value::Datetime(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the array value if it is an array.
    pub fn as_slice(&self) -> Option<&[Value]> {
        match *self { Value::Array(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table(&self) -> Option<&Table> {
        match *self { Value::Table(ref s) => Some(s), _ => None }
    }

    /// Lookups for value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let value: toml::Value = toml.parse().unwrap();
    ///
    /// let foo = value.lookup("test.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "bar");
    ///
    /// let foo = value.lookup("values.1.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "qux");
    ///
    /// let no_bar = value.lookup("test.bar");
    /// assert_eq!(no_bar.is_none(), true);
    /// ```
    pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
        let mut cur_value = self;
        if path.len() == 0 {
            return Some(cur_value)
        }

        for key in path.split('.') {
            match *cur_value {
                Value::Table(ref hm) => {
                    match hm.get(key) {
                        Some(v) => cur_value = v,
                        None => return None
                    }
                },
                Value::Array(ref v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur_value = &v[idx],
                        _ => return None
                    }
                },
                _ => return None
            }
        };

        Some(cur_value)
    }

    /// Lookups for mutable value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let mut value: toml::Value = toml.parse().unwrap();
    /// {
    ///    let string = value.lookup_mut("test.foo").unwrap();
    ///    assert_eq!(string, &mut toml::Value::String(String::from("bar")));
    ///    *string = toml::Value::String(String::from("foo"));
    /// }
    /// let result = value.lookup_mut("test.foo").unwrap();
    /// assert_eq!(result.as_str().unwrap(), "foo");
    /// ```
    pub fn lookup_mut(&mut self, path: &str) -> Option<&mut Value> {
        let mut cur = self;
        if path.len() == 0 {
            return Some(cur)
        }

        for key in path.split('.') {
            let tmp = cur;
            match *tmp {
                Value::Table(ref mut hm) => {
                    match hm.get_mut(key) {
                        Some(v) => cur = v,
                        None => return None
                    }
                }
                Value::Array(ref mut v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur = &mut v[idx],
                        _ => return None
                    }
                }
                _ => return None
           }
        }
        Some(cur)
    }
}

impl FromStr for Value {
    type Err = Vec<ParserError>;
    fn from_str(s: &str) -> Result<Value, Vec<ParserError>> {
        let mut p = Parser::new(s);
        match p.parse().map(Value::Table) {
            Some(n) => Ok(n),
            None => Err(p.errors),
        }
    }
}

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

    #[test]
    fn lookup_mut_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let test_foo = value.lookup_mut("test.foo").unwrap();
            assert_eq!(test_foo.as_str().unwrap(), "bar");
        }

        {
            let foo1 = value.lookup_mut("values.1.foo").unwrap();
            assert_eq!(foo1.as_str().unwrap(), "qux");
        }

        assert!(value.lookup_mut("test.bar").is_none());
        assert!(value.lookup_mut("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_mut_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let foo = value.lookup_mut("test.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.100.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.str.foo");
            assert!(foo.is_none());
        }
    }

    #[test]
    fn lookup_mut_self() {
        let mut value: Value = r#"foo = "bar""#.parse().unwrap();

        {
            let foo = value.lookup_mut("foo").unwrap();
            assert_eq!(foo.as_str().unwrap(), "bar");
        }

        let foo = value.lookup_mut("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup_mut("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let value: Value = toml.parse().unwrap();

        let test_foo = value.lookup("test.foo").unwrap();
        assert_eq!(test_foo.as_str().unwrap(), "bar");

        let foo1 = value.lookup("values.1.foo").unwrap();
        assert_eq!(foo1.as_str().unwrap(), "qux");

        assert!(value.lookup("test.bar").is_none());
        assert!(value.lookup("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let value: Value = toml.parse().unwrap();

        let foo = value.lookup("test.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.100.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.str.foo");
        assert!(foo.is_none());
    }

    #[test]
    fn lookup_self() {
        let value: Value = r#"foo = "bar""#.parse().unwrap();

        let foo = value.lookup("foo").unwrap();
        assert_eq!(foo.as_str().unwrap(), "bar");

        let foo = value.lookup("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }
}
<commit_msg>Add a test to see if the table's contents have changed<commit_after>//! A TOML-parsing library
//!
//! This library is an implementation in Rust of a parser for TOML configuration
//! files [1]. It is focused around high quality errors including specific spans
//! and detailed error messages when things go wrong.
//!
//! This implementation currently passes the language agnostic [test suite][2].
//!
//! # Example
//!
//! ```
//! let toml = r#"
//!     [test]
//!     foo = "bar"
//! "#;
//!
//! let value = toml::Parser::new(toml).parse().unwrap();
//! println!("{:?}", value);
//! ```
//!
//! # Conversions
//!
//! This library also supports using the standard `Encodable` and `Decodable`
//! traits with TOML values. This library provides the following conversion
//! capabilities:
//!
//! * `String` => `toml::Value` - via `Parser`
//! * `toml::Value` => `String` - via `Display`
//! * `toml::Value` => rust object - via `Decoder`
//! * rust object => `toml::Value` - via `Encoder`
//!
//! Convenience functions for performing multiple conversions at a time are also
//! provided.
//!
//! [1]: https://github.com/mojombo/toml
//! [2]: https://github.com/BurntSushi/toml-test

#![doc(html_root_url = "http://alexcrichton.com/toml-rs")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;

use std::collections::BTreeMap;
use std::str::FromStr;

pub use parser::{Parser, ParserError};

#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::encoder::{Encoder, Error, encode, encode_str};
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::decoder::{Decoder, DecodeError, DecodeErrorKind, decode, decode_str};

mod parser;
mod display;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod encoder;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod decoder;

/// Representation of a TOML value.
#[derive(PartialEq, Clone, Debug)]
#[allow(missing_docs)]
pub enum Value {
    String(String),
    Integer(i64),
    Float(f64),
    Boolean(bool),
    Datetime(String),
    Array(Array),
    Table(Table),
}

/// Type representing a TOML array, payload of the Value::Array variant
pub type Array = Vec<Value>;

/// Type representing a TOML table, payload of the Value::Table variant
pub type Table = BTreeMap<String, Value>;

impl Value {
    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::String(..), &Value::String(..)) |
            (&Value::Integer(..), &Value::Integer(..)) |
            (&Value::Float(..), &Value::Float(..)) |
            (&Value::Boolean(..), &Value::Boolean(..)) |
            (&Value::Datetime(..), &Value::Datetime(..)) |
            (&Value::Array(..), &Value::Array(..)) |
            (&Value::Table(..), &Value::Table(..)) => true,

            _ => false,
        }
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            Value::String(..) => "string",
            Value::Integer(..) => "integer",
            Value::Float(..) => "float",
            Value::Boolean(..) => "boolean",
            Value::Datetime(..) => "datetime",
            Value::Array(..) => "array",
            Value::Table(..) => "table",
        }
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str(&self) -> Option<&str> {
        match *self { Value::String(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self { Value::Integer(i) => Some(i), _ => None }
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self { Value::Float(f) => Some(f), _ => None }
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self { Value::Boolean(b) => Some(b), _ => None }
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime(&self) -> Option<&str> {
        match *self { Value::Datetime(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the array value if it is an array.
    pub fn as_slice(&self) -> Option<&[Value]> {
        match *self { Value::Array(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table(&self) -> Option<&Table> {
        match *self { Value::Table(ref s) => Some(s), _ => None }
    }

    /// Lookups for value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let value: toml::Value = toml.parse().unwrap();
    ///
    /// let foo = value.lookup("test.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "bar");
    ///
    /// let foo = value.lookup("values.1.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "qux");
    ///
    /// let no_bar = value.lookup("test.bar");
    /// assert_eq!(no_bar.is_none(), true);
    /// ```
    pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
        let mut cur_value = self;
        if path.len() == 0 {
            return Some(cur_value)
        }

        for key in path.split('.') {
            match *cur_value {
                Value::Table(ref hm) => {
                    match hm.get(key) {
                        Some(v) => cur_value = v,
                        None => return None
                    }
                },
                Value::Array(ref v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur_value = &v[idx],
                        _ => return None
                    }
                },
                _ => return None
            }
        };

        Some(cur_value)
    }

    /// Lookups for mutable value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let mut value: toml::Value = toml.parse().unwrap();
    /// {
    ///    let string = value.lookup_mut("test.foo").unwrap();
    ///    assert_eq!(string, &mut toml::Value::String(String::from("bar")));
    ///    *string = toml::Value::String(String::from("foo"));
    /// }
    /// let result = value.lookup_mut("test.foo").unwrap();
    /// assert_eq!(result.as_str().unwrap(), "foo");
    /// ```
    pub fn lookup_mut(&mut self, path: &str) -> Option<&mut Value> {
        let mut cur = self;
        if path.len() == 0 {
            return Some(cur)
        }

        for key in path.split('.') {
            let tmp = cur;
            match *tmp {
                Value::Table(ref mut hm) => {
                    match hm.get_mut(key) {
                        Some(v) => cur = v,
                        None => return None
                    }
                }
                Value::Array(ref mut v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur = &mut v[idx],
                        _ => return None
                    }
                }
                _ => return None
           }
        }
        Some(cur)
    }
}

impl FromStr for Value {
    type Err = Vec<ParserError>;
    fn from_str(s: &str) -> Result<Value, Vec<ParserError>> {
        let mut p = Parser::new(s);
        match p.parse().map(Value::Table) {
            Some(n) => Ok(n),
            None => Err(p.errors),
        }
    }
}

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

    #[test]
    fn lookup_mut_change() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let mut value: Value = toml.parse().unwrap();
        {
          let foo = value.lookup_mut("values.0.foo").unwrap();
          *foo = Value::String(String::from("bar"));
        }
        let foo = value.lookup("values.0.foo").unwrap();
        assert_eq!(foo.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_mut_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let test_foo = value.lookup_mut("test.foo").unwrap();
            assert_eq!(test_foo.as_str().unwrap(), "bar");
        }

        {
            let foo1 = value.lookup_mut("values.1.foo").unwrap();
            assert_eq!(foo1.as_str().unwrap(), "qux");
        }

        assert!(value.lookup_mut("test.bar").is_none());
        assert!(value.lookup_mut("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_mut_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let foo = value.lookup_mut("test.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.100.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.str.foo");
            assert!(foo.is_none());
        }
    }

    #[test]
    fn lookup_mut_self() {
        let mut value: Value = r#"foo = "bar""#.parse().unwrap();

        {
            let foo = value.lookup_mut("foo").unwrap();
            assert_eq!(foo.as_str().unwrap(), "bar");
        }

        let foo = value.lookup_mut("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup_mut("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let value: Value = toml.parse().unwrap();

        let test_foo = value.lookup("test.foo").unwrap();
        assert_eq!(test_foo.as_str().unwrap(), "bar");

        let foo1 = value.lookup("values.1.foo").unwrap();
        assert_eq!(foo1.as_str().unwrap(), "qux");

        assert!(value.lookup("test.bar").is_none());
        assert!(value.lookup("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let value: Value = toml.parse().unwrap();

        let foo = value.lookup("test.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.100.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.str.foo");
        assert!(foo.is_none());
    }

    #[test]
    fn lookup_self() {
        let value: Value = r#"foo = "bar""#.parse().unwrap();

        let foo = value.lookup("foo").unwrap();
        assert_eq!(foo.as_str().unwrap(), "bar");

        let foo = value.lookup("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }
}
<|endoftext|>


<commit_before>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! #![allow(unstable)]
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![feature(libc)]
#![feature(os)]

extern crate libc;

use libc::{c_uint,c_void};
use std::fmt;

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(usize)
}

impl fmt::Display for LzfError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LzfError::BufferTooSmall => {
                write!(f, "the given buffer is too small to handle the uncompressed data")
            }
            LzfError::DataCorrupted => {
                write!(f, "the given data is corrupted")
            }
            LzfError::NoCompressionPossible => {
                write!(f, "the input data cannot be compressed")
            }
            LzfError::UnknownError(err) => {
                write!(f, "unknown error, code {}", err)
            }
        }
    }
}

pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: usize) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {:?}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {:?}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<commit_msg>Return unknown error as i32<commit_after>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! #![allow(unstable)]
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![feature(libc)]
#![feature(os)]

extern crate libc;

use libc::{c_uint,c_void};
use std::fmt;

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(i32)
}

impl fmt::Display for LzfError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LzfError::BufferTooSmall => {
                write!(f, "the given buffer is too small to handle the uncompressed data")
            }
            LzfError::DataCorrupted => {
                write!(f, "the given data is corrupted")
            }
            LzfError::NoCompressionPossible => {
                write!(f, "the input data cannot be compressed")
            }
            LzfError::UnknownError(err) => {
                write!(f, "unknown error, code {}", err)
            }
        }
    }
}

pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: usize) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {:?}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {:?}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<|endoftext|>


<commit_before>#![feature(box_patterns)]

#[macro_use]
extern crate derive_new;
extern crate chrono;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;
extern crate itertools;
extern crate take_mut;

#[cfg(test)]
#[macro_use]
extern crate assert_matches;

mod db;
mod schedule_tree;

use std::fmt;

use chrono::{DateTime, Duration, TimeZone, UTC};
use diesel::prelude::*;
use itertools::Itertools;

use schedule_tree::ScheduleTree;

pub fn add(content: &str, deadline: &str, duration_hours: f64, importance: u32) {
    use db::tasks::dsl::tasks;

    let connection = db::make_connection();

    let deadline =
        UTC.datetime_from_str(deadline, "%-d %b %Y %-H:%M")
            .expect("Could not parse deadline. Please provide something like 4 Jul 6:05.");
    let duration = Duration::minutes((60.0 * duration_hours) as i64);
    let new_task = Task {
        id: None,
        content: content.to_string(),
        deadline: deadline,
        duration: duration,
        importance: importance,
    };

    diesel::insert(&new_task)
        .into(tasks)
        .execute(&connection)
        .expect("Error saving task.");
}

pub fn remove(id: u32) {
    use db::tasks::dsl::tasks;

    let connection = db::make_connection();

    diesel::delete(tasks.find(id as i32))
        .execute(&connection)
        .expect("Error removing task.");
}

pub fn print_schedule() {
    use db::tasks::dsl::tasks;

    let connection = db::make_connection();

    let tasks_ = tasks
        .load::<Task>(&connection)
        .expect("Error retrieving tasks.");

    println!("Tasks:\n");
    for task in &tasks_ {
        println!("{}", task);
    }

    let schedule = Schedule::schedule(&tasks_);
    println!("\n{}", schedule);
}

#[derive(Debug, Eq, new, Clone)]
pub struct Task {
    id: Option<u32>,
    content: String,
    deadline: DateTime<UTC>,
    duration: Duration,
    importance: u32,
}

impl PartialEq for Task {
    fn eq(&self, other: &Self) -> bool {
        let equal_id = match (self.id, other.id) {
            (Some(id1), Some(id2)) => id1 == id2,
            _ => true,
        };
        equal_id &&
            self.content == other.content &&
            self.deadline == other.deadline &&
            self.duration == other.duration &&
            self.importance == other.importance
    }
}

#[derive(Debug, new)]
struct ScheduledTask<'a> {
    task: &'a Task,
    when: DateTime<UTC>,
}

#[derive(Debug)]
pub struct Schedule<'a>(Vec<ScheduledTask<'a>>);

impl<'a> Schedule<'a> {
    /// Schedules tasks according to their deadlines, importance and duration.
    /// First, all tasks --- starting with the most important until the least important --- are
    /// scheduled as close as possible to their deadline.
    /// Next, all tasks --- starting with the most urgent one until the least urgent --- are put as
    /// close to the present as possible. This is too take care of contingencies like falling sick.
    /// A downside might be that a lot of time is spent doing urgent but non-important tasks.
    ///
    /// Args:
    ///     tasks: ordered list of tasks to schedule, ordered from most important to least
    ///     important.
    pub fn schedule<'b: 'a>(tasks: &'b [Task]) -> Schedule<'a> {
        let mut tree = ScheduleTree::new();
        for task in tasks {
            let start = task.deadline - task.duration;
            // TODO schedule close before the deadline
            tree.schedule_exact(start, task.duration, task);
        }
        let importance_schedule = tree.iter()
            .map(|entry| ScheduledTask::new(entry.data, entry.start))
            .collect();
        // TODO let urgent_first_schedule = importance_schedule
        Schedule(importance_schedule)
    }
}

impl<'a> fmt::Display for Schedule<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Schedule:\n  "));
        write!(f, "{}", self.0.iter().join("\n  "))
    }
}

impl<'a> fmt::Display for ScheduledTask<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: {}", self.when, self.task)
    }
}

impl fmt::Display for Task {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let prefix = match self.id {
            Some(id) => format!("{}.", id),
            None => "- ".to_string(),
        };
        write!(f,
               "{} {}\n    (deadline: {}, duration: {}, importance: {})",
               prefix,
               self.content,
               self.deadline,
               self.duration,
               self.importance)
    }
}

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

    #[test]
    fn all_tasks_are_planned() {
        let tasks = taskset1();
        let schedule = Schedule::schedule(&tasks);
        for scheduled_task in schedule.0 {
            assert!(tasks.contains(&scheduled_task.task))
        }
    }

    #[test]
    fn tasks_are_in_order() {
        let tasks = taskset1();
        let schedule = Schedule::schedule(&tasks);
        assert!(schedule.0[0].task.deadline < schedule.0[1].task.deadline);
        assert!(schedule.0[0].when < schedule.0[1].when);
    }

    fn taskset1() -> Vec<Task> {
        let task1 = Task {
            id: None,
            content: "do stuff".to_string(),
            deadline: UTC::now() + Duration::days(3),
            duration: Duration::hours(2),
            importance: 5,
        };
        let task2 = Task {
            id: None,
            content: "contemplate life".to_string(),
            deadline: UTC::now() + Duration::days(4),
            duration: Duration::hours(12),
            importance: 6,
        };
        vec![task1, task2]
    }
}
<commit_msg>Nice formatting for datetimes & durations<commit_after>#![feature(box_patterns)]

#[macro_use]
extern crate derive_new;
extern crate chrono;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;
extern crate itertools;
extern crate take_mut;

#[cfg(test)]
#[macro_use]
extern crate assert_matches;

mod db;
mod schedule_tree;

use std::fmt;

use chrono::{DateTime, Duration, TimeZone, UTC};
use diesel::prelude::*;
use itertools::Itertools;

use schedule_tree::ScheduleTree;

pub fn add(content: &str, deadline: &str, duration_hours: f64, importance: u32) {
    use db::tasks::dsl::tasks;

    let connection = db::make_connection();

    let deadline =
        UTC.datetime_from_str(deadline, "%-d %b %Y %-H:%M")
            .expect("Could not parse deadline. Please provide something like 4 Jul 6:05.");
    let duration = Duration::minutes((60.0 * duration_hours) as i64);
    let new_task = Task {
        id: None,
        content: content.to_string(),
        deadline: deadline,
        duration: duration,
        importance: importance,
    };

    diesel::insert(&new_task)
        .into(tasks)
        .execute(&connection)
        .expect("Error saving task.");
}

pub fn remove(id: u32) {
    use db::tasks::dsl::tasks;

    let connection = db::make_connection();

    diesel::delete(tasks.find(id as i32))
        .execute(&connection)
        .expect("Error removing task.");
}

pub fn print_schedule() {
    use db::tasks::dsl::tasks;

    let connection = db::make_connection();

    let tasks_ = tasks
        .load::<Task>(&connection)
        .expect("Error retrieving tasks.");

    println!("Tasks:");
    for task in &tasks_ {
        println!("  {}", task);
    }

    let schedule = Schedule::schedule(&tasks_);
    println!("\n{}", schedule);
}

#[derive(Debug, Eq, new, Clone)]
pub struct Task {
    id: Option<u32>,
    content: String,
    deadline: DateTime<UTC>,
    duration: Duration,
    importance: u32,
}

impl PartialEq for Task {
    fn eq(&self, other: &Self) -> bool {
        let equal_id = match (self.id, other.id) {
            (Some(id1), Some(id2)) => id1 == id2,
            _ => true,
        };
        equal_id &&
            self.content == other.content &&
            self.deadline == other.deadline &&
            self.duration == other.duration &&
            self.importance == other.importance
    }
}

#[derive(Debug, new)]
struct ScheduledTask<'a> {
    task: &'a Task,
    when: DateTime<UTC>,
}

#[derive(Debug)]
pub struct Schedule<'a>(Vec<ScheduledTask<'a>>);

impl<'a> Schedule<'a> {
    /// Schedules tasks according to their deadlines, importance and duration.
    /// First, all tasks --- starting with the most important until the least important --- are
    /// scheduled as close as possible to their deadline.
    /// Next, all tasks --- starting with the most urgent one until the least urgent --- are put as
    /// close to the present as possible. This is too take care of contingencies like falling sick.
    /// A downside might be that a lot of time is spent doing urgent but non-important tasks.
    ///
    /// Args:
    ///     tasks: ordered list of tasks to schedule, ordered from most important to least
    ///     important.
    pub fn schedule<'b: 'a>(tasks: &'b [Task]) -> Schedule<'a> {
        let mut tree = ScheduleTree::new();
        for task in tasks {
            let start = task.deadline - task.duration;
            // TODO schedule close before the deadline
            tree.schedule_exact(start, task.duration, task);
        }
        let importance_schedule = tree.iter()
            .map(|entry| ScheduledTask::new(entry.data, entry.start))
            .collect();
        // TODO let urgent_first_schedule = importance_schedule
        Schedule(importance_schedule)
    }
}

impl<'a> fmt::Display for Schedule<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Schedule:\n  "));
        write!(f, "{}", self.0.iter().join("\n  "))
    }
}

impl<'a> fmt::Display for ScheduledTask<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: {}",
               format_datetime(self.when),
               self.task)
    }
}

impl fmt::Display for Task {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let prefix = match self.id {
            Some(id) => format!("{}.", id),
            None => "- ".to_string(),
        };
        write!(f, "{} {}\n    (deadline: {}, duration: {}, importance: {})",
               prefix,
               self.content,
               format_datetime(self.deadline),
               format_duration(self.duration),
               self.importance)
    }
}

fn format_datetime(datetime: DateTime<UTC>) -> String {
    datetime.format("%a %-d %b %-H:%M").to_string()
}

fn format_duration(duration: Duration) -> String {
    if duration.num_minutes() > 0 {
        format!("{}h{}", duration.num_hours(), duration.num_minutes() % 60)
    } else {
        format!("{}h", duration.num_hours())
    }
}

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

    #[test]
    fn all_tasks_are_planned() {
        let tasks = taskset1();
        let schedule = Schedule::schedule(&tasks);
        for scheduled_task in schedule.0 {
            assert!(tasks.contains(&scheduled_task.task))
        }
    }

    #[test]
    fn tasks_are_in_order() {
        let tasks = taskset1();
        let schedule = Schedule::schedule(&tasks);
        assert!(schedule.0[0].task.deadline < schedule.0[1].task.deadline);
        assert!(schedule.0[0].when < schedule.0[1].when);
    }

    fn taskset1() -> Vec<Task> {
        let task1 = Task {
            id: None,
            content: "do stuff".to_string(),
            deadline: UTC::now() + Duration::days(3),
            duration: Duration::hours(2),
            importance: 5,
        };
        let task2 = Task {
            id: None,
            content: "contemplate life".to_string(),
            deadline: UTC::now() + Duration::days(4),
            duration: Duration::hours(12),
            importance: 6,
        };
        vec![task1, task2]
    }
}
<|endoftext|>