<commit_before>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug, PartialEq)]
pub enum Filter {
    Term(String, Json),
    Prefix(String, String),
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Box<Filter>),
}

#[derive(Debug, PartialEq)]
pub enum QueryParseError {
    ExpectedObject,
    ExpectedString,
    ExpectedArray,
    UnknownQueryType(String),
    NoQuery,
    FilteredNoFilter,
    FilteredNoQuery,
    MissingQueryString,
    MultiMatchMissingFields,
}

#[derive(Debug, PartialEq)]
pub enum Query {
    MatchAll,
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    return field_value == value;
                }

                false
            }
            Filter::Prefix(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value.starts_with(value);
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::Not(ref filter) => !filter.matches(doc),
        }
    }
}

pub fn parse_filter(json: &Json) -> Filter {
    let filter_json = json.as_object().unwrap();
    let first_key = filter_json.keys().nth(0).unwrap();

    if first_key == "term" {
        let filter_json = filter_json.get("term").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();

        Filter::Term(first_key.clone(), filter_json.get(first_key).unwrap().clone())
    } else if first_key == "prefix" {
        let filter_json = filter_json.get("prefix").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();
        let value = filter_json.get(first_key).unwrap().as_string().unwrap();

        Filter::Prefix(first_key.clone(), value.to_owned())
    } else if first_key == "and" {
        Filter::And(filter_json.get("and").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "or" {
        Filter::Or(filter_json.get("or").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "not" {
        Filter::Not(Box::new(parse_filter(filter_json.get("not").unwrap())))
    } else {
        Filter::Term("not".to_owned(), Json::String("implemented".to_owned()))
    }
}

impl Query {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Query::MatchAll => true,
            Query::Match{ref field, ref query} => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    let mut field_value = field_value.as_string().unwrap().to_lowercase();
                    let mut query = query.to_lowercase();

                    return field_value.contains(&query);
                }

                false
            }
            Query::MultiMatch{ref fields, ref query} => {
                // TODO
                false
            }
            Query::Filtered{ref query, ref filter} => {
                if filter.matches(doc) {
                    query.matches(doc)
                } else {
                    false
                }
            }
        }
    }
}

pub fn parse_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    Ok(Query::Match {
        field: first_key.clone(),
        query: json_object.get(first_key).unwrap().as_string().unwrap().to_owned(),
    })
}

pub fn parse_multi_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    // Convert "fields" into a Vec<String>
    let fields_json = try!(json_object.get("fields").ok_or(QueryParseError::MultiMatchMissingFields));
    let fields = try!(fields_json.as_array().ok_or(QueryParseError::ExpectedArray))
                      .iter().map(|s| s.as_string().unwrap().to_owned())
                      .collect::<Vec<_>>();

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::MissingQueryString));
    let query = try!(query_json.as_string().ok_or(QueryParseError::ExpectedString)).to_owned();

    Ok(Query::MultiMatch {
        fields: fields,
        query: query,
    })
}

pub fn parse_filtered_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    let filter_json = try!(json_object.get("filter").ok_or(QueryParseError::FilteredNoFilter));
    let filter = parse_filter(filter_json);

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::FilteredNoQuery));
    let query = try!(parse_query(query_json));

    Ok(Query::Filtered {
        filter: Box::new(filter),
        query: Box::new(query),
    })
}

pub fn parse_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    if first_key == "match_all" {
        Ok(Query::MatchAll)
    } else if first_key == "match" {
        let inner_query = json_object.get("match").unwrap();
        Ok(try!(parse_match_query(inner_query)))
    } else if first_key == "multi_match" {
        let inner_query = json_object.get("multi_match").unwrap();
        Ok(try!(parse_multi_match_query(inner_query)))
    } else if first_key == "filtered" {
        let inner_query = json_object.get("filtered").unwrap();
        Ok(try!(parse_filtered_query(inner_query)))
    } else {
        Err(QueryParseError::UnknownQueryType(first_key.clone()))
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;
    use super::{Query, Filter, QueryParseError, parse_query};

    #[test]
    fn test_match_all_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match_all\": {}
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchAll))
    }

    #[test]
    fn test_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {
                    \"title\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Match{
            field: "title".to_owned(),
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_match_query_without_field() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {}
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::NoQuery))
    }

    #[test]
    fn test_multi_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"],
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MultiMatch{
            fields: vec!["title".to_owned(), "body".to_owned()],
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_multi_match_query_without_fields() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MultiMatchMissingFields))
    }

    #[test]
    fn test_multi_match_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"]
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MissingQueryString))
    }

    #[test]
    fn test_filtered_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    },
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Filtered{
            query: Box::new(Query::Match{
                field: "title".to_owned(),
                query: "Hello world!".to_owned(),
            }),
            filter: Box::new(Filter::Term(
                "date".to_owned(),
                Json::from_str("\"2016-01-25\"").unwrap(),
            ))
        }))
    }

    #[test]
    fn test_filtered_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoQuery))
    }

    #[test]
    fn test_filtered_query_without_filter() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoFilter))
    }
}
<commit_msg>Implement multi match<commit_after>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug, PartialEq)]
pub enum Filter {
    Term(String, Json),
    Prefix(String, String),
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Box<Filter>),
}

#[derive(Debug, PartialEq)]
pub enum QueryParseError {
    ExpectedObject,
    ExpectedString,
    ExpectedArray,
    UnknownQueryType(String),
    NoQuery,
    FilteredNoFilter,
    FilteredNoQuery,
    MissingQueryString,
    MultiMatchMissingFields,
}

#[derive(Debug, PartialEq)]
pub enum Query {
    MatchAll,
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    return field_value == value;
                }

                false
            }
            Filter::Prefix(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value.starts_with(value);
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::Not(ref filter) => !filter.matches(doc),
        }
    }
}

pub fn parse_filter(json: &Json) -> Filter {
    let filter_json = json.as_object().unwrap();
    let first_key = filter_json.keys().nth(0).unwrap();

    if first_key == "term" {
        let filter_json = filter_json.get("term").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();

        Filter::Term(first_key.clone(), filter_json.get(first_key).unwrap().clone())
    } else if first_key == "prefix" {
        let filter_json = filter_json.get("prefix").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();
        let value = filter_json.get(first_key).unwrap().as_string().unwrap();

        Filter::Prefix(first_key.clone(), value.to_owned())
    } else if first_key == "and" {
        Filter::And(filter_json.get("and").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "or" {
        Filter::Or(filter_json.get("or").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "not" {
        Filter::Not(Box::new(parse_filter(filter_json.get("not").unwrap())))
    } else {
        Filter::Term("not".to_owned(), Json::String("implemented".to_owned()))
    }
}

impl Query {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Query::MatchAll => true,
            Query::Match{ref field, ref query} => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    let mut field_value = field_value.as_string().unwrap().to_lowercase();
                    let mut query = query.to_lowercase();

                    return field_value.contains(&query);
                }

                false
            }
            Query::MultiMatch{ref fields, ref query} => {
                let obj = doc.data.as_object().unwrap();

                for field in fields.iter() {
                    if let Some(field_value) = obj.get(field) {
                        let mut field_value = field_value.as_string().unwrap().to_lowercase();
                        let mut query = query.to_lowercase();

                        if field_value.contains(&query) {
                            return true;
                        }
                    }
                }

                false
            }
            Query::Filtered{ref query, ref filter} => {
                if filter.matches(doc) {
                    query.matches(doc)
                } else {
                    false
                }
            }
        }
    }
}

pub fn parse_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    Ok(Query::Match {
        field: first_key.clone(),
        query: json_object.get(first_key).unwrap().as_string().unwrap().to_owned(),
    })
}

pub fn parse_multi_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    // Convert "fields" into a Vec<String>
    let fields_json = try!(json_object.get("fields").ok_or(QueryParseError::MultiMatchMissingFields));
    let fields = try!(fields_json.as_array().ok_or(QueryParseError::ExpectedArray))
                      .iter().map(|s| s.as_string().unwrap().to_owned())
                      .collect::<Vec<_>>();

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::MissingQueryString));
    let query = try!(query_json.as_string().ok_or(QueryParseError::ExpectedString)).to_owned();

    Ok(Query::MultiMatch {
        fields: fields,
        query: query,
    })
}

pub fn parse_filtered_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    let filter_json = try!(json_object.get("filter").ok_or(QueryParseError::FilteredNoFilter));
    let filter = parse_filter(filter_json);

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::FilteredNoQuery));
    let query = try!(parse_query(query_json));

    Ok(Query::Filtered {
        filter: Box::new(filter),
        query: Box::new(query),
    })
}

pub fn parse_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    if first_key == "match_all" {
        Ok(Query::MatchAll)
    } else if first_key == "match" {
        let inner_query = json_object.get("match").unwrap();
        Ok(try!(parse_match_query(inner_query)))
    } else if first_key == "multi_match" {
        let inner_query = json_object.get("multi_match").unwrap();
        Ok(try!(parse_multi_match_query(inner_query)))
    } else if first_key == "filtered" {
        let inner_query = json_object.get("filtered").unwrap();
        Ok(try!(parse_filtered_query(inner_query)))
    } else {
        Err(QueryParseError::UnknownQueryType(first_key.clone()))
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;
    use super::{Query, Filter, QueryParseError, parse_query};

    #[test]
    fn test_match_all_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match_all\": {}
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchAll))
    }

    #[test]
    fn test_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {
                    \"title\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Match{
            field: "title".to_owned(),
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_match_query_without_field() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {}
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::NoQuery))
    }

    #[test]
    fn test_multi_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"],
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MultiMatch{
            fields: vec!["title".to_owned(), "body".to_owned()],
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_multi_match_query_without_fields() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MultiMatchMissingFields))
    }

    #[test]
    fn test_multi_match_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"]
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MissingQueryString))
    }

    #[test]
    fn test_filtered_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    },
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Filtered{
            query: Box::new(Query::Match{
                field: "title".to_owned(),
                query: "Hello world!".to_owned(),
            }),
            filter: Box::new(Filter::Term(
                "date".to_owned(),
                Json::from_str("\"2016-01-25\"").unwrap(),
            ))
        }))
    }

    #[test]
    fn test_filtered_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoQuery))
    }

    #[test]
    fn test_filtered_query_without_filter() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoFilter))
    }
}
<|endoftext|>


<commit_before>extern crate regex;

use std::iter::FromIterator;
use std::marker::PhantomData;

use primitives::{ConsumedResult, FullRangeStream, Parser, ParseError};
use primitives::FastResult::*;
use range::take;

pub trait MatchFind {
    type Range;
    fn end(&self) -> usize;
    fn as_match(&self) -> Self::Range;
}

impl<'t> MatchFind for self::regex::Match<'t> {
    type Range = &'t str;
    fn end(&self) -> usize {
        self::regex::Match::end(self)
    }
    fn as_match(&self) -> Self::Range {
        self.as_str()
    }
}

impl<'t> MatchFind for self::regex::bytes::Match<'t> {
    type Range = &'t [u8];
    fn end(&self) -> usize {
        self::regex::bytes::Match::end(self)
    }
    fn as_match(&self) -> Self::Range {
        self.as_bytes()
    }
}

pub trait Regex<Range> {
    fn is_match(&self, range: Range) -> bool;
    fn find_iter<F>(&self, range: Range) -> (usize, F) where F: FromIterator<Range>;
}

impl<'a, R, Range> Regex<Range> for &'a R where R: Regex<Range> {
    fn is_match(&self, range: Range) -> bool {
        (**self).is_match(range)
    }
    fn find_iter<F>(&self, range: Range) -> (usize, F) where F: FromIterator<Range> {
        (**self).find_iter(range)
    }
}

impl<'a> Regex<&'a str> for self::regex::Regex {
    fn is_match(&self, range: &'a str) -> bool {
        self::regex::Regex::is_match(self, range)
    }
    fn find_iter<F>(&self, range: &'a str) -> (usize, F) where F: FromIterator<&'a str> {
        let mut end = 0;
        let value = self::regex::Regex::find_iter(self, range).map(|m| {
            end = m.end();
            m.as_match()
        })
        .collect();
        (end, value)
    }
}

impl<'a> Regex<&'a [u8]> for self::regex::bytes::Regex {
    fn is_match(&self, range: &'a [u8]) -> bool {
        self::regex::bytes::Regex::is_match(self, range)
    }
    fn find_iter<F>(&self, range: &'a [u8]) -> (usize, F) where F: FromIterator<&'a [u8]> {
        let mut end = 0;
        let value = self::regex::bytes::Regex::find_iter(self, range).map(|m| {
            end = m.end();
            m.as_match()
        })
        .collect();
        (end, value)
    }
}

pub struct Match<R, I>(R, PhantomData<I>);

impl<'a, R, I> Parser for Match<R, I>
where
    R: Regex<I::Range>,
    I: FullRangeStream,
{
    type Input = I;
    type Output = I::Range;

    #[inline]
    fn parse_lazy(&mut self, input: Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
        if self.0.is_match(input.range()) {
            EmptyOk((input.range(), input))
        } else {
            EmptyErr(ParseError::empty(input.position()))
        }
    }
}

/// Matches `regex` on the input returning the entire input if it matches.
/// Never consumes any input.
pub fn match_<R, I>(regex: R) -> Match<R, I>
where
    R: Regex<I::Range>,
    I: FullRangeStream,
{
    Match(regex, PhantomData)
}

pub struct FindMany<F, R, I>(R, PhantomData<fn () -> (I, F)>);

impl<'a, F, R, I> Parser for FindMany<F, R, I>
where
    F: FromIterator<I::Range>,
    R: Regex<I::Range>,
    I: FullRangeStream,
    I::Range: ::primitives::Range,
{
    type Input = I;
    type Output = F;

    #[inline]
    fn parse_lazy(&mut self, input: Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
        let (end, value) = self.0.find_iter(input.range());
        take(end).parse_lazy(input).map(|_| value)
    }
}

/// Matches `regex` on the input by running `find_iter` on the input.
/// Returns all matches in a `F: FromIterator<I::Range>`.
/// Consumes all input up until the end of the last match.
///
/// ```
/// extern crate regex;
/// extern crate combine;
/// use regex::Regex;
/// use regex::bytes;
/// use combine::Parser;
/// use combine::regex::find_many;
///
/// fn main() {
///     let mut digits = find_many(Regex::new("[0-9]+").unwrap());
///     assert_eq!(digits.parse("123 456 "), Ok((vec!["123", "456"], " ")));
///     assert_eq!(digits.parse("abc 123 456 "), Ok((vec!["123", "456"], " ")));
///     assert_eq!(digits.parse("abc"), Ok((vec![], "abc")));
///
///     let regex = bytes::Regex::new("[0-9]+").unwrap();
///     // Shared references to any regex works as well
///     assert_eq!(
///         find_many(&regex).parse(&b"123 456 "[..]),
///         Ok((vec![&b"123"[..], &b"456"[..]], &b" "[..]))
///     );
///     assert_eq!(
///         find_many(regex).parse(&b""[..]),
///         Ok((vec![], &b""[..]))
///     );
/// }
/// ```
pub fn find_many<F, R, I>(regex: R) -> FindMany<F, R, I>
where
    F: FromIterator<I::Range>,
    R: Regex<I::Range>,
    I: FullRangeStream,
    I::Range: ::primitives::Range,
{
    FindMany(regex, PhantomData)
}<commit_msg>Add a captures regex parser<commit_after>//! All regex parsers are overloaded on `&str` and `&[u8]` ranges and can take a `Regex` by value
//! or shared reference (`&`)
//!
//! ```
//! extern crate regex;
//! extern crate combine;
//! use regex::bytes::Regex;
//! use combine::Parser;
//! use combine::regex::find_many;
//!
//! fn main() {
//!     let regex = Regex::new("[0-9]+").unwrap();
//!     // Shared references to any regex works as well
//!     assert_eq!(
//!         find_many(&regex).parse(&b"123 456 "[..]),
//!         Ok((vec![&b"123"[..], &b"456"[..]], &b" "[..]))
//!     );
//!     assert_eq!(
//!         find_many(regex).parse(&b""[..]),
//!         Ok((vec![], &b""[..]))
//!     );
//! }
//! ```

extern crate regex;

use std::iter::FromIterator;
use std::marker::PhantomData;

use primitives::{ConsumedResult, FullRangeStream, ParseError, Parser};
use primitives::FastResult::*;
use range::take;

pub trait MatchFind {
    type Range;
    fn end(&self) -> usize;
    fn as_match(&self) -> Self::Range;
}

impl<'t> MatchFind for self::regex::Match<'t> {
    type Range = &'t str;
    fn end(&self) -> usize {
        self::regex::Match::end(self)
    }
    fn as_match(&self) -> Self::Range {
        self.as_str()
    }
}

impl<'t> MatchFind for self::regex::bytes::Match<'t> {
    type Range = &'t [u8];
    fn end(&self) -> usize {
        self::regex::bytes::Match::end(self)
    }
    fn as_match(&self) -> Self::Range {
        self.as_bytes()
    }
}

pub trait Regex<Range> {
    fn is_match(&self, range: Range) -> bool;
    fn find_iter<F>(&self, range: Range) -> (usize, F)
    where
        F: FromIterator<Range>;
    fn captures<F, G>(&self, range: Range) -> (usize, G)
    where
        F: FromIterator<Range>,
        G: FromIterator<F>;
}

impl<'a, R, Range> Regex<Range> for &'a R
where
    R: Regex<Range>,
{
    fn is_match(&self, range: Range) -> bool {
        (**self).is_match(range)
    }
    fn find_iter<F>(&self, range: Range) -> (usize, F)
    where
        F: FromIterator<Range>,
    {
        (**self).find_iter(range)
    }
    fn captures<F, G>(&self, range: Range) -> (usize, G)
    where
        F: FromIterator<Range>,
        G: FromIterator<F>,
    {
        (**self).captures(range)
    }
}

impl<'a> Regex<&'a str> for self::regex::Regex {
    fn is_match(&self, range: &'a str) -> bool {
        self::regex::Regex::is_match(self, range)
    }
    fn find_iter<F>(&self, range: &'a str) -> (usize, F)
    where
        F: FromIterator<&'a str>,
    {
        let mut end = 0;
        let value = self::regex::Regex::find_iter(self, range)
            .map(|m| {
                end = m.end();
                m.as_match()
            })
            .collect();
        (end, value)
    }
    fn captures<F, G>(&self, range: &'a str) -> (usize, G)
    where
        F: FromIterator<&'a str>,
        G: FromIterator<F>,
    {
        let mut end = 0;
        let value = self::regex::Regex::captures_iter(self, range)
            .map(|captures| {
                let mut captures_iter = captures.iter();
                // The first group is the match on the entire regex
                let first_match = captures_iter.next().unwrap().unwrap();
                end = first_match.end();
                Some(Some(first_match))
                    .into_iter()
                    .chain(captures_iter)
                    .filter_map(|match_| match_.map(|m| m.as_match()))
                    .collect()
            })
            .collect();
        (end, value)
    }
}

impl<'a> Regex<&'a [u8]> for self::regex::bytes::Regex {
    fn is_match(&self, range: &'a [u8]) -> bool {
        self::regex::bytes::Regex::is_match(self, range)
    }
    fn find_iter<F>(&self, range: &'a [u8]) -> (usize, F)
    where
        F: FromIterator<&'a [u8]>,
    {
        let mut end = 0;
        let value = self::regex::bytes::Regex::find_iter(self, range)
            .map(|m| {
                end = m.end();
                m.as_match()
            })
            .collect();
        (end, value)
    }
    fn captures<F, G>(&self, range: &'a [u8]) -> (usize, G)
    where
        F: FromIterator<&'a [u8]>,
        G: FromIterator<F>,
    {
        let mut end = 0;
        let value = self::regex::bytes::Regex::captures_iter(self, range)
            .map(|captures| {
                let mut captures_iter = captures.iter();
                // The first group is the match on the entire regex
                let first_match = captures_iter.next().unwrap().unwrap();
                end = first_match.end();
                Some(Some(first_match))
                    .into_iter()
                    .chain(captures_iter)
                    .filter_map(|match_| match_.map(|m| m.as_match()))
                    .collect()
            })
            .collect();
        (end, value)
    }
}

pub struct Match<R, I>(R, PhantomData<I>);

impl<'a, R, I> Parser for Match<R, I>
where
    R: Regex<I::Range>,
    I: FullRangeStream,
{
    type Input = I;
    type Output = I::Range;

    #[inline]
    fn parse_lazy(&mut self, input: Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
        if self.0.is_match(input.range()) {
            EmptyOk((input.range(), input))
        } else {
            EmptyErr(ParseError::empty(input.position()))
        }
    }
}

/// Matches `regex` on the input returning the entire input if it matches.
/// Never consumes any input.
pub fn match_<R, I>(regex: R) -> Match<R, I>
where
    R: Regex<I::Range>,
    I: FullRangeStream,
{
    Match(regex, PhantomData)
}

#[derive(Clone)]
pub struct FindMany<F, R, I>(R, PhantomData<fn() -> (I, F)>);

impl<'a, F, R, I> Parser for FindMany<F, R, I>
where
    F: FromIterator<I::Range>,
    R: Regex<I::Range>,
    I: FullRangeStream,
    I::Range: ::primitives::Range,
{
    type Input = I;
    type Output = F;

    #[inline]
    fn parse_lazy(&mut self, input: Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
        let (end, value) = self.0.find_iter(input.range());
        take(end).parse_lazy(input).map(|_| value)
    }
}

/// Matches `regex` on the input by running `find_iter` on the input.
/// Returns all matches in a `F: FromIterator<I::Range>`.
/// Consumes all input up until the end of the last match.
///
/// ```
/// extern crate regex;
/// extern crate combine;
/// use regex::Regex;
/// use regex::bytes;
/// use combine::Parser;
/// use combine::regex::find_many;
///
/// fn main() {
///     let mut digits = find_many(Regex::new("[0-9]+").unwrap());
///     assert_eq!(digits.parse("123 456 "), Ok((vec!["123", "456"], " ")));
///     assert_eq!(digits.parse("abc 123 456 "), Ok((vec!["123", "456"], " ")));
///     assert_eq!(digits.parse("abc"), Ok((vec![], "abc")));
/// }
/// ```
pub fn find_many<F, R, I>(regex: R) -> FindMany<F, R, I>
where
    F: FromIterator<I::Range>,
    R: Regex<I::Range>,
    I: FullRangeStream,
    I::Range: ::primitives::Range,
{
    FindMany(regex, PhantomData)
}

#[derive(Clone)]
pub struct Captures<F, G, R, I>(R, PhantomData<fn() -> (I, F, G)>);

impl<'a, F, G, R, I> Parser for Captures<F, G, R, I>
where
    F: FromIterator<I::Range>,
    G: FromIterator<F>,
    R: Regex<I::Range>,
    I: FullRangeStream,
    I::Range: ::primitives::Range,
{
    type Input = I;
    type Output = G;

    #[inline]
    fn parse_lazy(&mut self, input: Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
        let (end, value) = self.0.captures(input.range());
        take(end).parse_lazy(input).map(|_| value)
    }
}

/// Matches `regex` on the input by running `captures_iter` on the input.
/// Returns all captures which is part of the match in a `F: FromIterator<I::Range>`.
/// Consumes all input up until the end of the last match.
///
/// ```
/// extern crate regex;
/// extern crate combine;
/// use regex::Regex;
/// use regex::bytes;
/// use combine::Parser;
/// use combine::regex::captures;
///
/// fn main() {
///     let mut fields = captures(Regex::new("([a-z]+):([0-9]+)").unwrap());
///     assert_eq!(
///         fields.parse("test:123 field:456 "),
///         Ok((vec![vec!["test:123", "test", "123"],
///                  vec!["field:456", "field", "456"]],
///             " "
///         ))
///     );
///     assert_eq!(
///         fields.parse("test:123 :456 "),
///         Ok((vec![vec!["test:123", "test", "123"]],
///             " :456 "
///         ))
///     );
/// }
/// ```
pub fn captures<F, G, R, I>(regex: R) -> Captures<F, G, R, I>
where
    F: FromIterator<I::Range>,
    G: FromIterator<F>,
    R: Regex<I::Range>,
    I: FullRangeStream,
    I::Range: ::primitives::Range,
{
    Captures(regex, PhantomData)
}
<|endoftext|>


<commit_before>use slack_hook::{Attachment, AttachmentBuilder, Field, PayloadBuilder, Slack, SlackText, SlackLink};
use slack_hook::SlackTextContent::{Text, Link};

use taste::{BenchmarkResult, TastingResult};

pub struct SlackNotifier {
    conn: Slack,
    channel: String,
    github_repo: String,
}

impl SlackNotifier {
    pub fn new(hook_url: &str, channel: &str, repo_url: &str) -> SlackNotifier {
        SlackNotifier {
            conn: Slack::new(hook_url).unwrap(),
            channel: String::from(channel),
            github_repo: String::from(repo_url),
        }
    }

    pub fn notify(&self, res: &TastingResult) -> Result<(), String> {
        let payload = PayloadBuilder::new()
            .text(vec![Text("I've tasted commit _".into()),
                       Text(format!("\"{}\"_ -- ", res.commit_msg.lines().next().unwrap())
                           .into()),
                       Link(SlackLink::new(&format!("{}/commit/{}",
                                                    res.commit_url,
                                                    res.commit_id),
                                           &res.commit_id[0..6]))]
                .as_slice())
            .attachments(result_to_attachments(&res))
            .channel(self.channel.clone())
            .username("taster")
            .icon_emoji(":tea:")
            .build()
            .unwrap();

        match self.conn.send(&payload) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}

fn result_to_attachments(res: &TastingResult) -> Vec<Attachment> {
    let color = if !res.build || !res.bench {
        "danger"
    } else {
        "good"
    };

    let title = if !res.build {
        "Build failure!"
    } else if !res.bench {
        "Benchmark failure!"
    } else {
        "Performance results:"
    };

    let taste = if !res.build || !res.bench {
        "was inedible"
    } else {
        "tasted nice"
    };

    let mut attachments = Vec::new();
    let build_att = AttachmentBuilder::new("")
        .title(format!("It {}.", taste))
        .fields(vec![Field {
                         title: "Build".into(),
                         value: SlackText::new(if res.build { ":white_check_mark:" } else { ":x:" }),
                         short: Some(true),
                     },
                     Field {
                         title: "Benchmark".into(),
                         value: SlackText::new(if res.bench { ":white_check_mark:" } else { ":x:" }),
                         short: Some(true),
                     }])
        .color(color)
        .build()
        .unwrap();
    attachments.push(build_att);

    match res.results {
        None => (),
        Some(ref r) => {
            for res in r {
                let mut nv = res.iter()
                    .map(|(k, v)| {
                        let val = match v {
                            &BenchmarkResult::Neutral(ref s, _) => s,
                            _ => unimplemented!(),
                        };
                        Field {
                            title: k.clone(),
                            value: SlackText::new(val.clone()),
                            short: Some(true),
                        }
                    })
                    .collect::<Vec<_>>();
                nv.sort_by(|a, b| b.title.cmp(&a.title));
                let att = AttachmentBuilder::new("")
                    .color(color)
                    .fields(nv)
                    .build()
                    .unwrap();
                attachments.push(att);
            }
        }
    }
    attachments
}
<commit_msg>Correct commit links.<commit_after>use slack_hook::{Attachment, AttachmentBuilder, Field, PayloadBuilder, Slack, SlackText, SlackLink};
use slack_hook::SlackTextContent::{Text, Link};

use taste::{BenchmarkResult, TastingResult};

pub struct SlackNotifier {
    conn: Slack,
    channel: String,
    github_repo: String,
}

impl SlackNotifier {
    pub fn new(hook_url: &str, channel: &str, repo_url: &str) -> SlackNotifier {
        SlackNotifier {
            conn: Slack::new(hook_url).unwrap(),
            channel: String::from(channel),
            github_repo: String::from(repo_url),
        }
    }

    pub fn notify(&self, res: &TastingResult) -> Result<(), String> {
        let payload = PayloadBuilder::new()
            .text(vec![Text("I've tasted commit _".into()),
                       Text(format!("\"{}\"_ -- ", res.commit_msg.lines().next().unwrap())
                           .into()),
                       Link(SlackLink::new(&res.commit_url, &res.commit_id[0..6]))]
                .as_slice())
            .attachments(result_to_attachments(&res))
            .channel(self.channel.clone())
            .username("taster")
            .icon_emoji(":tea:")
            .build()
            .unwrap();

        match self.conn.send(&payload) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}

fn result_to_attachments(res: &TastingResult) -> Vec<Attachment> {
    let color = if !res.build || !res.bench {
        "danger"
    } else {
        "good"
    };

    let title = if !res.build {
        "Build failure!"
    } else if !res.bench {
        "Benchmark failure!"
    } else {
        "Performance results:"
    };

    let taste = if !res.build || !res.bench {
        "was inedible"
    } else {
        "tasted nice"
    };

    let mut attachments = Vec::new();
    let build_att = AttachmentBuilder::new("")
        .title(format!("It {}.", taste))
        .fields(vec![Field {
                         title: "Build".into(),
                         value: SlackText::new(if res.build { ":white_check_mark:" } else { ":x:" }),
                         short: Some(true),
                     },
                     Field {
                         title: "Benchmark".into(),
                         value: SlackText::new(if res.bench { ":white_check_mark:" } else { ":x:" }),
                         short: Some(true),
                     }])
        .color(color)
        .build()
        .unwrap();
    attachments.push(build_att);

    match res.results {
        None => (),
        Some(ref r) => {
            for res in r {
                let mut nv = res.iter()
                    .map(|(k, v)| {
                        let val = match v {
                            &BenchmarkResult::Neutral(ref s, _) => s,
                            _ => unimplemented!(),
                        };
                        Field {
                            title: k.clone(),
                            value: SlackText::new(val.clone()),
                            short: Some(true),
                        }
                    })
                    .collect::<Vec<_>>();
                nv.sort_by(|a, b| b.title.cmp(&a.title));
                let att = AttachmentBuilder::new("")
                    .color(color)
                    .fields(nv)
                    .build()
                    .unwrap();
                attachments.push(att);
            }
        }
    }
    attachments
}
<|endoftext|>


<commit_before>
use std::time::duration::Duration;
use std::io::{standard_error, IoErrorKind, Stream};
use std::iter::FromIterator;
use std::collections::BTreeMap;
use time::{Timespec, strptime};
use rustc_serialize::{Encoder, Encodable};

use error::MpdResult;
use client::{MpdPair, MpdClient};
use utils::{FieldCutIter, ForceEncodable};

#[derive(Show, Copy, RustcEncodable)]
pub struct MpdQueuePlace {
    pub id: uint,
    pub pos: uint,
    pub prio: uint
}

#[derive(Show, RustcEncodable)]
pub struct MpdSong {
    pub file: String,
    pub last_mod: Timespec,
    pub duration: Duration,
    pub place: Option<MpdQueuePlace>,
    pub range: (Duration, Option<Duration>),
    pub tags: BTreeMap<String, String>,
}

impl MpdSong {
    pub fn seek<S: Stream>(&self, cli: &mut MpdClient<S>, time: Duration) -> MpdResult<()> {
        cli.exec_arg2("seekid", self.place.unwrap().id, time.num_milliseconds() as f32 / 1000f32)
    }
}

impl FromIterator<MpdResult<MpdPair>> for MpdResult<MpdSong> {
    fn from_iter<T: Iterator<MpdResult<MpdPair>>>(iterator: T) -> MpdResult<MpdSong> {
        let mut song = MpdSong {
            file: "".to_string(),
            last_mod: Timespec::new(0, 0),
            duration: Duration::zero(),
            place: None,
            range: (Duration::zero(), None),
            tags: BTreeMap::new(),
        };
        let mut place = MpdQueuePlace {
            id: 0,
            pos: 0,
            prio: 0
        };

        let mut iter = iterator;

        for field in iter {
            let MpdPair(key, value) = try!(field);
            match key[] {
                "file" => song.file = value,
                "Last-Modified" => song.last_mod = try!(strptime(value[], "%Y-%m-%dT%H:%M:%S%Z").map_err(|_| standard_error(IoErrorKind::InvalidInput))).to_timespec(),
                "Time" => song.duration = Duration::seconds(value.parse().unwrap_or(0)),
                "Range" => {
                    let mut splits = value[].split('-').flat_map(|v| v.parse::<i64>().into_iter());
                    match (splits.next(), splits.next()) {
                        (Some(s), Some(e)) => song.range = (Duration::seconds(s), Some(Duration::seconds(e))),
                        (None, Some(e)) => song.range = (Duration::zero(), Some(Duration::seconds(e))),
                        (Some(s), None) => song.range = (Duration::seconds(s), None),
                        (None, None) => (),
                    }
                },
                "Id" => place.id = value.parse().unwrap_or(0),
                "Pos" => place.pos = value.parse().unwrap_or(0),
                "Prio" => place.prio = value.parse().unwrap_or(0),
                _ => { song.tags.insert(key, value); }
            }
        }

        if place.id > 0 {
            song.place = Some(place);
        }

        Ok(song)
    }
}

mpd_collectable!(MpdSong, "file");
<commit_msg>priority is u8<commit_after>
use std::time::duration::Duration;
use std::io::{standard_error, IoErrorKind, Stream};
use std::iter::FromIterator;
use std::collections::BTreeMap;
use time::{Timespec, strptime};
use rustc_serialize::{Encoder, Encodable};

use error::MpdResult;
use client::{MpdPair, MpdClient};
use utils::{FieldCutIter, ForceEncodable};

#[derive(Show, Copy, RustcEncodable)]
pub struct MpdQueuePlace {
    pub id: uint,
    pub pos: uint,
    pub prio: u8
}

#[derive(Show, RustcEncodable)]
pub struct MpdSong {
    pub file: String,
    pub last_mod: Timespec,
    pub duration: Duration,
    pub place: Option<MpdQueuePlace>,
    pub range: (Duration, Option<Duration>),
    pub tags: BTreeMap<String, String>,
}

impl MpdSong {
    pub fn seek<S: Stream>(&self, cli: &mut MpdClient<S>, time: Duration) -> MpdResult<()> {
        cli.exec_arg2("seekid", self.place.unwrap().id, time.num_milliseconds() as f32 / 1000f32)
    }
}

impl FromIterator<MpdResult<MpdPair>> for MpdResult<MpdSong> {
    fn from_iter<T: Iterator<MpdResult<MpdPair>>>(iterator: T) -> MpdResult<MpdSong> {
        let mut song = MpdSong {
            file: "".to_string(),
            last_mod: Timespec::new(0, 0),
            duration: Duration::zero(),
            place: None,
            range: (Duration::zero(), None),
            tags: BTreeMap::new(),
        };
        let mut place = MpdQueuePlace {
            id: 0,
            pos: 0,
            prio: 0
        };

        let mut iter = iterator;

        for field in iter {
            let MpdPair(key, value) = try!(field);
            match key[] {
                "file" => song.file = value,
                "Last-Modified" => song.last_mod = try!(strptime(value[], "%Y-%m-%dT%H:%M:%S%Z").map_err(|_| standard_error(IoErrorKind::InvalidInput))).to_timespec(),
                "Time" => song.duration = Duration::seconds(value.parse().unwrap_or(0)),
                "Range" => {
                    let mut splits = value[].split('-').flat_map(|v| v.parse::<i64>().into_iter());
                    match (splits.next(), splits.next()) {
                        (Some(s), Some(e)) => song.range = (Duration::seconds(s), Some(Duration::seconds(e))),
                        (None, Some(e)) => song.range = (Duration::zero(), Some(Duration::seconds(e))),
                        (Some(s), None) => song.range = (Duration::seconds(s), None),
                        (None, None) => (),
                    }
                },
                "Id" => place.id = value.parse().unwrap_or(0),
                "Pos" => place.pos = value.parse().unwrap_or(0),
                "Prio" => place.prio = value.parse().unwrap_or(0),
                _ => { song.tags.insert(key, value); }
            }
        }

        if place.id > 0 {
            song.place = Some(place);
        }

        Ok(song)
    }
}

mpd_collectable!(MpdSong, "file");
<|endoftext|>


<commit_before>use variables::*;
use variables::LpExpression::*;
use std::rc::Rc;
use operations::LpOperations;
use problem::LpFileFormat;

#[test]
fn expressions_creation() {
    let ref a = LpInteger::new("a")
        .lower_bound(10.0)
        .upper_bound(20.0);
    let ref b = LpInteger::new("b");

    assert_eq!(a + b, AddExpr(Rc::new(ConsInt(a.clone())), Rc::new(ConsInt(b.clone()))));
}

#[test]
fn distributivity() {

    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    let test = a * (2 + b) * 3;
    let test2 = test.clone();
    assert_eq!( (2 * (2 + a)).to_lp_file_format(), "2 a + 4");
    assert_eq!( ((2+a) * (2+b)).to_lp_file_format(), "2 a + 2 b + b a + 4" );
    assert_eq!( test.to_lp_file_format(), "6 a + 3 a b" );
    assert_eq!( (10 * test).to_lp_file_format(), "60 a + 30 a b" );
    assert_eq!( ((c + 10) * test2).to_lp_file_format(), "6 c a + 3 c a b + 60 a + 30 a b" );

}

#[test]
fn associativity() {

    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    assert_eq!( (a + (b + 2)).to_lp_file_format(), "a + b + 2" );
    assert_eq!( ((a + b) + 2).to_lp_file_format(), "a + b + 2" );

    assert_eq!( (a + (b - 2)).to_lp_file_format(), "a + b - 2" );
    assert_eq!( ((a + b) - 2).to_lp_file_format(), "a + b - 2" );

    assert_eq!( (a - (b + 2)).to_lp_file_format(), "a - b - 2" );
    assert_eq!( ((a - b) + 2).to_lp_file_format(), "a - b + 2" );

    assert_eq!( (a - (b - 2)).to_lp_file_format(), "a - b + 2" );
    assert_eq!( ((a - b) - 2).to_lp_file_format(), "a - b - 2" );

    assert_eq!( (a - (b - 2) + c).to_lp_file_format(), "a - b + c + 2" );
    assert_eq!( ((a - b) - 2 + c).to_lp_file_format(), "a - b + c - 2" );
}

#[test]
fn literal_first_with_accumulation() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    assert_eq!( (a + 1 + b + 2 + c + 3 + a + 4).to_lp_file_format(), "a + b + c + a + 10");
    assert_eq!( (a - 1 + b - 2 - c + 3 + a - 4).to_lp_file_format(), "a + b - c + a - 4");
    assert_eq!( (a + b + 1 - c - a - 3).to_lp_file_format(), "a + b - c - a - 2");
    assert_eq!( (a + b + (c - 1) * 2 - a - 3).to_lp_file_format(), "a + b + 2 c - a - 5");
    assert_eq!( (a + b + (1 - c) * 2 - a - 3).to_lp_file_format(), "a + b - 2 c - a - 1");
    assert_eq!( (2*(a + 5)).to_lp_file_format(), "2 a + 10");
    assert_eq!( ((2+b)*(a + 5)).to_lp_file_format(), "2 a + a b + 5 b + 10");
    assert_eq!( (2 + (a+b) + 3).to_lp_file_format(), "a + b + 5");

}

#[test]
fn trivial_rules() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");

    assert_eq!( ((a+b) * 0).to_lp_file_format(), "0");
    assert_eq!( ( 0 * (a+b)).to_lp_file_format(), "0");
    assert_eq!( ((a+b) + 0).to_lp_file_format(), "a + b");
    assert_eq!( (0 + (a+b)).to_lp_file_format(), "a + b");

}

#[test]
fn expressions_to_lp_file_format() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    // Expressions
    assert_eq!((a + 2*b + c).to_lp_file_format(), "a + 2 b + c");
    assert_eq!((a + b*2 + c).to_lp_file_format(), "a + 2 b + c");
    assert_eq!((a + b*2 + 3 * 2 * c).to_lp_file_format(), "a + 2 b + 6 c");
    assert_eq!((a + 2).to_lp_file_format(), "a + 2");
    assert_eq!((2*a + 2*b -4*c).to_lp_file_format(), "2 a + 2 b - 4 c");
    assert_eq!((-2*a).to_lp_file_format(), "-2 a");

    // Constraints
    assert_eq!((a+b).equal(10).to_lp_file_format(), "a + b = 10");
    assert_eq!((2*a + b).ge(10).to_lp_file_format(), "2 a + b >= 10");
    assert_eq!((2*a + b + 20).ge(c).to_lp_file_format(), "2 a + b - c >= -20");
    assert_eq!((-a).ge(10).to_lp_file_format(), "-a >= 10");
    assert_eq!((2*a - 20 + b).ge(-c).to_lp_file_format(), "2 a + b + c >= 20");
}

#[test]
fn test_readme_example() {
    use problem::{LpObjective, LpProblem};
    use operations::{LpOperations};
    use variables::LpInteger;
    use solvers::{SolverTrait, CbcSolver};

    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
    problem += 10.0 * a + 20.0 * b;

    problem += (500*a + 1200*b + 1500*c).le(10000);
    problem += (a).le(b);

    let solver = CbcSolver::new();

    match solver.run(&problem) {
        Ok((status, res)) => {
            println!("Status {:?}", status);
            for (name, value) in res.iter() {
                println!("value of {} = {}", name, value);
            }
        },
        Err(msg) => println!("{}", msg),
    }

    let output1 = "\\ One Problem

Maximize
  obj: 10 a + 20 b

Subject To
  c1: 500 a + 1200 b + 1500 c <= 10000
  c2: a - b <= 0

".to_string();
    let output2 = problem.to_lp_file_format();
    let output2 = output2.split("Generals").collect::<Vec<&str>>();
    let output2 = output2[0];
    assert_eq!(output1, output2);
}
<commit_msg>Add rules for cummulative addition of the const<commit_after>use variables::*;
use variables::LpExpression::*;
use std::rc::Rc;
use operations::LpOperations;
use problem::LpFileFormat;

#[test]
fn expressions_creation() {
    let ref a = LpInteger::new("a")
        .lower_bound(10.0)
        .upper_bound(20.0);
    let ref b = LpInteger::new("b");

    assert_eq!(a + b, AddExpr(Rc::new(ConsInt(a.clone())), Rc::new(ConsInt(b.clone()))));
}

#[test]
fn distributivity() {

    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    let test = a * (2 + b) * 3;
    let test2 = test.clone();
    assert_eq!( (2 * (2 + a)).to_lp_file_format(), "2 a + 4");
    assert_eq!( ((2+a) * (2+b)).to_lp_file_format(), "2 a + 2 b + b a + 4" );
    assert_eq!( test.to_lp_file_format(), "6 a + 3 a b" );
    assert_eq!( (10 * test).to_lp_file_format(), "60 a + 30 a b" );
    assert_eq!( ((c + 10) * test2).to_lp_file_format(), "6 c a + 3 c a b + 60 a + 30 a b" );

}

#[test]
fn associativity() {

    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    assert_eq!( (a + (b + 2)).to_lp_file_format(), "a + b + 2" );
    assert_eq!( ((a + b) + 2).to_lp_file_format(), "a + b + 2" );

    assert_eq!( (a + (b - 2)).to_lp_file_format(), "a + b - 2" );
    assert_eq!( ((a + b) - 2).to_lp_file_format(), "a + b - 2" );

    assert_eq!( (a - (b + 2)).to_lp_file_format(), "a - b - 2" );
    assert_eq!( ((a - b) + 2).to_lp_file_format(), "a - b + 2" );

    assert_eq!( (a - (b - 2)).to_lp_file_format(), "a - b + 2" );
    assert_eq!( ((a - b) - 2).to_lp_file_format(), "a - b - 2" );

    assert_eq!( (a - (b - 2) + c).to_lp_file_format(), "a - b + c + 2" );
    assert_eq!( ((a - b) - 2 + c).to_lp_file_format(), "a - b + c - 2" );
}

#[test]
fn literal_first_with_accumulation() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    assert_eq!( (a + 1 + b + 2 + c + 3 + a + 4).to_lp_file_format(), "a + b + c + a + 10");
    assert_eq!( (a - 1 + b - 2 - c + 3 + a - 4).to_lp_file_format(), "a + b - c + a - 4");
    assert_eq!( (a + b + 1 - c - a - 3).to_lp_file_format(), "a + b - c - a - 2");
    assert_eq!( (a + b + (c - 1) * 2 - a - 3).to_lp_file_format(), "a + b + 2 c - a - 5");
    assert_eq!( (a + b + (1 - c) * 2 - a - 3).to_lp_file_format(), "a + b - 2 c - a - 1");
    assert_eq!( (2*(a + 5)).to_lp_file_format(), "2 a + 10");
    assert_eq!( ((2+b)*(a + 5)).to_lp_file_format(), "2 a + a b + 5 b + 10");
    assert_eq!( (2 + (a+b) + 3).to_lp_file_format(), "a + b + 5");

}

#[test]
fn trivial_rules() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");

    assert_eq!( ((a+b) * 0).to_lp_file_format(), "0");
    assert_eq!( ( 0 * (a+b)).to_lp_file_format(), "0");
    assert_eq!( ((a+b) + 0).to_lp_file_format(), "a + b");
    assert_eq!( (0 + (a+b) + 0).to_lp_file_format(), "a + b");
    assert_eq!( (0 + (a+b)).to_lp_file_format(), "a + b");
    assert_eq!( ((a+b) - 0).to_lp_file_format(), "a + b");
    assert_eq!( (0 - (a+b)).to_lp_file_format(), "-a - b");
    assert_eq!( (0 + (a+b)).to_lp_file_format(), "a + b");

}

#[test]
fn expressions_to_lp_file_format() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    // Expressions
    assert_eq!((a + 2*b + c).to_lp_file_format(), "a + 2 b + c");
    assert_eq!((a + b*2 + c).to_lp_file_format(), "a + 2 b + c");
    assert_eq!((a + b*2 + 3 * 2 * c).to_lp_file_format(), "a + 2 b + 6 c");
    assert_eq!((a + 2).to_lp_file_format(), "a + 2");
    assert_eq!((2*a + 2*b -4*c).to_lp_file_format(), "2 a + 2 b - 4 c");
    assert_eq!((-2*a).to_lp_file_format(), "-2 a");

    // Constraints
    assert_eq!((a+b).equal(10).to_lp_file_format(), "a + b = 10");
    assert_eq!((2*a + b).ge(10).to_lp_file_format(), "2 a + b >= 10");
    assert_eq!((2*a + b + 20).ge(c).to_lp_file_format(), "2 a + b - c >= -20");
    assert_eq!((-a).ge(10).to_lp_file_format(), "-a >= 10");
    assert_eq!((2*a - 20 + b).ge(-c).to_lp_file_format(), "2 a + b + c >= 20");
}

#[test]
fn test_readme_example() {
    use problem::{LpObjective, LpProblem};
    use operations::{LpOperations};
    use variables::LpInteger;
    use solvers::{SolverTrait, CbcSolver};

    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
    problem += 10.0 * a + 20.0 * b;

    problem += (500*a + 1200*b + 1500*c).le(10000);
    problem += (a).le(b);

    let solver = CbcSolver::new();

    match solver.run(&problem) {
        Ok((status, res)) => {
            println!("Status {:?}", status);
            for (name, value) in res.iter() {
                println!("value of {} = {}", name, value);
            }
        },
        Err(msg) => println!("{}", msg),
    }

    let output1 = "\\ One Problem

Maximize
  obj: 10 a + 20 b

Subject To
  c1: 500 a + 1200 b + 1500 c <= 10000
  c2: a - b <= 0

".to_string();
    let output2 = problem.to_lp_file_format();
    let output2 = output2.split("Generals").collect::<Vec<&str>>();
    let output2 = output2[0];
    assert_eq!(output1, output2);
}
<|endoftext|>


<commit_before>use std::error;
use std::os::raw::c_int;
use std::convert::{From, Into};
use std::result;
use std::fmt;

use ffi;

pub type PortMidiDeviceId = c_int;

/// PortMidi result type.
pub type Result<T> = result::Result<T, Error>;
impl From<ffi::PmError> for Result<()> {
    fn from(err: ffi::PmError) -> Self {
        match err {
            ffi::PmError::PmNoError | ffi::PmError::PmGotData => Ok(()),
            _ => Err(Error::PortMidi(err)),
        }
    }
}

/// PortMidi error type.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Error {
    PortMidi(ffi::PmError),
    Unknown,
    Unimplemented,
    NoDefaultDevice,
    NotAnInputDevice,
    NotAnOutputDevice,
    Invalid,
}
impl From<ffi::PmError> for Error {
    fn from(err: ffi::PmError) -> Self {
        match err {
            err @ _ => Error::PortMidi(err),
        }
    }
}
impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::PortMidi(pm_err) => write!(f, "{}", pm_err),
            err @ _ => write!(f, "{:?}", err),
        }
    }
}
impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::PortMidi(pm_error)   => match pm_error {
                ffi::PmError::PmNoError             => "",
                ffi::PmError::PmGotData             => "PortMidi: `Illegal error number'",
                ffi::PmError::PmHostError           => "PortMidi: `Host error'",
                ffi::PmError::PmInvalidDeviceId     => "PortMidi: `Invalid device ID'",
                ffi::PmError::PmInsufficientMemory  => "PortMidi: `Insufficient memory'",
                ffi::PmError::PmBufferTooSmall      => "PortMidi: `Buffer too small'",
                ffi::PmError::PmBufferOverflow      => "PortMidi: `Buffer overflow'",
                ffi::PmError::PmBadPtr              => "PortMidi: `Bad pointer'",
                ffi::PmError::PmBadData             => "PortMidi: `Invalid MIDI message Data'",
                ffi::PmError::PmInternalError       => "PortMidi: `Internal PortMidi Error'",
                ffi::PmError::PmBufferMaxSize       => "PortMidi: `Buffer cannot be made larger'"
            },
            Error::Unknown              => "Unknown",
            Error::Unimplemented        => "Unimplemented",
            Error::NoDefaultDevice      => "No default device",
            Error::NotAnInputDevice     => "Not an input device",
            Error::NotAnOutputDevice    => "Not an output device",
            Error::Invalid              => "Invalid"
        }
    }
}

/// Represents a Midi message.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MidiMessage {
    pub status: u8,
    pub data1: u8,
    pub data2: u8,
}
impl From<[u8; 3]> for MidiMessage {
    fn from(raw: [u8; 3]) -> Self {
        MidiMessage {
            status: raw[0],
            data1: raw[1],
            data2: raw[2],
        }
    }
}
impl fmt::Display for MidiMessage {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "status: {}, data: {}, {}",
               self.status,
               self.data1,
               self.data2)
    }
}
/// Converts a `PmMessage` to a `MidiMessage.
/// This can be used for `c_int` as well as `i32` because these are only type aliases.
impl From<ffi::PmMessage> for MidiMessage {
    fn from(raw: i32) -> Self {
        MidiMessage {
            status: (raw & 0x00_00_00_FF) as u8,
            data1: ((raw & 0x00_00_FF_00) >> 8) as u8,
            data2: ((raw & 0x00_FF_00_00) >> 16) as u8,
        }
    }
}
impl Into<ffi::PmMessage> for MidiMessage {
    fn into(self) -> i32 {
        (((self.data2 as i32) << 16)) | (((self.data1 as i32) << 8)) | self.status as i32
    }
}

/// Represents a time stamped midi event. See also `MidiMessage`
///
/// See the PortMidi documentation for how SysEx and midi realtime messages
/// are handled
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MidiEvent {
    pub message: MidiMessage,
    pub timestamp: ffi::PmTimestamp,
}
impl From<ffi::PmEvent> for MidiEvent {
    fn from(raw: ffi::PmEvent) -> Self {
        MidiEvent {
            message: MidiMessage::from(raw.message),
            timestamp: raw.timestamp,
        }
    }
}
impl From<MidiMessage> for MidiEvent {
    fn from(msg: MidiMessage) -> Self {
        MidiEvent {
            message: msg,
            timestamp: 0,
        }
    }
}
impl Into<ffi::PmEvent> for MidiEvent {
    fn into(self) -> ffi::PmEvent {
        ffi::PmEvent {
            message: MidiMessage::into(self.message),
            timestamp: self.timestamp,
        }
    }
}
<commit_msg>Prefix non-FFI error descriptions w/ portmidi-rs<commit_after>use std::error;
use std::os::raw::c_int;
use std::convert::{From, Into};
use std::result;
use std::fmt;

use ffi;

pub type PortMidiDeviceId = c_int;

/// PortMidi result type.
pub type Result<T> = result::Result<T, Error>;
impl From<ffi::PmError> for Result<()> {
    fn from(err: ffi::PmError) -> Self {
        match err {
            ffi::PmError::PmNoError | ffi::PmError::PmGotData => Ok(()),
            _ => Err(Error::PortMidi(err)),
        }
    }
}

/// PortMidi error type.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Error {
    PortMidi(ffi::PmError),
    Unknown,
    Unimplemented,
    NoDefaultDevice,
    NotAnInputDevice,
    NotAnOutputDevice,
    Invalid,
}
impl From<ffi::PmError> for Error {
    fn from(err: ffi::PmError) -> Self {
        match err {
            err @ _ => Error::PortMidi(err),
        }
    }
}
impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::PortMidi(pm_err) => write!(f, "{}", pm_err),
            err @ _ => write!(f, "{:?}", err),
        }
    }
}
impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::PortMidi(pm_error)   => match pm_error {
                ffi::PmError::PmNoError             => "",
                ffi::PmError::PmGotData             => "PortMidi: `Illegal error number'",
                ffi::PmError::PmHostError           => "PortMidi: `Host error'",
                ffi::PmError::PmInvalidDeviceId     => "PortMidi: `Invalid device ID'",
                ffi::PmError::PmInsufficientMemory  => "PortMidi: `Insufficient memory'",
                ffi::PmError::PmBufferTooSmall      => "PortMidi: `Buffer too small'",
                ffi::PmError::PmBufferOverflow      => "PortMidi: `Buffer overflow'",
                ffi::PmError::PmBadPtr              => "PortMidi: `Bad pointer'",
                ffi::PmError::PmBadData             => "PortMidi: `Invalid MIDI message Data'",
                ffi::PmError::PmInternalError       => "PortMidi: `Internal PortMidi Error'",
                ffi::PmError::PmBufferMaxSize       => "PortMidi: `Buffer cannot be made larger'"
            },
            Error::Unknown              => "portmidi-rs: Unknown",
            Error::Unimplemented        => "portmidi-rs: Unimplemented",
            Error::NoDefaultDevice      => "portmidi-rs: No default device",
            Error::NotAnInputDevice     => "portmidi-rs: Not an input device",
            Error::NotAnOutputDevice    => "portmidi-rs: Not an output device",
            Error::Invalid              => "portmidi-rs: Invalid"
        }
    }
}

/// Represents a Midi message.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MidiMessage {
    pub status: u8,
    pub data1: u8,
    pub data2: u8,
}
impl From<[u8; 3]> for MidiMessage {
    fn from(raw: [u8; 3]) -> Self {
        MidiMessage {
            status: raw[0],
            data1: raw[1],
            data2: raw[2],
        }
    }
}
impl fmt::Display for MidiMessage {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "status: {}, data: {}, {}",
               self.status,
               self.data1,
               self.data2)
    }
}
/// Converts a `PmMessage` to a `MidiMessage.
/// This can be used for `c_int` as well as `i32` because these are only type aliases.
impl From<ffi::PmMessage> for MidiMessage {
    fn from(raw: i32) -> Self {
        MidiMessage {
            status: (raw & 0x00_00_00_FF) as u8,
            data1: ((raw & 0x00_00_FF_00) >> 8) as u8,
            data2: ((raw & 0x00_FF_00_00) >> 16) as u8,
        }
    }
}
impl Into<ffi::PmMessage> for MidiMessage {
    fn into(self) -> i32 {
        (((self.data2 as i32) << 16)) | (((self.data1 as i32) << 8)) | self.status as i32
    }
}

/// Represents a time stamped midi event. See also `MidiMessage`
///
/// See the PortMidi documentation for how SysEx and midi realtime messages
/// are handled
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MidiEvent {
    pub message: MidiMessage,
    pub timestamp: ffi::PmTimestamp,
}
impl From<ffi::PmEvent> for MidiEvent {
    fn from(raw: ffi::PmEvent) -> Self {
        MidiEvent {
            message: MidiMessage::from(raw.message),
            timestamp: raw.timestamp,
        }
    }
}
impl From<MidiMessage> for MidiEvent {
    fn from(msg: MidiMessage) -> Self {
        MidiEvent {
            message: msg,
            timestamp: 0,
        }
    }
}
impl Into<ffi::PmEvent> for MidiEvent {
    fn into(self) -> ffi::PmEvent {
        ffi::PmEvent {
            message: MidiMessage::into(self.message),
            timestamp: self.timestamp,
        }
    }
}
<|endoftext|>


<commit_before>use std::process::Command;
use std::path::Path;
use std::fs::File;
use std::io::{Read, Write};
use std::error::Error;
use std::env;

pub struct ExecutionStatus {
    status: Option< i32 >
}

impl ExecutionStatus {
    pub fn is_ok( &self ) -> bool {
        self.status == Some( 0 )
    }
}

pub trait CommandExt {
    fn run( &mut self ) -> ExecutionStatus;
    fn append_to_path< P: AsRef< Path > >( &mut self, path: P ) -> &mut Self;
}

impl CommandExt for Command {
    fn run( &mut self ) -> ExecutionStatus {
        let mut child = match self.spawn() {
            Ok( child ) => child,
            Err( _ ) => {
                return ExecutionStatus {
                    status: None
                };
            }
        };
        let result = child.wait();
        let status = result.unwrap().code().unwrap();
        ExecutionStatus {
            status: Some( status )
        }
    }

    fn append_to_path< P: AsRef< Path > >( &mut self, path: P ) -> &mut Self {
        let mut paths = env::var_os( "PATH" ).map( |paths| env::split_paths( &paths ).collect() ).unwrap_or( Vec::new() );
        paths.push( path.as_ref().into() );
        let new_path = env::join_paths( paths ).unwrap();

        self.env( "PATH", new_path );
        self
    }
}

pub fn read< P: AsRef< Path > >( path: P ) -> Result< String, Box< Error > > {
    let mut fp = File::open( path.as_ref() )?;
    let mut output = String::new();
    fp.read_to_string( &mut output )?;
    Ok( output )
}

pub fn write< P: AsRef< Path > >( path: P, string: &str ) -> Result< (), Box< Error > > {
    let mut fp = File::create( path )?;
    fp.write_all( string.as_bytes() )?;
    Ok( () )
}
<commit_msg>Switch from Box< Error > to io::Error in utils.rs<commit_after>use std::process::Command;
use std::path::Path;
use std::fs::File;
use std::io::{self, Read, Write};
use std::env;

pub struct ExecutionStatus {
    status: Option< i32 >
}

impl ExecutionStatus {
    pub fn is_ok( &self ) -> bool {
        self.status == Some( 0 )
    }
}

pub trait CommandExt {
    fn run( &mut self ) -> ExecutionStatus;
    fn append_to_path< P: AsRef< Path > >( &mut self, path: P ) -> &mut Self;
}

impl CommandExt for Command {
    fn run( &mut self ) -> ExecutionStatus {
        let mut child = match self.spawn() {
            Ok( child ) => child,
            Err( _ ) => {
                return ExecutionStatus {
                    status: None
                };
            }
        };
        let result = child.wait();
        let status = result.unwrap().code().unwrap();
        ExecutionStatus {
            status: Some( status )
        }
    }

    fn append_to_path< P: AsRef< Path > >( &mut self, path: P ) -> &mut Self {
        let mut paths = env::var_os( "PATH" ).map( |paths| env::split_paths( &paths ).collect() ).unwrap_or( Vec::new() );
        paths.push( path.as_ref().into() );
        let new_path = env::join_paths( paths ).unwrap();

        self.env( "PATH", new_path );
        self
    }
}

pub fn read< P: AsRef< Path > >( path: P ) -> Result< String, io::Error > {
    let mut fp = File::open( path.as_ref() )?;
    let mut output = String::new();
    fp.read_to_string( &mut output )?;
    Ok( output )
}

pub fn write< P: AsRef< Path > >( path: P, string: &str ) -> Result< (), io::Error > {
    let mut fp = File::create( path )?;
    fp.write_all( string.as_bytes() )?;
    Ok( () )
}
<|endoftext|>


<commit_before>extern crate c_ares_sys;

use c_types;

use error::AresError;
use types::AddressFamily;
use std::mem;
use std::os::raw::c_int;
use std::net::{
    Ipv4Addr,
    Ipv6Addr,
    SocketAddrV4,
    SocketAddrV6,
};

// Convert an error code from the library into a more strongly typed AresError.
pub fn ares_error(code: c_int) -> AresError {
    match code {
        c_ares_sys::ARES_ENODATA => AresError::ENODATA,
        c_ares_sys::ARES_EFORMERR => AresError::EFORMERR,
        c_ares_sys::ARES_ESERVFAIL => AresError::ESERVFAIL,
        c_ares_sys::ARES_ENOTFOUND => AresError::ENOTFOUND,
        c_ares_sys::ARES_ENOTIMP => AresError::ENOTIMP,
        c_ares_sys::ARES_EREFUSED => AresError::EREFUSED,
        c_ares_sys::ARES_EBADQUERY => AresError::EBADQUERY,
        c_ares_sys::ARES_EBADNAME => AresError::EBADNAME,
        c_ares_sys::ARES_EBADFAMILY => AresError::EBADFAMILY,
        c_ares_sys::ARES_EBADRESP => AresError::EBADRESP,
        c_ares_sys::ARES_ECONNREFUSED => AresError::ECONNREFUSED,
        c_ares_sys::ARES_ETIMEOUT => AresError::ETIMEOUT,
        c_ares_sys::ARES_EOF => AresError::EOF,
        c_ares_sys::ARES_EFILE => AresError::EFILE,
        c_ares_sys::ARES_ENOMEM => AresError::ENOMEM,
        c_ares_sys::ARES_EDESTRUCTION => AresError::EDESTRUCTION,
        c_ares_sys::ARES_EBADSTR => AresError::EBADSTR,
        c_ares_sys::ARES_EBADFLAGS => AresError::EBADFLAGS,
        c_ares_sys::ARES_ENONAME => AresError::ENONAME,
        c_ares_sys::ARES_EBADHINTS => AresError::EBADHINTS,
        c_ares_sys::ARES_ENOTINITIALIZED => AresError::ENOTINITIALIZED,
        c_ares_sys::ARES_ELOADIPHLPAPI => AresError::ELOADIPHLPAPI,
        c_ares_sys::ARES_EADDRGETNETWORKPARAMS =>
            AresError::EADDRGETNETWORKPARAMS,
        c_ares_sys::ARES_ECANCELLED => AresError::ECANCELLED,
        _ => AresError::UNKNOWN,
    }
}

// Convert an address family into a more strongly typed AddressFamily.
pub fn address_family(family: c_int) -> Option<AddressFamily> {
    match family {
        c_types::AF_INET => Some(AddressFamily::INET),
        c_types::AF_INET6 => Some(AddressFamily::INET6),
        _ => None,
    }
}

// Get an in_addr from an Ipv4Addr.
#[cfg(unix)]
pub fn ipv4_as_in_addr(ipv4: &Ipv4Addr) -> c_types::in_addr {
    c_types::in_addr { s_addr: u32::from(*ipv4).to_be() }
}

#[cfg(windows)]
pub fn ipv4_as_in_addr(ipv4: &Ipv4Addr) -> c_types::in_addr {
    c_types::in_addr { S_un: u32::from(*ipv4).to_be() }
}

// Get an Ipv4Addr from an in_addr.
#[cfg(unix)]
pub fn ipv4_from_in_addr(in_addr: &c_types::in_addr) -> Ipv4Addr {
    Ipv4Addr::from(u32::from_be(in_addr.s_addr))
}

#[cfg(windows)]
pub fn ipv4_from_in_addr(in_addr: &c_types::in_addr) -> Ipv4Addr {
    Ipv4Addr::from(u32::from_be(in_addr.S_un))
}

// Get an in6_addr from an Ipv6Addr.
pub fn ipv6_as_in6_addr(ipv6: &Ipv6Addr) -> c_types::in6_addr {
    let segments = ipv6.segments();
    let mut in6_addr: c_types::in6_addr = unsafe { mem::uninitialized() };
    in6_addr.s6_addr[0] = (segments[0] >> 8) as u8;
    in6_addr.s6_addr[1] = segments[0] as u8;
    in6_addr.s6_addr[2] = (segments[1] >> 8) as u8;
    in6_addr.s6_addr[3] = segments[1] as u8;
    in6_addr.s6_addr[4] = (segments[2] >> 8) as u8;
    in6_addr.s6_addr[5] = segments[2] as u8;
    in6_addr.s6_addr[6] = (segments[3] >> 8) as u8;
    in6_addr.s6_addr[7] = segments[3] as u8;
    in6_addr.s6_addr[8] = (segments[4] >> 8) as u8;
    in6_addr.s6_addr[9] = segments[4] as u8;
    in6_addr.s6_addr[10] = (segments[5] >> 8) as u8;
    in6_addr.s6_addr[11] = segments[5] as u8;
    in6_addr.s6_addr[12] = (segments[6] >> 8) as u8;
    in6_addr.s6_addr[13] = segments[6] as u8;
    in6_addr.s6_addr[14] = (segments[7] >> 8) as u8;
    in6_addr.s6_addr[15] = segments[7] as u8;
    in6_addr
}

// Get an Ipv4Addr from an array of four bytes, as found in a `hostent`.
pub fn ipv4_address_from_bytes(bytes: &[u8]) -> Ipv4Addr {
    Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3])
}

// Get an Ipv6Addr from an array of sixteen bytes, as found in a `hostent`.
pub fn ipv6_address_from_bytes(bytes: &[u8]) -> Ipv6Addr {
    Ipv6Addr::new(
        ((bytes[0] as u16) << 8) | bytes[1] as u16,
        ((bytes[2] as u16) << 8) | bytes[3] as u16,
        ((bytes[4] as u16) << 8) | bytes[5] as u16,
        ((bytes[6] as u16) << 8) | bytes[7] as u16,
        ((bytes[8] as u16) << 8) | bytes[9] as u16,
        ((bytes[10] as u16) << 8) | bytes[11] as u16,
        ((bytes[12] as u16) << 8) | bytes[13] as u16,
        ((bytes[14] as u16) << 8) | bytes[15] as u16)
}

// Get a sockaddr_in from a SocketAddrV4.
#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "openbsd",
          target_os = "netbsd",
          target_os = "bitrig"))]
pub fn socket_addrv4_as_sockaddr_in(
    sock_v4: &SocketAddrV4) -> c_types::sockaddr_in {
    let in_addr = ipv4_as_in_addr(sock_v4.ip());
    c_types::sockaddr_in {
        sin_len: mem::size_of::<c_types::sockaddr_in>() as u8,
        sin_family: c_types::AF_INET as c_types::sa_family_t,
        sin_port: sock_v4.port().to_be(),
        sin_addr: in_addr,
        sin_zero: [0; 8],
    }
}

#[cfg(not(any(target_os = "macos",
              target_os = "ios",
              target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "openbsd",
              target_os = "netbsd",
              target_os = "bitrig")))]
pub fn socket_addrv4_as_sockaddr_in(
    sock_v4: &SocketAddrV4) -> c_types::sockaddr_in {
    let in_addr = ipv4_as_in_addr(sock_v4.ip());
    c_types::sockaddr_in {
        sin_family: c_types::AF_INET as c_types::sa_family_t,
        sin_port: sock_v4.port().to_be(),
        sin_addr: in_addr,
        sin_zero: [0; 8],
    }
}

// Get a sockaddr_in6 from a SocketAddrV6.
#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "openbsd",
          target_os = "netbsd",
          target_os = "bitrig"))]
pub fn socket_addrv6_as_sockaddr_in6(
    sock_v6: &SocketAddrV6) -> c_types::sockaddr_in6 {
    let in6_addr = ipv6_as_in6_addr(sock_v6.ip());
    c_types::sockaddr_in6 {
        sin6_len: mem::size_of::<c_types::sockaddr_in6>() as u8,
        sin6_family: c_types::AF_INET6 as c_types::sa_family_t,
        sin6_port: sock_v6.port().to_be(),
        sin6_addr: in6_addr,
        sin6_flowinfo: sock_v6.flowinfo().to_be(),
        sin6_scope_id: sock_v6.scope_id().to_be(),
    }
}

#[cfg(all(unix,not(any(target_os = "macos",
                       target_os = "ios",
                       target_os = "freebsd",
                       target_os = "dragonfly",
                       target_os = "openbsd",
                       target_os = "netbsd",
                       target_os = "bitrig"))))]
pub fn socket_addrv6_as_sockaddr_in6(
    sock_v6: &SocketAddrV6) -> c_types::sockaddr_in6 {
    let in6_addr = ipv6_as_in6_addr(sock_v6.ip());
    c_types::sockaddr_in6 {
        sin6_family: c_types::AF_INET6 as c_types::sa_family_t,
        sin6_port: sock_v6.port().to_be(),
        sin6_addr: in6_addr,
        sin6_flowinfo: sock_v6.flowinfo().to_be(),
        sin6_scope_id: sock_v6.scope_id().to_be(),
    }
}

#[cfg(windows)]
pub fn socket_addrv6_as_sockaddr_in6(
    sock_v6: &SocketAddrV6) -> c_types::sockaddr_in6 {
    let in6_addr = ipv6_as_in6_addr(sock_v6.ip());
    c_types::sockaddr_in6 {
        sin6_family: c_types::AF_INET6 as i16,
        sin6_port: sock_v6.port().to_be(),
        sin6_addr: in6_addr,
        sin6_flowinfo: sock_v6.flowinfo().to_be(),
        sin6_scope_id: sock_v6.scope_id().to_be(),
    }
}
<commit_msg>Host byte order for some sockaddr_in6 fields<commit_after>extern crate c_ares_sys;

use c_types;

use error::AresError;
use types::AddressFamily;
use std::mem;
use std::os::raw::c_int;
use std::net::{
    Ipv4Addr,
    Ipv6Addr,
    SocketAddrV4,
    SocketAddrV6,
};

// Convert an error code from the library into a more strongly typed AresError.
pub fn ares_error(code: c_int) -> AresError {
    match code {
        c_ares_sys::ARES_ENODATA => AresError::ENODATA,
        c_ares_sys::ARES_EFORMERR => AresError::EFORMERR,
        c_ares_sys::ARES_ESERVFAIL => AresError::ESERVFAIL,
        c_ares_sys::ARES_ENOTFOUND => AresError::ENOTFOUND,
        c_ares_sys::ARES_ENOTIMP => AresError::ENOTIMP,
        c_ares_sys::ARES_EREFUSED => AresError::EREFUSED,
        c_ares_sys::ARES_EBADQUERY => AresError::EBADQUERY,
        c_ares_sys::ARES_EBADNAME => AresError::EBADNAME,
        c_ares_sys::ARES_EBADFAMILY => AresError::EBADFAMILY,
        c_ares_sys::ARES_EBADRESP => AresError::EBADRESP,
        c_ares_sys::ARES_ECONNREFUSED => AresError::ECONNREFUSED,
        c_ares_sys::ARES_ETIMEOUT => AresError::ETIMEOUT,
        c_ares_sys::ARES_EOF => AresError::EOF,
        c_ares_sys::ARES_EFILE => AresError::EFILE,
        c_ares_sys::ARES_ENOMEM => AresError::ENOMEM,
        c_ares_sys::ARES_EDESTRUCTION => AresError::EDESTRUCTION,
        c_ares_sys::ARES_EBADSTR => AresError::EBADSTR,
        c_ares_sys::ARES_EBADFLAGS => AresError::EBADFLAGS,
        c_ares_sys::ARES_ENONAME => AresError::ENONAME,
        c_ares_sys::ARES_EBADHINTS => AresError::EBADHINTS,
        c_ares_sys::ARES_ENOTINITIALIZED => AresError::ENOTINITIALIZED,
        c_ares_sys::ARES_ELOADIPHLPAPI => AresError::ELOADIPHLPAPI,
        c_ares_sys::ARES_EADDRGETNETWORKPARAMS =>
            AresError::EADDRGETNETWORKPARAMS,
        c_ares_sys::ARES_ECANCELLED => AresError::ECANCELLED,
        _ => AresError::UNKNOWN,
    }
}

// Convert an address family into a more strongly typed AddressFamily.
pub fn address_family(family: c_int) -> Option<AddressFamily> {
    match family {
        c_types::AF_INET => Some(AddressFamily::INET),
        c_types::AF_INET6 => Some(AddressFamily::INET6),
        _ => None,
    }
}

// Get an in_addr from an Ipv4Addr.
#[cfg(unix)]
pub fn ipv4_as_in_addr(ipv4: &Ipv4Addr) -> c_types::in_addr {
    c_types::in_addr { s_addr: u32::from(*ipv4).to_be() }
}

#[cfg(windows)]
pub fn ipv4_as_in_addr(ipv4: &Ipv4Addr) -> c_types::in_addr {
    c_types::in_addr { S_un: u32::from(*ipv4).to_be() }
}

// Get an Ipv4Addr from an in_addr.
#[cfg(unix)]
pub fn ipv4_from_in_addr(in_addr: &c_types::in_addr) -> Ipv4Addr {
    Ipv4Addr::from(u32::from_be(in_addr.s_addr))
}

#[cfg(windows)]
pub fn ipv4_from_in_addr(in_addr: &c_types::in_addr) -> Ipv4Addr {
    Ipv4Addr::from(u32::from_be(in_addr.S_un))
}

// Get an in6_addr from an Ipv6Addr.
pub fn ipv6_as_in6_addr(ipv6: &Ipv6Addr) -> c_types::in6_addr {
    let segments = ipv6.segments();
    let mut in6_addr: c_types::in6_addr = unsafe { mem::uninitialized() };
    in6_addr.s6_addr[0] = (segments[0] >> 8) as u8;
    in6_addr.s6_addr[1] = segments[0] as u8;
    in6_addr.s6_addr[2] = (segments[1] >> 8) as u8;
    in6_addr.s6_addr[3] = segments[1] as u8;
    in6_addr.s6_addr[4] = (segments[2] >> 8) as u8;
    in6_addr.s6_addr[5] = segments[2] as u8;
    in6_addr.s6_addr[6] = (segments[3] >> 8) as u8;
    in6_addr.s6_addr[7] = segments[3] as u8;
    in6_addr.s6_addr[8] = (segments[4] >> 8) as u8;
    in6_addr.s6_addr[9] = segments[4] as u8;
    in6_addr.s6_addr[10] = (segments[5] >> 8) as u8;
    in6_addr.s6_addr[11] = segments[5] as u8;
    in6_addr.s6_addr[12] = (segments[6] >> 8) as u8;
    in6_addr.s6_addr[13] = segments[6] as u8;
    in6_addr.s6_addr[14] = (segments[7] >> 8) as u8;
    in6_addr.s6_addr[15] = segments[7] as u8;
    in6_addr
}

// Get an Ipv4Addr from an array of four bytes, as found in a `hostent`.
pub fn ipv4_address_from_bytes(bytes: &[u8]) -> Ipv4Addr {
    Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3])
}

// Get an Ipv6Addr from an array of sixteen bytes, as found in a `hostent`.
pub fn ipv6_address_from_bytes(bytes: &[u8]) -> Ipv6Addr {
    Ipv6Addr::new(
        ((bytes[0] as u16) << 8) | bytes[1] as u16,
        ((bytes[2] as u16) << 8) | bytes[3] as u16,
        ((bytes[4] as u16) << 8) | bytes[5] as u16,
        ((bytes[6] as u16) << 8) | bytes[7] as u16,
        ((bytes[8] as u16) << 8) | bytes[9] as u16,
        ((bytes[10] as u16) << 8) | bytes[11] as u16,
        ((bytes[12] as u16) << 8) | bytes[13] as u16,
        ((bytes[14] as u16) << 8) | bytes[15] as u16)
}

// Get a sockaddr_in from a SocketAddrV4.
#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "openbsd",
          target_os = "netbsd",
          target_os = "bitrig"))]
pub fn socket_addrv4_as_sockaddr_in(
    sock_v4: &SocketAddrV4) -> c_types::sockaddr_in {
    let in_addr = ipv4_as_in_addr(sock_v4.ip());
    c_types::sockaddr_in {
        sin_len: mem::size_of::<c_types::sockaddr_in>() as u8,
        sin_family: c_types::AF_INET as c_types::sa_family_t,
        sin_port: sock_v4.port().to_be(),
        sin_addr: in_addr,
        sin_zero: [0; 8],
    }
}

#[cfg(not(any(target_os = "macos",
              target_os = "ios",
              target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "openbsd",
              target_os = "netbsd",
              target_os = "bitrig")))]
pub fn socket_addrv4_as_sockaddr_in(
    sock_v4: &SocketAddrV4) -> c_types::sockaddr_in {
    let in_addr = ipv4_as_in_addr(sock_v4.ip());
    c_types::sockaddr_in {
        sin_family: c_types::AF_INET as c_types::sa_family_t,
        sin_port: sock_v4.port().to_be(),
        sin_addr: in_addr,
        sin_zero: [0; 8],
    }
}

// Get a sockaddr_in6 from a SocketAddrV6.
#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "openbsd",
          target_os = "netbsd",
          target_os = "bitrig"))]
pub fn socket_addrv6_as_sockaddr_in6(
    sock_v6: &SocketAddrV6) -> c_types::sockaddr_in6 {
    let in6_addr = ipv6_as_in6_addr(sock_v6.ip());
    c_types::sockaddr_in6 {
        sin6_len: mem::size_of::<c_types::sockaddr_in6>() as u8,
        sin6_family: c_types::AF_INET6 as c_types::sa_family_t,
        sin6_port: sock_v6.port().to_be(),
        sin6_addr: in6_addr,
        sin6_flowinfo: sock_v6.flowinfo(),
        sin6_scope_id: sock_v6.scope_id(),
    }
}

#[cfg(all(unix,not(any(target_os = "macos",
                       target_os = "ios",
                       target_os = "freebsd",
                       target_os = "dragonfly",
                       target_os = "openbsd",
                       target_os = "netbsd",
                       target_os = "bitrig"))))]
pub fn socket_addrv6_as_sockaddr_in6(
    sock_v6: &SocketAddrV6) -> c_types::sockaddr_in6 {
    let in6_addr = ipv6_as_in6_addr(sock_v6.ip());
    c_types::sockaddr_in6 {
        sin6_family: c_types::AF_INET6 as c_types::sa_family_t,
        sin6_port: sock_v6.port().to_be(),
        sin6_addr: in6_addr,
        sin6_flowinfo: sock_v6.flowinfo(),
        sin6_scope_id: sock_v6.scope_id(),
    }
}

#[cfg(windows)]
pub fn socket_addrv6_as_sockaddr_in6(
    sock_v6: &SocketAddrV6) -> c_types::sockaddr_in6 {
    let in6_addr = ipv6_as_in6_addr(sock_v6.ip());
    c_types::sockaddr_in6 {
        sin6_family: c_types::AF_INET6 as i16,
        sin6_port: sock_v6.port().to_be(),
        sin6_addr: in6_addr,
        sin6_flowinfo: sock_v6.flowinfo(),
        sin6_scope_id: sock_v6.scope_id(),
    }
}
<|endoftext|>


<commit_before>//! Contains the different types of values understood by XML-RPC.

use utils::{escape_xml, format_datetime};

use base64::encode;
use iso8601::DateTime;

use std::collections::BTreeMap;
use std::io::{self, Write};

/// The possible XML-RPC values.
#[derive(Debug, PartialEq)]
pub enum Value {
    /// `<i4>` or `<int>`, 32-bit signed integer.
    Int(i32),
    /// `<boolean>`, 0 == `false`, 1 == `true`.
    Bool(bool),
    /// `<string>`
    // FIXME zero-copy? `Cow<'static, ..>`?
    String(String),
    /// `<double>`
    Double(f64),
    /// `<dateTime.iso8601>`, an ISO 8601 formatted date/time value.
    DateTime(DateTime),
    /// `<base64>`, base64-encoded binary data.
    Base64(Vec<u8>),

    /// `<struct>`, a mapping of named values.
    Struct(BTreeMap<String, Value>),
    /// `<array>`, a list of arbitrary (heterogeneous) values.
    Array(Vec<Value>),

    // TODO Nil
}

impl Value {
    pub fn format<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        try!(writeln!(fmt, "<value>"));

        match *self {
            Value::Int(i) => {
                try!(writeln!(fmt, "<i4>{}</i4>", i));
            }
            Value::Bool(b) => {
                try!(writeln!(fmt, "<boolean>{}</boolean>", if b { "1" } else { "0" }));
            }
            Value::String(ref s) => {
                try!(writeln!(fmt, "<string>{}</string>", escape_xml(s)));
            }
            Value::Double(d) => {
                try!(writeln!(fmt, "<double>{}</double>", d));
            }
            Value::DateTime(date_time) => {
                try!(writeln!(fmt, "<dateTime.iso8601>{}</dateTime.iso8601>", format_datetime(&date_time)));
            }
            Value::Base64(ref data) => {
                try!(writeln!(fmt, "<base64>{}</base64>", encode(data)));
            }
            Value::Struct(ref map) => {
                try!(writeln!(fmt, "<struct>"));
                for (ref name, ref value) in map {
                    try!(writeln!(fmt, "<member>"));
                    try!(writeln!(fmt, "<name>{}</name>", escape_xml(name)));
                    try!(value.format(fmt));
                    try!(writeln!(fmt, "</member>"));
                }
                try!(writeln!(fmt, "</struct>"));
            }
            Value::Array(ref array) => {
                try!(writeln!(fmt, "<array>"));
                try!(writeln!(fmt, "<data>"));
                for value in array {
                    try!(value.format(fmt));
                }
                try!(writeln!(fmt, "</data>"));
                try!(writeln!(fmt, "</array>"));
            }
        }

        try!(writeln!(fmt, "</value>"));
        Ok(())
    }
}

impl From<i32> for Value {
    fn from(other: i32) -> Self {
        Value::Int(other)
    }
}

impl From<bool> for Value {
    fn from(other: bool) -> Self {
        Value::Bool(other)
    }
}

impl From<String> for Value {
    fn from(other: String) -> Self {
        Value::String(other)
    }
}

impl From<f64> for Value {
    fn from(other: f64) -> Self {
        Value::Double(other)
    }
}

impl From<DateTime> for Value {
    fn from(other: DateTime) -> Self {
        Value::DateTime(other)
    }
}

impl From<Vec<u8>> for Value {
    fn from(other: Vec<u8>) -> Self {
        Value::Base64(other)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str;
    use std::collections::BTreeMap;

    #[test]
    fn escapes_strings() {
        let mut output: Vec<u8> = Vec::new();

        Value::from("<xml> string".to_string()).format(&mut output).unwrap();
        assert_eq!(str::from_utf8(&output).unwrap(), "<value>\n<string><xml>&nbsp;string</string>\n</value>\n");
    }

    #[test]
    fn escapes_struct_member_names() {
        let mut output: Vec<u8> = Vec::new();
        let mut map: BTreeMap<String, Value> = BTreeMap::new();
        map.insert("x&<x".to_string(), Value::from(true));

        Value::Struct(map).format(&mut output).unwrap();
        assert_eq!(str::from_utf8(&output).unwrap(), "<value>\n<struct>\n<member>\n<name>x&<x</name>\n<value>\n<boolean>1</boolean>\n</value>\n</member>\n</struct>\n</value>\n");
    }
}
<commit_msg>Implement Value::from(&str) for convenience<commit_after>//! Contains the different types of values understood by XML-RPC.

use utils::{escape_xml, format_datetime};

use base64::encode;
use iso8601::DateTime;

use std::collections::BTreeMap;
use std::io::{self, Write};

/// The possible XML-RPC values.
#[derive(Debug, PartialEq)]
pub enum Value {
    /// `<i4>` or `<int>`, 32-bit signed integer.
    Int(i32),
    /// `<boolean>`, 0 == `false`, 1 == `true`.
    Bool(bool),
    /// `<string>`
    // FIXME zero-copy? `Cow<'static, ..>`?
    String(String),
    /// `<double>`
    Double(f64),
    /// `<dateTime.iso8601>`, an ISO 8601 formatted date/time value.
    DateTime(DateTime),
    /// `<base64>`, base64-encoded binary data.
    Base64(Vec<u8>),

    /// `<struct>`, a mapping of named values.
    Struct(BTreeMap<String, Value>),
    /// `<array>`, a list of arbitrary (heterogeneous) values.
    Array(Vec<Value>),

    // TODO Nil
}

impl Value {
    pub fn format<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        try!(writeln!(fmt, "<value>"));

        match *self {
            Value::Int(i) => {
                try!(writeln!(fmt, "<i4>{}</i4>", i));
            }
            Value::Bool(b) => {
                try!(writeln!(fmt, "<boolean>{}</boolean>", if b { "1" } else { "0" }));
            }
            Value::String(ref s) => {
                try!(writeln!(fmt, "<string>{}</string>", escape_xml(s)));
            }
            Value::Double(d) => {
                try!(writeln!(fmt, "<double>{}</double>", d));
            }
            Value::DateTime(date_time) => {
                try!(writeln!(fmt, "<dateTime.iso8601>{}</dateTime.iso8601>", format_datetime(&date_time)));
            }
            Value::Base64(ref data) => {
                try!(writeln!(fmt, "<base64>{}</base64>", encode(data)));
            }
            Value::Struct(ref map) => {
                try!(writeln!(fmt, "<struct>"));
                for (ref name, ref value) in map {
                    try!(writeln!(fmt, "<member>"));
                    try!(writeln!(fmt, "<name>{}</name>", escape_xml(name)));
                    try!(value.format(fmt));
                    try!(writeln!(fmt, "</member>"));
                }
                try!(writeln!(fmt, "</struct>"));
            }
            Value::Array(ref array) => {
                try!(writeln!(fmt, "<array>"));
                try!(writeln!(fmt, "<data>"));
                for value in array {
                    try!(value.format(fmt));
                }
                try!(writeln!(fmt, "</data>"));
                try!(writeln!(fmt, "</array>"));
            }
        }

        try!(writeln!(fmt, "</value>"));
        Ok(())
    }
}

impl From<i32> for Value {
    fn from(other: i32) -> Self {
        Value::Int(other)
    }
}

impl From<bool> for Value {
    fn from(other: bool) -> Self {
        Value::Bool(other)
    }
}

impl From<String> for Value {
    fn from(other: String) -> Self {
        Value::String(other)
    }
}

impl<'a> From<&'a str> for Value {
    fn from(other: &'a str) -> Self {
        Value::String(other.to_string())
    }
}

impl From<f64> for Value {
    fn from(other: f64) -> Self {
        Value::Double(other)
    }
}

impl From<DateTime> for Value {
    fn from(other: DateTime) -> Self {
        Value::DateTime(other)
    }
}

impl From<Vec<u8>> for Value {
    fn from(other: Vec<u8>) -> Self {
        Value::Base64(other)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str;
    use std::collections::BTreeMap;

    #[test]
    fn escapes_strings() {
        let mut output: Vec<u8> = Vec::new();

        Value::from("<xml> string").format(&mut output).unwrap();
        assert_eq!(str::from_utf8(&output).unwrap(), "<value>\n<string><xml>&nbsp;string</string>\n</value>\n");
    }

    #[test]
    fn escapes_struct_member_names() {
        let mut output: Vec<u8> = Vec::new();
        let mut map: BTreeMap<String, Value> = BTreeMap::new();
        map.insert("x&<x".to_string(), Value::from(true));

        Value::Struct(map).format(&mut output).unwrap();
        assert_eq!(str::from_utf8(&output).unwrap(), "<value>\n<struct>\n<member>\n<name>x&<x</name>\n<value>\n<boolean>1</boolean>\n</value>\n</member>\n</struct>\n</value>\n");
    }
}
<|endoftext|>