<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

${helpers.four_sides_shorthand(
    "padding",
    "padding-%s",
    "specified::NonNegativeLengthPercentage::parse",
    engines="gecko servo-2013 servo-2020",
    spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
    allow_quirks="Yes",
)}

${helpers.two_properties_shorthand(
    "padding-block",
    "padding-block-start",
    "padding-block-end",
    "specified::NonNegativeLengthPercentage::parse",
    engines="gecko servo-2013 servo-2020",
    spec="https://drafts.csswg.org/css-logical/#propdef-padding-block"
)}

${helpers.two_properties_shorthand(
    "padding-inline",
    "padding-inline-start",
    "padding-inline-end",
    "specified::NonNegativeLengthPercentage::parse",
    engines="gecko servo-2013 servo-2020",
    spec="https://drafts.csswg.org/css-logical/#propdef-padding-inline"
)}

${helpers.four_sides_shorthand(
    "scroll-padding",
    "scroll-padding-%s",
    "specified::NonNegativeLengthPercentageOrAuto::parse",
    engines="gecko",
    spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding"
)}

${helpers.two_properties_shorthand(
    "scroll-padding-block",
    "scroll-padding-block-start",
    "scroll-padding-block-end",
    "specified::NonNegativeLengthPercentageOrAuto::parse",
    engines="gecko",
    spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-block"
)}

${helpers.two_properties_shorthand(
    "scroll-padding-inline",
    "scroll-padding-inline-start",
    "scroll-padding-inline-end",
    "specified::NonNegativeLengthPercentageOrAuto::parse",
    engines="gecko",
    spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-inline"
)}

<commit_msg>style: Remove trailing empty lines<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

${helpers.four_sides_shorthand(
    "padding",
    "padding-%s",
    "specified::NonNegativeLengthPercentage::parse",
    engines="gecko servo-2013 servo-2020",
    spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
    allow_quirks="Yes",
)}

${helpers.two_properties_shorthand(
    "padding-block",
    "padding-block-start",
    "padding-block-end",
    "specified::NonNegativeLengthPercentage::parse",
    engines="gecko servo-2013 servo-2020",
    spec="https://drafts.csswg.org/css-logical/#propdef-padding-block"
)}

${helpers.two_properties_shorthand(
    "padding-inline",
    "padding-inline-start",
    "padding-inline-end",
    "specified::NonNegativeLengthPercentage::parse",
    engines="gecko servo-2013 servo-2020",
    spec="https://drafts.csswg.org/css-logical/#propdef-padding-inline"
)}

${helpers.four_sides_shorthand(
    "scroll-padding",
    "scroll-padding-%s",
    "specified::NonNegativeLengthPercentageOrAuto::parse",
    engines="gecko",
    spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding"
)}

${helpers.two_properties_shorthand(
    "scroll-padding-block",
    "scroll-padding-block-start",
    "scroll-padding-block-end",
    "specified::NonNegativeLengthPercentageOrAuto::parse",
    engines="gecko",
    spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-block"
)}

${helpers.two_properties_shorthand(
    "scroll-padding-inline",
    "scroll-padding-inline-start",
    "scroll-padding-inline-end",
    "specified::NonNegativeLengthPercentageOrAuto::parse",
    engines="gecko",
    spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-inline"
)}
<|endoftext|>


<commit_before>#![crate_id(name="uutils", vers="1.0.0", author="Michael Gehring")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

@CRATES@

use std::os;
use std::collections::hashmap::HashMap;

static NAME: &'static str = "uutils";
static VERSION: &'static str = "1.0.0";

fn util_map() -> HashMap<&'static str, fn(Vec<String>) -> int> {
    fn uutrue(_: Vec<String>) -> int { 0 }
    fn uufalse(_: Vec<String>) -> int { 1 }

    let mut map = HashMap::new();
    @UTIL_MAP@
    map
}

fn usage(cmap: &HashMap<&'static str, fn(Vec<String>) -> int>) {
    println!("{} {}", NAME, VERSION);
    println!("");
    println!("Usage:");
    println!("  {} [util [arguments...]", NAME);
    println!("Currently defined functions:");
    let mut utils: Vec<&str> = cmap.keys().map(|&s| s).collect();
    utils.sort();
    for util in utils.iter() {
        println!("\t{}", util);
    }
    println!("");
}

fn main() {
    let umap = util_map();
    let mut args = os::args();

    // try binary name as util name.
    let binary = Path::new(args.get(0).as_slice());
    let binary_as_util = binary.filename_str().unwrap();

    match umap.find_equiv(&binary_as_util) {
        Some(&uumain) => {
            os::set_exit_status(uumain(args));
            return
        }
        None => (),
    }

    if binary_as_util.starts_with("uutils")
        || binary_as_util.starts_with("busybox") {
            // uutils can be called as either "uutils", "busybox"
            // "uutils-suffix" or "busybox-suffix". Not sure
            // what busybox uses the -suffix pattern for.
    } else {
        println!("{}: applet not found", binary_as_util);
        os::set_exit_status(1);
        return
    }

    // try first arg as util name.
    if args.len() >= 2 {
        args.shift();
        let util = args.get(0).as_slice();

        match umap.find_equiv(&util) {
            Some(&uumain) => {
                os::set_exit_status(uumain(args.clone()));
                return
            }
            None => {
                if args.get(0).as_slice() == "--help" {
                    // see if they want help on a specific util
                    if args.len() >= 2 {
                        let util = args.get(1).as_slice();
                        match umap.find_equiv(&util) {
                            Some(&uumain) => {
                                os::set_exit_status(uumain(vec!["--help".to_string()]));
                                return
                            }
                            None => {
                                println!("{}: applet not found", util);
                                os::set_exit_status(1);
                                return
                            }
                        }
                    }
                    usage(&umap);
                    os::set_exit_status(0);
                    return
                } else {
                    println!("{}: applet not found", util);
                    os::set_exit_status(1);
                    return
                }
            }
        }
    } else {
        // no arguments provided
        usage(&umap);
        os::set_exit_status(0);
        return
    }
}
<commit_msg>uutils: fix 'uutils --help <util>'<commit_after>#![crate_id(name="uutils", vers="1.0.0", author="Michael Gehring")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

@CRATES@

use std::os;
use std::collections::hashmap::HashMap;

static NAME: &'static str = "uutils";
static VERSION: &'static str = "1.0.0";

fn util_map() -> HashMap<&'static str, fn(Vec<String>) -> int> {
    fn uutrue(_: Vec<String>) -> int { 0 }
    fn uufalse(_: Vec<String>) -> int { 1 }

    let mut map = HashMap::new();
    @UTIL_MAP@
    map
}

fn usage(cmap: &HashMap<&'static str, fn(Vec<String>) -> int>) {
    println!("{} {}", NAME, VERSION);
    println!("");
    println!("Usage:");
    println!("  {} [util [arguments...]", NAME);
    println!("Currently defined functions:");
    let mut utils: Vec<&str> = cmap.keys().map(|&s| s).collect();
    utils.sort();
    for util in utils.iter() {
        println!("\t{}", util);
    }
    println!("");
}

fn main() {
    let umap = util_map();
    let mut args = os::args();

    // try binary name as util name.
    let binary = Path::new(args.get(0).as_slice());
    let binary_as_util = binary.filename_str().unwrap();

    match umap.find_equiv(&binary_as_util) {
        Some(&uumain) => {
            os::set_exit_status(uumain(args));
            return
        }
        None => (),
    }

    if binary_as_util.starts_with("uutils")
        || binary_as_util.starts_with("busybox") {
            // uutils can be called as either "uutils", "busybox"
            // "uutils-suffix" or "busybox-suffix". Not sure
            // what busybox uses the -suffix pattern for.
    } else {
        println!("{}: applet not found", binary_as_util);
        os::set_exit_status(1);
        return
    }

    // try first arg as util name.
    if args.len() >= 2 {
        args.shift();
        let util = args.get(0).as_slice();

        match umap.find_equiv(&util) {
            Some(&uumain) => {
                os::set_exit_status(uumain(args.clone()));
                return
            }
            None => {
                if args.get(0).as_slice() == "--help" {
                    // see if they want help on a specific util
                    if args.len() >= 2 {
                        let util = args.get(1).as_slice();
                        match umap.find_equiv(&util) {
                            Some(&uumain) => {
                                os::set_exit_status(uumain(vec![util.to_string(), "--help".to_string()]));
                                return
                            }
                            None => {
                                println!("{}: applet not found", util);
                                os::set_exit_status(1);
                                return
                            }
                        }
                    }
                    usage(&umap);
                    os::set_exit_status(0);
                    return
                } else {
                    println!("{}: applet not found", util);
                    os::set_exit_status(1);
                    return
                }
            }
        }
    } else {
        // no arguments provided
        usage(&umap);
        os::set_exit_status(0);
        return
    }
}
<|endoftext|>


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

use analysis::Analyzer;
use term::Term;
use mapping::FieldMapping;
use query::{Query, TermMatcher};
use query::parser::{QueryParseContext, QueryParseError};
use query::parser::utils::{parse_string, parse_float, Operator, parse_operator};

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

    // Match queries are single-key objects. The key is the field name, the value is either a
    // string or a sub-object with extra configuration:
    //
    // {
    //     "foo": "bar"
    // }
    //
    // {
    //     "foo": {
    //         "query": "bar",
    //         "boost": 2.0
    //     }
    // }
    //
    let field_name = if object.len() == 1 {
        object.keys().collect::<Vec<_>>()[0]
    } else {
        return Err(QueryParseError::ExpectedSingleKey)
    };

    // Get mapping for field
    let field_mapping = context.index.get_field_mapping_by_name(field_name);

    // Get configuration
    let mut query = Json::Null;
    let mut boost = 1.0f64;
    let mut operator = Operator::Or;

    match object[field_name] {
        Json::String(ref string) => query = object[field_name].clone(),
        Json::Object(ref inner_object) => {
            let mut has_query_key = false;

            for (key, value) in inner_object.iter() {
                match key.as_ref() {
                    "query" => {
                        has_query_key = true;
                        query = value.clone();
                    }
                    "boost" => {
                        boost = try!(parse_float(value));
                    }
                    "operator" => {
                        operator = try!(parse_operator(value))
                    }
                    _ => return Err(QueryParseError::UnrecognisedKey(key.clone()))
                }
            }

            if !has_query_key {
                return Err(QueryParseError::ExpectedKey("query"))
            }
        }
        _ => return Err(QueryParseError::ExpectedObjectOrString),
    }

    // Tokenise query string
    let tokens = match field_mapping {
        Some(ref field_mapping) => {
            field_mapping.process_value_for_query(query.clone())
        }
        None => {
            // TODO: Raise error?
            warn!("Unknown field: {}", field_name);

            FieldMapping::default().process_value_for_query(query.clone())
        }
    };

    let tokens = match tokens {
        Some(tokens) => tokens,
        None => {
            // Couldn't convert the passed in value into tokens
            // TODO: Raise error
            warn!("Unprocessable query: {}", query);

            return Ok(Query::MatchNone);
        }
    };

    // Create a term query for each token
    let mut sub_queries = Vec::new();
    for token in tokens {
        sub_queries.push(Query::MatchTerm {
            field: field_name.clone(),
            term: token.term,
            matcher: TermMatcher::Exact,
        });
    }

    // Combine the term queries
    let mut query = match operator {
        Operator::Or => {
            Query::Bool {
                must: vec![],
                must_not: vec![],
                should: sub_queries,
                filter: vec![],
                minimum_should_match: 1,
            }
        }
        Operator::And => {
            Query::Bool {
                must: sub_queries,
                must_not: vec![],
                should: vec![],
                filter: vec![],
                minimum_should_match: 0,
            }
        }
    };

    // Add boost
    if boost != 1.0f64 {
        query = Query::BoostScore {
            query: Box::new(query),
            boost: boost,
        };
    }

    return Ok(query);
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;

    use term::Term;
    use query::{Query, TermMatcher};
    use query::parser::{QueryParseContext, QueryParseError};
    use index::Index;

    use super::parse;

    #[test]
    fn test_match_query() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\"
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::Bool {
            must: vec![],
            must_not: vec![],
            should: vec![
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("bar".to_string()),
                    matcher: TermMatcher::Exact
                }
            ],
            filter: vec![],
            minimum_should_match: 1,
        }))
    }

    #[test]
    fn test_multi_term_match_query() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar baz\"
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::Bool {
            must: vec![],
            must_not: vec![],
            should: vec![
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("bar".to_string()),
                    matcher: TermMatcher::Exact
                },
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("baz".to_string()),
                    matcher: TermMatcher::Exact
                }
            ],
            filter: vec![],
            minimum_should_match: 1,
        }))
    }

    #[test]
    fn test_simple_multi_term_match_query() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": \"bar baz\"
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::Bool {
            must: vec![],
            must_not: vec![],
            should: vec![
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("bar".to_string()),
                    matcher: TermMatcher::Exact
                },
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("baz".to_string()),
                    matcher: TermMatcher::Exact
                }
            ],
            filter: vec![],
            minimum_should_match: 1,
        }))
    }

    #[test]
    fn test_with_boost() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": 2.0
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::BoostScore {
            query: Box::new(Query::Bool {
                must: vec![],
                must_not: vec![],
                should: vec![
                    Query::MatchTerm {
                        field: "foo".to_string(),
                        term: Term::String("bar".to_string()),
                        matcher: TermMatcher::Exact
                    }
                ],
                filter: vec![],
                minimum_should_match: 1,
            }),
            boost: 2.0f64,
        }))
    }

    #[test]
    fn test_with_boost_integer() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": 2
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::BoostScore {
            query: Box::new(Query::Bool {
                must: vec![],
                must_not: vec![],
                should: vec![
                    Query::MatchTerm {
                        field: "foo".to_string(),
                        term: Term::String("bar".to_string()),
                        matcher: TermMatcher::Exact
                    }
                ],
                filter: vec![],
                minimum_should_match: 1,
            }),
            boost: 2.0f64,
        }))
    }

    #[test]
    fn test_with_and_operator() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"operator\": \"and\"
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::Bool {
            must: vec![
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("bar".to_string()),
                    matcher: TermMatcher::Exact
                }
            ],
            must_not: vec![],
            should: vec![],
            filter: vec![],
            minimum_should_match: 0,
        }))
    }

    #[test]
    fn test_gives_error_for_incorrect_type() {
        // Array
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        [
            \"foo\"
        ]
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));

        // Integer
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        123
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));

        // Float
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        123.1234
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));
    }

    #[test]
    fn test_gives_error_for_incorrect_boost_type() {
        // String
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": \"2\"
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));

        // Array
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": [2]
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));

        // Object
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": {
                    \"value\": 2
                }
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));
    }

    #[test]
    fn test_gives_error_for_missing_query() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedKey("query")));
    }

    #[test]
    fn test_gives_error_for_extra_key() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\"
            },
            \"hello\": \"world\"
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedSingleKey));
    }

    #[test]
    fn test_gives_error_for_extra_inner_key() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"hello\": \"world\"
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::UnrecognisedKey("hello".to_string())));
    }
}
<commit_msg>Rewrite match_query to not use Bool query<commit_after>use rustc_serialize::json::Json;

use analysis::Analyzer;
use term::Term;
use mapping::FieldMapping;
use query::{Query, TermMatcher};
use query::parser::{QueryParseContext, QueryParseError};
use query::parser::utils::{parse_string, parse_float, Operator, parse_operator};

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

    // Match queries are single-key objects. The key is the field name, the value is either a
    // string or a sub-object with extra configuration:
    //
    // {
    //     "foo": "bar"
    // }
    //
    // {
    //     "foo": {
    //         "query": "bar",
    //         "boost": 2.0
    //     }
    // }
    //
    let field_name = if object.len() == 1 {
        object.keys().collect::<Vec<_>>()[0]
    } else {
        return Err(QueryParseError::ExpectedSingleKey)
    };

    // Get mapping for field
    let field_mapping = context.index.get_field_mapping_by_name(field_name);

    // Get configuration
    let mut query = Json::Null;
    let mut boost = 1.0f64;
    let mut operator = Operator::Or;

    match object[field_name] {
        Json::String(ref string) => query = object[field_name].clone(),
        Json::Object(ref inner_object) => {
            let mut has_query_key = false;

            for (key, value) in inner_object.iter() {
                match key.as_ref() {
                    "query" => {
                        has_query_key = true;
                        query = value.clone();
                    }
                    "boost" => {
                        boost = try!(parse_float(value));
                    }
                    "operator" => {
                        operator = try!(parse_operator(value))
                    }
                    _ => return Err(QueryParseError::UnrecognisedKey(key.clone()))
                }
            }

            if !has_query_key {
                return Err(QueryParseError::ExpectedKey("query"))
            }
        }
        _ => return Err(QueryParseError::ExpectedObjectOrString),
    }

    // Tokenise query string
    let tokens = match field_mapping {
        Some(ref field_mapping) => {
            field_mapping.process_value_for_query(query.clone())
        }
        None => {
            // TODO: Raise error?
            warn!("Unknown field: {}", field_name);

            FieldMapping::default().process_value_for_query(query.clone())
        }
    };

    let tokens = match tokens {
        Some(tokens) => tokens,
        None => {
            // Couldn't convert the passed in value into tokens
            // TODO: Raise error
            warn!("Unprocessable query: {}", query);

            return Ok(Query::MatchNone);
        }
    };

    // Create a term query for each token
    let mut sub_queries = Vec::new();
    for token in tokens {
        sub_queries.push(Query::MatchTerm {
            field: field_name.clone(),
            term: token.term,
            matcher: TermMatcher::Exact,
        });
    }

    // Combine the term queries
    let mut query = match operator {
        Operator::Or => {
            Query::Or {
                queries: sub_queries,
            }
        }
        Operator::And => {
            Query::And {
                queries: sub_queries,
            }
        }
    };

    // Add boost
    if boost != 1.0f64 {
        query = Query::BoostScore {
            query: Box::new(query),
            boost: boost,
        };
    }

    return Ok(query);
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;

    use term::Term;
    use query::{Query, TermMatcher};
    use query::parser::{QueryParseContext, QueryParseError};
    use index::Index;

    use super::parse;

    #[test]
    fn test_match_query() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\"
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::Or {
            queries: vec![
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("bar".to_string()),
                    matcher: TermMatcher::Exact
                }
            ],
        }))
    }

    #[test]
    fn test_multi_term_match_query() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar baz\"
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::Or {
            queries: vec![
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("bar".to_string()),
                    matcher: TermMatcher::Exact
                },
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("baz".to_string()),
                    matcher: TermMatcher::Exact
                }
            ],
        }))
    }

    #[test]
    fn test_simple_multi_term_match_query() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": \"bar baz\"
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::Or {
            queries: vec![
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("bar".to_string()),
                    matcher: TermMatcher::Exact
                },
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("baz".to_string()),
                    matcher: TermMatcher::Exact
                }
            ],
        }))
    }

    #[test]
    fn test_with_boost() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": 2.0
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::BoostScore {
            query: Box::new(Query::Or {
                queries: vec![
                    Query::MatchTerm {
                        field: "foo".to_string(),
                        term: Term::String("bar".to_string()),
                        matcher: TermMatcher::Exact
                    }
                ],
            }),
            boost: 2.0f64,
        }))
    }

    #[test]
    fn test_with_boost_integer() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": 2
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::BoostScore {
            query: Box::new(Query::Or {
                queries: vec![
                    Query::MatchTerm {
                        field: "foo".to_string(),
                        term: Term::String("bar".to_string()),
                        matcher: TermMatcher::Exact
                    }
                ],
            }),
            boost: 2.0f64,
        }))
    }

    #[test]
    fn test_with_and_operator() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"operator\": \"and\"
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::And {
            queries: vec![
                Query::MatchTerm {
                    field: "foo".to_string(),
                    term: Term::String("bar".to_string()),
                    matcher: TermMatcher::Exact
                }
            ],
        }))
    }

    #[test]
    fn test_gives_error_for_incorrect_type() {
        // Array
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        [
            \"foo\"
        ]
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));

        // Integer
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        123
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));

        // Float
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        123.1234
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));
    }

    #[test]
    fn test_gives_error_for_incorrect_boost_type() {
        // String
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": \"2\"
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));

        // Array
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": [2]
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));

        // Object
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": {
                    \"value\": 2
                }
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));
    }

    #[test]
    fn test_gives_error_for_missing_query() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedKey("query")));
    }

    #[test]
    fn test_gives_error_for_extra_key() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\"
            },
            \"hello\": \"world\"
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedSingleKey));
    }

    #[test]
    fn test_gives_error_for_extra_inner_key() {
        let query = parse(&QueryParseContext::new(&Index::new()), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"hello\": \"world\"
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::UnrecognisedKey("hello".to_string())));
    }
}
<|endoftext|>


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

use aes::Aes128;
use aes::BLOCK_SIZE;
use aes::MODE;

use xor::XOR;

use serialize::from_base64_file;
use serialize::from_hex;

use mac::hmac_sha1;
use mac::mac_sha1;

use hmac_client;
use hmac_server;

use rand;
use rand::Rng;

use set2::prefix_length;
use set2::random_block;

use errors::*;

use prefix_suffix_oracles::{Oracle, Oracle26};

use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
use sha1::Sha1;
use std::mem;

struct Encrypter25 {
    cleartext: Vec<u8>,
    key: Vec<u8>,
    ciphertext: Vec<u8>,
}

impl Encrypter25 {
    pub fn new() -> Result<Self, Error> {
        let cleartext = from_base64_file(Path::new("data/25.txt"))?;
        let key = random_block();
        let ciphertext = cleartext.encrypt(&key, None, MODE::CTR)?;
        Ok(Encrypter25 {
            cleartext,
            key,
            ciphertext,
        })
    }

    pub fn get_ciphertext(&self) -> &[u8] {
        &self.ciphertext
    }

    pub fn edit(&self, offset: usize, newtext: Vec<u8>) -> Result<Vec<u8>, Error> {
        let mut cleartext = self.cleartext.clone();
        let end = offset + newtext.len();
        if end > cleartext.len() {
            bail!("input out of bounds")
        }
        cleartext[offset..end].copy_from_slice(&newtext);
        cleartext.encrypt(&self.key, None, MODE::CTR)
    }

    pub fn verify_solution(&self, candidate_cleartext: &[u8]) -> Result<(), Error> {
        compare_eq(&self.cleartext[..], candidate_cleartext)
    }
}

fn challenge_25() -> Result<(), Error> {
    // This exercise is trivial: In CTR mode, if we know the underlying plaintext at some location,
    // we can trivially recover the used keystream by xor'ing the ciphertext with the
    // known plaintext. We simply use the edit function to set the entire cleartext to 0 so that
    // the ciphertext is even equal to the keystream.

    let encrypter = Encrypter25::new()?;
    let ciphertext = encrypter.get_ciphertext();
    let keystream = encrypter.edit(0, vec![0; ciphertext.len()])?;
    encrypter.verify_solution(&ciphertext.xor(&keystream))
}

fn challenge_26() -> Result<(), Error> {
    // This exercise is trivial: In CTR mode, if we know the underlying plaintext at some location,
    // we can inject any plaintext at the same location by xor'ing the ciphertext with
    // known_plaintext ^ target_plaintext.

    let oracle = Oracle26::new()?;
    let prefix_len = prefix_length(&oracle)?;
    let target_cleartext = b";admin=true";
    let mut ciphertext = oracle.encrypt(&vec![0; target_cleartext.len()])?;
    ciphertext.truncate(prefix_len + target_cleartext.len());
    ciphertext[prefix_len..].xor_inplace(target_cleartext);
    oracle.verify_solution(&ciphertext)
}

struct Sender27 {
    key: Vec<u8>,
}

struct Receiver27 {
    key: Vec<u8>,
}

impl Sender27 {
    pub fn encrypt(&self, input: &[u8]) -> Result<Vec<u8>, Error> {
        // Exclude ';' and '='
        if input
            .iter()
            .any(|&c| !c.is_ascii() || c == b';' || c == b'=')
        {
            bail!("invalid character in input");
        }

        let prefix = b"comment1=cooking%20MCs;userdata=";
        let suffix = b";comment2=%20like%20a%20pound%20of%20bacon";
        let mut cleartext = Vec::with_capacity(prefix.len() + input.len() + suffix.len());
        cleartext.extend_from_slice(prefix);
        cleartext.extend_from_slice(input);
        cleartext.extend_from_slice(suffix);
        cleartext.encrypt(&self.key, Some(&self.key), MODE::CBC)
    }
}

impl Receiver27 {
    pub fn try_decrypt(&self, ciphertext: &[u8]) -> Result<(), Error> {
        let cleartext = ciphertext.decrypt(&self.key, Some(&self.key), MODE::CBC)?;
        if !cleartext.is_ascii() {
            Err(NonAscii(cleartext).into())
        } else {
            Ok(())
        }
    }

    pub fn verify_solution(&self, candidate_key: &[u8]) -> Result<(), Error> {
        compare_eq(&self.key[..], candidate_key)
    }
}

fn get_sender_and_receiver_with_shared_key() -> (Sender27, Receiver27) {
    let secret_key = random_block();
    let sender = Sender27 {
        key: secret_key.clone(),
    };
    let receiver = Receiver27 {
        key: secret_key.clone(),
    };
    (sender, receiver)
}

#[derive(Debug, Fail)]
#[fail(display = "invalid input: {:?}", _0)]
struct NonAscii(Vec<u8>);

fn challenge_27() -> Result<(), Error> {
    let (sender, receiver) = get_sender_and_receiver_with_shared_key();

    let ciphertext = sender.encrypt(&[])?;

    let mut attack_ciphertext = Vec::with_capacity(3 * BLOCK_SIZE);
    attack_ciphertext.extend_from_slice(&ciphertext[0..BLOCK_SIZE]);
    attack_ciphertext.extend_from_slice(&[0; BLOCK_SIZE]);
    attack_ciphertext.extend_from_slice(&ciphertext[0..BLOCK_SIZE]);
    //Push last two blocks to preserve valid padding at the end
    attack_ciphertext.extend_from_slice(&ciphertext[ciphertext.len() - 2 * BLOCK_SIZE..]);

    if let Err(err) = receiver.try_decrypt(&attack_ciphertext) {
        if let Ok(NonAscii(attack_cleartext)) = err.downcast::<NonAscii>() {
            return receiver.verify_solution(
                &attack_cleartext[0..BLOCK_SIZE]
                    .xor(&attack_cleartext[2 * BLOCK_SIZE..3 * BLOCK_SIZE]),
            );
        }
    }

    bail!("attack ciphertext did not deceive the receiver");
}

fn challenge_28() -> Result<(), Error> {
    compare_eq(
        from_hex("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12")?,
        mac_sha1(b"The quick brown fox ", b"jumps over the lazy dog"),
    )
}

// Below we want to create an instance of the Sha1 type from the
// sha1 crate with a specific state. Unfortunately the sha1 crate
// does not offer any way to do this.
// We therfore include a copy of the Sha1 type here. We can then create
// an instance of our type with the desired state and transmute it to Sha1.

struct Sha1_0_20 {
    _state: Sha1State,
    _blocks: Blocks,
    _len: u64,
}

struct Blocks {
    _len: u32,
    _block: [u8; 64],
}

struct Sha1State {
    _state: [u32; 5],
}

impl Sha1_0_20 {
    fn new(state: [u32; 5], len: u64) -> Self {
        Sha1_0_20 {
            _state: Sha1State { _state: state },
            _len: len,
            _blocks: Blocks {
                _len: 0,
                _block: [0; 64],
            },
        }
    }
}

struct Server29 {
    key: Vec<u8>,
}

impl Server29 {
    pub fn new() -> Self {
        let mut rng = rand::thread_rng();
        let key_len = rng.gen_range(1, 200);
        let key: Vec<u8> = rng.gen_iter().take(key_len).collect();
        Server29 { key }
    }

    pub fn get_message_with_mac(&self) -> (Vec<u8>, Vec<u8>) {
        let message =
            b"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon"
                .to_vec();
        let mac = mac_sha1(&self.key, &message);
        (message, mac)
    }

    pub fn verify_mac(&self, message: &[u8], mac: &[u8]) -> bool {
        mac_sha1(&self.key, message) == mac
    }
}

fn padding(length: usize) -> Vec<u8> {
    let mut w = Vec::new();
    w.push(0x80u8);
    let zero_padding_count = 64 - ((length + 9) % 64);
    for _ in 0..zero_padding_count {
        w.push(0u8);
    }
    w.write_u64::<BigEndian>((length as u64) * 8).unwrap();
    w
}

fn challenge_29() -> Result<(), Error> {
    let server = Server29::new();
    let (input, hash) = server.get_message_with_mac();
    let suffix = b";admin=true";

    // Split the 20 bytes of `hash` into chunks of four
    // bytes and interpret each chunk as a u32.
    let mut state: [u32; 5] = [0; 5];
    for (b, s) in hash.chunks(4).zip(state.iter_mut()) {
        *s = BigEndian::read_u32(b)
    }

    for key_len in 0..200 {
        let secret_len = input.len() + key_len;
        let padding = padding(secret_len);
        let mut m2: Sha1;
        unsafe {
            m2 = mem::transmute(Sha1_0_20::new(state, (secret_len + padding.len()) as u64));
        }
        m2.update(suffix);
        let mac = m2.digest().bytes();

        let mut message = Vec::new();
        message.extend_from_slice(&input);
        message.extend_from_slice(&padding);
        message.extend_from_slice(suffix);
        if server.verify_mac(&message, &mac) {
            return Ok(());
        }
    }
    bail!("No matching message found.");
}

fn challenge_30() -> Result<(), Error> {
    /* Skipping/postponing Challenge 30 because
     * 1) SHA1 was much more interesting anyway,
     * 2) no MD4 implementation seems to be available.  */

    Err(ChallengeError::NotImplemented.into())
}

fn challenge_31() -> Result<(), Error> {
    compare_eq(
        from_hex("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9")?,
        hmac_sha1(b"key", b"The quick brown fox jumps over the lazy dog"),
    )
}

fn challenge_32() -> Result<(), Error> {
    let skip_exercise = true;

    if skip_exercise {
        return Err(ChallengeError::Skipped("Runs very long.").into());
    }

    let mut rng = rand::thread_rng();
    let key: Vec<u8> = rng.gen_iter().take(20).collect();

    let mut server = hmac_server::start(key);

    hmac_client::run();

    server.close().context("failed to close connection")?;

    Ok(()) //TODO Add proper error handling
}

pub fn add_challenges(challenges: &mut Vec<fn() -> Result<(), Error>>) {
    challenges.push(challenge_25);
    challenges.push(challenge_26);
    challenges.push(challenge_27);
    challenges.push(challenge_28);
    challenges.push(challenge_29);
    challenges.push(challenge_30);
    challenges.push(challenge_31);
    challenges.push(challenge_32);
}
<commit_msg>Add comment explaining the solution to challenge 29<commit_after>use std::path::Path;

use aes::Aes128;
use aes::BLOCK_SIZE;
use aes::MODE;

use xor::XOR;

use serialize::from_base64_file;
use serialize::from_hex;

use mac::hmac_sha1;
use mac::mac_sha1;

use hmac_client;
use hmac_server;

use rand;
use rand::Rng;

use set2::prefix_length;
use set2::random_block;

use errors::*;

use prefix_suffix_oracles::{Oracle, Oracle26};

use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
use sha1::Sha1;
use std::mem;

struct Encrypter25 {
    cleartext: Vec<u8>,
    key: Vec<u8>,
    ciphertext: Vec<u8>,
}

impl Encrypter25 {
    pub fn new() -> Result<Self, Error> {
        let cleartext = from_base64_file(Path::new("data/25.txt"))?;
        let key = random_block();
        let ciphertext = cleartext.encrypt(&key, None, MODE::CTR)?;
        Ok(Encrypter25 {
            cleartext,
            key,
            ciphertext,
        })
    }

    pub fn get_ciphertext(&self) -> &[u8] {
        &self.ciphertext
    }

    pub fn edit(&self, offset: usize, newtext: Vec<u8>) -> Result<Vec<u8>, Error> {
        let mut cleartext = self.cleartext.clone();
        let end = offset + newtext.len();
        if end > cleartext.len() {
            bail!("input out of bounds")
        }
        cleartext[offset..end].copy_from_slice(&newtext);
        cleartext.encrypt(&self.key, None, MODE::CTR)
    }

    pub fn verify_solution(&self, candidate_cleartext: &[u8]) -> Result<(), Error> {
        compare_eq(&self.cleartext[..], candidate_cleartext)
    }
}

fn challenge_25() -> Result<(), Error> {
    // This exercise is trivial: In CTR mode, if we know the underlying plaintext at some location,
    // we can trivially recover the used keystream by xor'ing the ciphertext with the
    // known plaintext. We simply use the edit function to set the entire cleartext to 0 so that
    // the ciphertext is even equal to the keystream.

    let encrypter = Encrypter25::new()?;
    let ciphertext = encrypter.get_ciphertext();
    let keystream = encrypter.edit(0, vec![0; ciphertext.len()])?;
    encrypter.verify_solution(&ciphertext.xor(&keystream))
}

fn challenge_26() -> Result<(), Error> {
    // This exercise is trivial: In CTR mode, if we know the underlying plaintext at some location,
    // we can inject any plaintext at the same location by xor'ing the ciphertext with
    // known_plaintext ^ target_plaintext.

    let oracle = Oracle26::new()?;
    let prefix_len = prefix_length(&oracle)?;
    let target_cleartext = b";admin=true";
    let mut ciphertext = oracle.encrypt(&vec![0; target_cleartext.len()])?;
    ciphertext.truncate(prefix_len + target_cleartext.len());
    ciphertext[prefix_len..].xor_inplace(target_cleartext);
    oracle.verify_solution(&ciphertext)
}

struct Sender27 {
    key: Vec<u8>,
}

struct Receiver27 {
    key: Vec<u8>,
}

impl Sender27 {
    pub fn encrypt(&self, input: &[u8]) -> Result<Vec<u8>, Error> {
        // Exclude ';' and '='
        if input
            .iter()
            .any(|&c| !c.is_ascii() || c == b';' || c == b'=')
        {
            bail!("invalid character in input");
        }

        let prefix = b"comment1=cooking%20MCs;userdata=";
        let suffix = b";comment2=%20like%20a%20pound%20of%20bacon";
        let mut cleartext = Vec::with_capacity(prefix.len() + input.len() + suffix.len());
        cleartext.extend_from_slice(prefix);
        cleartext.extend_from_slice(input);
        cleartext.extend_from_slice(suffix);
        cleartext.encrypt(&self.key, Some(&self.key), MODE::CBC)
    }
}

impl Receiver27 {
    pub fn try_decrypt(&self, ciphertext: &[u8]) -> Result<(), Error> {
        let cleartext = ciphertext.decrypt(&self.key, Some(&self.key), MODE::CBC)?;
        if !cleartext.is_ascii() {
            Err(NonAscii(cleartext).into())
        } else {
            Ok(())
        }
    }

    pub fn verify_solution(&self, candidate_key: &[u8]) -> Result<(), Error> {
        compare_eq(&self.key[..], candidate_key)
    }
}

fn get_sender_and_receiver_with_shared_key() -> (Sender27, Receiver27) {
    let secret_key = random_block();
    let sender = Sender27 {
        key: secret_key.clone(),
    };
    let receiver = Receiver27 {
        key: secret_key.clone(),
    };
    (sender, receiver)
}

#[derive(Debug, Fail)]
#[fail(display = "invalid input: {:?}", _0)]
struct NonAscii(Vec<u8>);

fn challenge_27() -> Result<(), Error> {
    let (sender, receiver) = get_sender_and_receiver_with_shared_key();

    let ciphertext = sender.encrypt(&[])?;

    let mut attack_ciphertext = Vec::with_capacity(3 * BLOCK_SIZE);
    attack_ciphertext.extend_from_slice(&ciphertext[0..BLOCK_SIZE]);
    attack_ciphertext.extend_from_slice(&[0; BLOCK_SIZE]);
    attack_ciphertext.extend_from_slice(&ciphertext[0..BLOCK_SIZE]);
    //Push last two blocks to preserve valid padding at the end
    attack_ciphertext.extend_from_slice(&ciphertext[ciphertext.len() - 2 * BLOCK_SIZE..]);

    if let Err(err) = receiver.try_decrypt(&attack_ciphertext) {
        if let Ok(NonAscii(attack_cleartext)) = err.downcast::<NonAscii>() {
            return receiver.verify_solution(
                &attack_cleartext[0..BLOCK_SIZE]
                    .xor(&attack_cleartext[2 * BLOCK_SIZE..3 * BLOCK_SIZE]),
            );
        }
    }

    bail!("attack ciphertext did not deceive the receiver");
}

fn challenge_28() -> Result<(), Error> {
    compare_eq(
        from_hex("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12")?,
        mac_sha1(b"The quick brown fox ", b"jumps over the lazy dog"),
    )
}

// Below we want to create an instance of the Sha1 type from the
// sha1 crate with a specific state. Unfortunately the sha1 crate
// does not offer any way to do this.
// We therfore include a copy of the Sha1 type here. We can then create
// an instance of our type with the desired state and transmute it to Sha1.

struct Sha1_0_20 {
    _state: Sha1State,
    _blocks: Blocks,
    _len: u64,
}

struct Blocks {
    _len: u32,
    _block: [u8; 64],
}

struct Sha1State {
    _state: [u32; 5],
}

impl Sha1_0_20 {
    fn new(state: [u32; 5], len: u64) -> Self {
        Sha1_0_20 {
            _state: Sha1State { _state: state },
            _len: len,
            _blocks: Blocks {
                _len: 0,
                _block: [0; 64],
            },
        }
    }
}

struct Server29 {
    key: Vec<u8>,
}

impl Server29 {
    pub fn new() -> Self {
        let mut rng = rand::thread_rng();
        let key_len = rng.gen_range(1, 200);
        let key: Vec<u8> = rng.gen_iter().take(key_len).collect();
        Server29 { key }
    }

    pub fn get_message_with_mac(&self) -> (Vec<u8>, Vec<u8>) {
        let message =
            b"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon"
                .to_vec();
        let mac = mac_sha1(&self.key, &message);
        (message, mac)
    }

    pub fn verify_mac(&self, message: &[u8], mac: &[u8]) -> bool {
        mac_sha1(&self.key, message) == mac
    }
}

/* A SHA-1 hasher consists of an internal state of 160 bits and a function which takes 512
 * bits of data and mangles them with the current state to produce a new state. In order to compute
 * the hash of a message, the message is first padded with the padding function below so that
 * its length is a multiple of 512 bits. It is then split into chunks of 512 bits and the chunks
 * are consecutively passed to the mangling function (starting with a hardcoded initial state).
 * The resulting state is the hash of the message.
 *
 * In other words, SHA1(message) = state after processing (message || padding)
 *
 * Hence if we use SHA1(message) as the initial state of a hasher and then use
 * this hasher to compute the hash of another-message, the resulting hash will be equal to
 * SHA1(message || padding || another-message)
 *
 * This observation is the basis for the following challenge.
 */

fn padding(length: usize) -> Vec<u8> {
    let mut w = Vec::new();
    w.push(0x80u8);
    let zero_padding_length = 64 - ((length + 9) % 64);
    for _ in 0..zero_padding_length {
        w.push(0u8);
    }
    w.write_u64::<BigEndian>((length as u64) * 8).unwrap();
    w
}

fn challenge_29() -> Result<(), Error> {
    let server = Server29::new();
    let (original_message, mac) = server.get_message_with_mac();
    let new_message = b";admin=true";

    // Split the 20 bytes of `mac` into chunks of four
    // bytes and interpret each chunk as a u32.
    let mut state: [u32; 5] = [0; 5];
    for (b, s) in mac.chunks(4).zip(state.iter_mut()) {
        *s = BigEndian::read_u32(b)
    }

    // We do not know the actual key length so we have to try different possibilities.
    for key_len in 0..200 {
        let secret_len = original_message.len() + key_len;
        let padding = padding(secret_len);
        let mut m2: Sha1;
        unsafe {
            m2 = mem::transmute(Sha1_0_20::new(state, (secret_len + padding.len()) as u64));
        }
        m2.update(new_message);
        let mac = m2.digest().bytes();

        let mut message = Vec::new();
        message.extend_from_slice(&original_message);
        message.extend_from_slice(&padding);
        message.extend_from_slice(new_message);
        if server.verify_mac(&message, &mac) {
            return Ok(());
        }
    }
    bail!("No matching message found.");
}

fn challenge_30() -> Result<(), Error> {
    /* Skipping/postponing Challenge 30 because
     * 1) SHA1 was much more interesting anyway,
     * 2) no MD4 implementation seems to be available.  */

    Err(ChallengeError::NotImplemented.into())
}

fn challenge_31() -> Result<(), Error> {
    compare_eq(
        from_hex("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9")?,
        hmac_sha1(b"key", b"The quick brown fox jumps over the lazy dog"),
    )
}

fn challenge_32() -> Result<(), Error> {
    let skip_exercise = true;

    if skip_exercise {
        return Err(ChallengeError::Skipped("Runs very long.").into());
    }

    let mut rng = rand::thread_rng();
    let key: Vec<u8> = rng.gen_iter().take(20).collect();

    let mut server = hmac_server::start(key);

    hmac_client::run();

    server.close().context("failed to close connection")?;

    Ok(()) //TODO Add proper error handling
}

pub fn add_challenges(challenges: &mut Vec<fn() -> Result<(), Error>>) {
    challenges.push(challenge_25);
    challenges.push(challenge_26);
    challenges.push(challenge_27);
    challenges.push(challenge_28);
    challenges.push(challenge_29);
    challenges.push(challenge_30);
    challenges.push(challenge_31);
    challenges.push(challenge_32);
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::{Rc, Weak};
use std::cmp;
use std::mem;
use uuid::Uuid;

use alloc::{Alloc, AllocBox};
use js_types::js_type::{JsVar, JsType, JsPtrEnum};

pub struct Scope {
    pub parent: Option<Rc<Scope>>,
    alloc_box: Rc<RefCell<AllocBox>>,
    get_roots: Box<Fn() -> HashSet<Uuid>>,
}

impl Scope {
    pub fn new<F>(alloc_box: Rc<RefCell<AllocBox>>, get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: None,
            alloc_box: alloc_box,
            get_roots: Box::new(get_roots),
        }
    }

    pub fn as_child<F>(parent: Rc<Scope>, alloc_box: Rc<RefCell<AllocBox>>, get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: Some(parent),
            alloc_box: alloc_box,
            get_roots: Box::new(get_roots),
        }
    }

    pub fn set_parent(&mut self, parent: &Rc<Scope>) {
        self.parent = Some(parent.clone());
    }

    pub fn alloc(&mut self, uuid: Uuid, ptr: JsPtrEnum) -> Uuid {
        self.alloc_box.borrow_mut().alloc(uuid, ptr)
    }

    pub fn dealloc(&mut self, uuid: &Uuid) -> bool {
        self.alloc_box.borrow_mut().dealloc(uuid)
    }

    pub fn get_var_copy(&self, uuid: &Uuid) -> Option<JsPtrEnum> {
        self.alloc_box.borrow().find_id(uuid).map(|var| var.borrow().clone())
    }

    /// TODO Compute the roots of the current scope-- any variable that is
    /// directly referenced or declared within the scope. This might just be the
    /// key set of the uuid map(?) Not necessarily, I think. What if you do
    /// something like this:
    /// var x = {}
    /// var y = { 1: x }
    /// y = x
    /// y would be a root by the definition above, but is no longer reachable at
    /// the end of the scope because it now aliases x. A better definition would
    /// be "Any variable that is declared or referenced directly, but a direct
    /// reference (variable usage) supercedes a declaration." The above example
    /// demonstrates why this is necessary.
    /// This should come from the interpreter, so I shouldn't actually have to
    /// care about getting the root set myself.

    /// Roots always get marked as Black, since they're always reachable from
    /// the current scope. NB that this assumes all root references are actually
    /// valid reference types, i.e. they're not numbers, etc.
    pub fn mark_roots(&mut self) {
        let marks = (self.get_roots)();
        self.alloc_box.borrow_mut().mark_roots(marks);
    }

}

#[cfg(test)]
mod tests {
    /*use super::*;
    use std::collections::hash_set::HashSet;
    use std::rc::{Rc, Weak};
    use uuid::Uuid;

    use alloc::Alloc;
    use js_types::js_type::{JsVar, JsType, JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::js_obj::{JsObjStruct};

    fn dummy_get_roots() -> HashSet<Uuid> {
        HashSet::new()
    }

    fn make_num(i: f64) -> JsVar {
        JsVar::new(JsType::JsNum(i))
    }

    fn make_obj(kvs: Vec<(JsKey, Alloc<JsVar>)>) -> JsVar {
        JsVar::new(JsType::JsPtr(JsPtrEnum::JsObj(JsObjStruct::new(None, "test", kvs))))
    }

    #[test]
    fn test_new_scope() {
        let mut test_scope = Scope::new(dummy_get_roots);
        assert!(test_scope.parent.is_none());
        assert!(test_scope.black_set.is_empty());
        assert!(test_scope.grey_set.is_empty());
        assert!(test_scope.white_set.is_empty());
        assert_eq!(test_scope.children.len(), 0);
    }

    #[test]
    fn test_as_child_scope() {
        let parent_scope = Rc::new(Scope::new(dummy_get_roots));
        let mut test_scope = Scope::as_child(Rc::downgrade(&parent_scope.clone()), dummy_get_roots);

        assert!(test_scope.parent.is_some());
        assert!(test_scope.black_set.is_empty());
        assert!(test_scope.grey_set.is_empty());
        assert!(test_scope.white_set.is_empty());
        assert_eq!(test_scope.children.len(), 0);
    }

    #[test]
    fn test_set_parent() {
        let parent_scope = Rc::new(Scope::new(dummy_get_roots));
        let mut test_scope = Scope::new(dummy_get_roots);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(&parent_scope);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_add_child() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let child_scope1 = Scope::new(dummy_get_roots);
        let child_scope2 = Scope::new(dummy_get_roots);
        assert_eq!(test_scope.children.len(), 0);
        test_scope.add_child(child_scope1);
        assert_eq!(test_scope.children.len(), 1);
        test_scope.add_child(child_scope2);
        assert_eq!(test_scope.children.len(), 2);
    }

    #[test]
    fn test_alloc() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let test_uuid = test_var.uuid.clone();
        let uuid = test_scope.alloc(test_var);
        assert_eq!(test_uuid, uuid);
        assert!(test_scope.white_set.contains_key(&uuid));
        assert_eq!(test_scope.white_set.len(), 1);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
        let test_var2 = make_num(2.0);
        let uuid = test_scope.alloc(test_var2);
        assert!(test_scope.white_set.contains_key(&uuid));
        assert_eq!(test_scope.white_set.len(), 2);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
    }

    #[test]
    fn test_dealloc() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let bad_uuid = Uuid::new_v4();
        assert!(test_scope.dealloc(&uuid));
        assert_eq!(test_scope.white_set.len(), 0);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
        assert!(!test_scope.dealloc(&bad_uuid));
    }

    #[test]
    fn test_get_var_copy() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let bad_uuid = Uuid::new_v4();
        let var_copy = test_scope.get_var_copy(&uuid);
        assert!(var_copy.is_some());
        let var = var_copy.unwrap();
        assert_eq!(var.uuid, uuid);
        let bad_copy = test_scope.get_var_copy(&bad_uuid);
        assert!(bad_copy.is_none());
    }

    #[test]
    fn test_update_var() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let mut update = test_scope.get_var_copy(&uuid).unwrap();
        update = make_num(2.0);
        update.uuid = uuid;
        assert!(test_scope.update_var(update));
        let update = test_scope.get_var_copy(&uuid).unwrap();
        match update {
            JsVar{ t: JsType::JsNum(i), ..} => assert_eq!(i, 2.0),
            _ => ()
        }
        test_scope.dealloc(&uuid);
        assert!(!test_scope.update_var(update));
    }

    #[test]
    fn test_mark_roots() {
        let test_uuid = Uuid::new_v4();
        let mut test_var = make_num(1.0);
        let mut test_var2 = make_num(2.0);
        test_var.uuid = test_uuid;
        let simple_get_roots = move || { let mut set = HashSet::new();
                                    set.insert(test_uuid);
                                    set };
        let mut test_scope = Scope::new(simple_get_roots);
        let test_uuid = test_scope.alloc(test_var);
        let test_uuid2 = test_scope.alloc(test_var2);
        test_scope.mark_roots();
        assert_eq!(test_scope.black_set.len(), 1);
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert!(test_scope.black_set.get(&test_uuid2).is_none());
    }

    #[test]
    fn test_mark_phase() {
        let test_uuid = Uuid::new_v4();
        let simple_get_roots = move || { let mut set = HashSet::new();
                                    set.insert(test_uuid);
                                    set };
        let mut test_scope = Scope::new(simple_get_roots);

        let mut test_var2 = make_num(2.0);
        let test_uuid2 = test_scope.alloc(test_var2);
        let test_var2_alloc = test_scope.find_id(&test_uuid2).unwrap().clone();

        let test_key = JsKey::new(JsKeyEnum::JsNum(1.0));
        let mut test_var = make_obj(vec![(test_key, test_var2_alloc)]);
        test_var.uuid = test_uuid;
        let test_uuid = test_scope.alloc(test_var);

        // Mark roots first...
        test_scope.mark_roots();
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert_eq!(test_scope.black_set.len(), 1);
        assert_eq!(test_scope.grey_set.len(), 1);

        // ...then mark everything else
        test_scope.mark_phase();

        assert_eq!(test_scope.grey_set.len(), 0);
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert!(test_scope.black_set.get(&test_uuid2).is_some());
    }*/
}
<commit_msg>Pass things by reference to Scope methods to put clone burden on Scope instances<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::{Rc, Weak};
use std::cmp;
use std::mem;
use uuid::Uuid;

use alloc::{Alloc, AllocBox};
use js_types::js_type::{JsVar, JsType, JsPtrEnum};

pub struct Scope {
    pub parent: Option<Rc<Scope>>,
    alloc_box: Rc<RefCell<AllocBox>>,
    get_roots: Box<Fn() -> HashSet<Uuid>>,
}

impl Scope {
    pub fn new<F>(alloc_box: &Rc<RefCell<AllocBox>>, get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: None,
            alloc_box: alloc_box.clone(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn as_child<F>(parent: &Rc<Scope>, alloc_box: &Rc<RefCell<AllocBox>>, get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: Some(parent.clone()),
            alloc_box: alloc_box.clone(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn set_parent(&mut self, parent: &Rc<Scope>) {
        self.parent = Some(parent.clone());
    }

    pub fn alloc(&mut self, uuid: Uuid, ptr: JsPtrEnum) -> Uuid {
        self.alloc_box.borrow_mut().alloc(uuid, ptr)
    }

    pub fn dealloc(&mut self, uuid: &Uuid) -> bool {
        self.alloc_box.borrow_mut().dealloc(uuid)
    }

    pub fn get_ptr_copy(&self, uuid: &Uuid) -> Option<JsPtrEnum> {
        self.alloc_box.borrow().find_id(uuid).map(|var| var.borrow().clone())
    }

    pub fn update_ptr(&mut self, uuid: &Uuid, ptr: JsPtrEnum) -> bool {
        self.alloc_box.borrow_mut().update_var(uuid, ptr)
    }

    /// TODO Compute the roots of the current scope-- any variable that is
    /// directly referenced or declared within the scope. This might just be the
    /// key set of the uuid map(?) Not necessarily, I think. What if you do
    /// something like this:
    /// var x = {}
    /// var y = { 1: x }
    /// y = x
    /// y would be a root by the definition above, but is no longer reachable at
    /// the end of the scope because it now aliases x. A better definition would
    /// be "Any variable that is declared or referenced directly, but a direct
    /// reference (variable usage) supercedes a declaration." The above example
    /// demonstrates why this is necessary.
    /// This should come from the interpreter, so I shouldn't actually have to
    /// care about getting the root set myself.

    /// Roots always get marked as Black, since they're always reachable from
    /// the current scope. NB that this assumes all root references are actually
    /// valid reference types, i.e. they're not numbers, etc.
    pub fn mark_roots(&mut self) {
        let marks = (self.get_roots)();
        self.alloc_box.borrow_mut().mark_roots(marks);
    }

}

#[cfg(test)]
mod tests {
    /*use super::*;
    use std::collections::hash_set::HashSet;
    use std::rc::{Rc, Weak};
    use uuid::Uuid;

    use alloc::Alloc;
    use js_types::js_type::{JsVar, JsType, JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::js_obj::{JsObjStruct};

    fn dummy_get_roots() -> HashSet<Uuid> {
        HashSet::new()
    }

    fn make_num(i: f64) -> JsVar {
        JsVar::new(JsType::JsNum(i))
    }

    fn make_obj(kvs: Vec<(JsKey, Alloc<JsVar>)>) -> JsVar {
        JsVar::new(JsType::JsPtr(JsPtrEnum::JsObj(JsObjStruct::new(None, "test", kvs))))
    }

    #[test]
    fn test_new_scope() {
        let mut test_scope = Scope::new(dummy_get_roots);
        assert!(test_scope.parent.is_none());
        assert!(test_scope.black_set.is_empty());
        assert!(test_scope.grey_set.is_empty());
        assert!(test_scope.white_set.is_empty());
        assert_eq!(test_scope.children.len(), 0);
    }

    #[test]
    fn test_as_child_scope() {
        let parent_scope = Rc::new(Scope::new(dummy_get_roots));
        let mut test_scope = Scope::as_child(Rc::downgrade(&parent_scope.clone()), dummy_get_roots);

        assert!(test_scope.parent.is_some());
        assert!(test_scope.black_set.is_empty());
        assert!(test_scope.grey_set.is_empty());
        assert!(test_scope.white_set.is_empty());
        assert_eq!(test_scope.children.len(), 0);
    }

    #[test]
    fn test_set_parent() {
        let parent_scope = Rc::new(Scope::new(dummy_get_roots));
        let mut test_scope = Scope::new(dummy_get_roots);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(&parent_scope);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_add_child() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let child_scope1 = Scope::new(dummy_get_roots);
        let child_scope2 = Scope::new(dummy_get_roots);
        assert_eq!(test_scope.children.len(), 0);
        test_scope.add_child(child_scope1);
        assert_eq!(test_scope.children.len(), 1);
        test_scope.add_child(child_scope2);
        assert_eq!(test_scope.children.len(), 2);
    }

    #[test]
    fn test_alloc() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let test_uuid = test_var.uuid.clone();
        let uuid = test_scope.alloc(test_var);
        assert_eq!(test_uuid, uuid);
        assert!(test_scope.white_set.contains_key(&uuid));
        assert_eq!(test_scope.white_set.len(), 1);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
        let test_var2 = make_num(2.0);
        let uuid = test_scope.alloc(test_var2);
        assert!(test_scope.white_set.contains_key(&uuid));
        assert_eq!(test_scope.white_set.len(), 2);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
    }

    #[test]
    fn test_dealloc() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let bad_uuid = Uuid::new_v4();
        assert!(test_scope.dealloc(&uuid));
        assert_eq!(test_scope.white_set.len(), 0);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
        assert!(!test_scope.dealloc(&bad_uuid));
    }

    #[test]
    fn test_get_var_copy() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let bad_uuid = Uuid::new_v4();
        let var_copy = test_scope.get_var_copy(&uuid);
        assert!(var_copy.is_some());
        let var = var_copy.unwrap();
        assert_eq!(var.uuid, uuid);
        let bad_copy = test_scope.get_var_copy(&bad_uuid);
        assert!(bad_copy.is_none());
    }

    #[test]
    fn test_update_var() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let mut update = test_scope.get_var_copy(&uuid).unwrap();
        update = make_num(2.0);
        update.uuid = uuid;
        assert!(test_scope.update_var(update));
        let update = test_scope.get_var_copy(&uuid).unwrap();
        match update {
            JsVar{ t: JsType::JsNum(i), ..} => assert_eq!(i, 2.0),
            _ => ()
        }
        test_scope.dealloc(&uuid);
        assert!(!test_scope.update_var(update));
    }

    #[test]
    fn test_mark_roots() {
        let test_uuid = Uuid::new_v4();
        let mut test_var = make_num(1.0);
        let mut test_var2 = make_num(2.0);
        test_var.uuid = test_uuid;
        let simple_get_roots = move || { let mut set = HashSet::new();
                                    set.insert(test_uuid);
                                    set };
        let mut test_scope = Scope::new(simple_get_roots);
        let test_uuid = test_scope.alloc(test_var);
        let test_uuid2 = test_scope.alloc(test_var2);
        test_scope.mark_roots();
        assert_eq!(test_scope.black_set.len(), 1);
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert!(test_scope.black_set.get(&test_uuid2).is_none());
    }

    #[test]
    fn test_mark_phase() {
        let test_uuid = Uuid::new_v4();
        let simple_get_roots = move || { let mut set = HashSet::new();
                                    set.insert(test_uuid);
                                    set };
        let mut test_scope = Scope::new(simple_get_roots);

        let mut test_var2 = make_num(2.0);
        let test_uuid2 = test_scope.alloc(test_var2);
        let test_var2_alloc = test_scope.find_id(&test_uuid2).unwrap().clone();

        let test_key = JsKey::new(JsKeyEnum::JsNum(1.0));
        let mut test_var = make_obj(vec![(test_key, test_var2_alloc)]);
        test_var.uuid = test_uuid;
        let test_uuid = test_scope.alloc(test_var);

        // Mark roots first...
        test_scope.mark_roots();
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert_eq!(test_scope.black_set.len(), 1);
        assert_eq!(test_scope.grey_set.len(), 1);

        // ...then mark everything else
        test_scope.mark_phase();

        assert_eq!(test_scope.grey_set.len(), 0);
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert!(test_scope.black_set.get(&test_uuid2).is_some());
    }*/
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]
#[test]
fn it_works() {
}

pub mod svm {
    mod slist {
        use svm::slist::List::{Cons,Nil};
        /// Singly-linked cons list.
        ///
        /// This is used internally to represent list primitives in the machine.
        enum List<T> {
            Nil,
            Cons(T, Box<List<T>>)
        }

        /// Public implementation for List.
        impl<T> List<T> {

            /// Creates a new empty list
            fn new() -> List<T> {
                Nil
            }

            /// Prepends the given item to the list
            fn prepend(self, it: T) -> List<T> {
                Cons(it, box self)
            }

            /// Returns the length of the list
            fn length (&self) -> i32 {
                match *self {
                    Cons(_, ref tail) => 1 + tail.length(),
                    Nil => 0
                }
            }
        }
    }

    enum Exp {
        Number(i32)
    }

    struct Engine {
        stack: Vec<Exp>
    }
}
<commit_msg>Add to_string() for List<commit_after>#![feature(box_syntax)]
#[test]
fn it_works() {
}

pub mod svm {
    mod slist {

        use svm::slist::List::{Cons,Nil};
        use std::fmt::Show;

        /// Singly-linked cons list.
        ///
        /// This is used internally to represent list primitives in the machine.
        #[deriving(Show)]
        pub enum List<T> {
            Cons(T, Box<List<T>>),
            Nil,
        }

        /// Public implementation for List.
        impl<T> List<T> {

            /// Creates a new empty list
            fn new() -> List<T> {
                Nil
            }

            /// Prepends the given item to the list
            fn prepend(self, it: T) -> List<T> {
                Cons(it, box self)
            }

            /// Returns the length of the list
            fn length (&self) -> i32 {
                match *self {
                    Cons(_, ref tail) => 1 + tail.length(),
                    Nil => 0
                }
            }
        }

        impl<T> List<T> where T: Show {
            /// Return a string representation of the list
            fn to_string(&self) -> String {
                match *self {
                    Cons(ref head, ref tail) => format!("({:?}, {})", head, tail.to_string()),
                    Nil => format!("nil")
                }

            }
        }

        #[cfg(test)]
        mod tests {
            use super::List;
            use super::List::{Cons,Nil};

            #[test]
            fn test_length() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.length(), 3);
            }

             #[test]
            fn test_to_string() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.to_string(), "(1i32, (2i32, (3i32, nil)))");
            }
        }
    }

    enum Exp {
        Number(i32)
    }

    struct Engine {
        stack: Vec<Exp>
    }
}
<|endoftext|>


<commit_before>//! Handle `cargo rm` arguments

use errors::*;

#[derive(Debug, Deserialize)]
/// Docopts input args.
pub struct Args {
    /// Crate name (usage 1)
    pub arg_crate: String,
    /// Crate names (usage 2)
    pub arg_crates: Vec<String>,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
    /// '--quiet'
    pub flag_quiet: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.flag_dev {
            "dev-dependencies"
        } else if self.flag_build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self) -> Result<Vec<String>> {
        if !self.arg_crates.is_empty() {
            return Ok(self.arg_crates.to_owned());
        }

        Ok(vec![self.arg_crate.to_owned()])
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            arg_crates: vec![],
            flag_dev: false,
            flag_build: false,
            flag_manifest_path: None,
            flag_version: false,
            flag_quiet: false,
        }
    }
}
<commit_msg>fix my stupid bug<commit_after>//! Handle `cargo rm` arguments

use crate::errors::*;

#[derive(Debug, Deserialize)]
/// Docopts input args.
pub struct Args {
    /// Crate name (usage 1)
    pub arg_crate: String,
    /// Crate names (usage 2)
    pub arg_crates: Vec<String>,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
    /// '--quiet'
    pub flag_quiet: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.flag_dev {
            "dev-dependencies"
        } else if self.flag_build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self) -> Result<Vec<String>> {
        if !self.arg_crates.is_empty() {
            return Ok(self.arg_crates.to_owned());
        }

        Ok(vec![self.arg_crate.to_owned()])
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            arg_crates: vec![],
            flag_dev: false,
            flag_build: false,
            flag_manifest_path: None,
            flag_version: false,
            flag_quiet: false,
        }
    }
}
<|endoftext|>


<commit_before>// cargo.rs - Rust package manager

import rustc::syntax::{ast, codemap, visit};
import rustc::syntax::parse::parser;

import std::fs;
import std::generic_os;
import std::io;
import std::option;
import std::option::{none, some};
import std::os;
import std::run;
import std::str;
import std::tempfile;
import std::vec;

type cargo = {
    root: str,
    bindir: str,
    libdir: str,
    workdir: str,
    fetchdir: str
};

type pkg = {
    name: str,
    vers: str,
    uuid: str,
    desc: option::t<str>,
    sigs: option::t<str>,
    crate_type: option::t<str>
};

fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
                                         option::t<str>,
                                         option::t<str>) {
    let name = none;
    let vers = none;
    let uuid = none;
    for a: @ast::meta_item in mis {
        alt a.node {
            ast::meta_name_value(v, {node: ast::lit_str(s), span: _}) {
                alt v {
                    "name" { name = some(s); }
                    "vers" { vers = some(s); }
                    "uuid" { uuid = some(s); }
                    _ { }
                }
            }
        }
    }
    (name, vers, uuid)
}

fn load_pkg(filename: str) -> option::t<pkg> {
    let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
    let c = parser::parse_crate_from_crate_file(filename, [], sess);

    let name = none;
    let vers = none;
    let uuid = none;
    let desc = none;
    let sigs = none;
    let crate_type = none;

    for a in c.node.attrs {
        alt a.node.value.node {
            ast::meta_name_value(v, {node: ast::lit_str(s), span: _}) {
                alt v {
                    "desc" { desc = some(v); }
                    "sigs" { sigs = some(v); }
                    "crate_type" { crate_type = some(v); }
                    _ { }
                }
            }
            ast::meta_list(v, mis) {
                if v == "link" {
                    let (n, v, u) = load_link(mis);
                    name = n;
                    vers = v;
                    uuid = u;
                }
            }
        }
    }

    alt (name, vers, uuid) {
        (some(name0), some(vers0), some(uuid0)) {
            some({
                name: name0,
                vers: vers0,
                uuid: uuid0,
                desc: desc,
                sigs: sigs,
                crate_type: crate_type})
        }
        _ { ret none; }
    }
}

fn print(s: str) {
    io::stdout().write_line(s);
}

fn rest(s: str, start: uint) -> str {
    if (start >= str::char_len(s)) {
        ""
    } else {
        str::char_slice(s, start, str::char_len(s))
    }
}

fn need_dir(s: str) {
    if fs::file_is_dir(s) { ret; }
    if !fs::make_dir(s, 0x1c0i32) {
        fail #fmt["can't make_dir %s", s];
    }
}

fn configure() -> cargo {
    let p = alt generic_os::getenv("CARGO_ROOT") {
        some(_p) { _p }
        none. {
            alt generic_os::getenv("HOME") {
                some(_q) { fs::connect(_q, "/.cargo") }
                none. { fail "no CARGO_ROOT or HOME"; }
            }
        }
    };

    log #fmt["p: %s", p];

    let c = {
        root: p,
        bindir: fs::connect(p, "bin"),
        libdir: fs::connect(p, "lib"),
        workdir: fs::connect(p, "work"),
        fetchdir: fs::connect(p, "fetch")
    };

    need_dir(c.root);
    need_dir(c.fetchdir);
    need_dir(c.workdir);
    need_dir(c.libdir);
    need_dir(c.bindir);

    c
}

fn install_one_crate(c: cargo, path: str, cf: str, p: pkg) {
    let name = fs::basename(cf);
    let ri = str::index(name, '.' as u8);
    if ri != -1 {
        name = str::slice(name, 0u, ri as uint);
    }
    log #fmt["Installing: %s", name];
    let old = fs::list_dir(".");
    run::run_program("rustc", [cf]);
    let new = fs::list_dir(".");
    let created = vec::filter::<str>({ |n| !vec::member::<str>(n, old) }, new);
    for ct: str in created {
        if str::ends_with(ct, os::exec_suffix()) {
            log #fmt["  bin: %s", ct];
            // FIXME: need libstd fs::copy or something
            run::run_program("cp", [ct, c.bindir]);
        } else {
            log #fmt["  lib: %s", ct];
            run::run_program("cp", [ct, c.libdir]);
        }
    }
}

fn install_source(c: cargo, path: str) {
    log #fmt["source: %s", path];
    fs::change_dir(path);
    let contents = fs::list_dir(".");

    log #fmt["contents: %s", str::connect(contents, ", ")];

    let cratefiles = vec::filter::<str>({ |n| str::ends_with(n, ".rc") }, contents);

    if vec::is_empty(cratefiles) {
        fail "This doesn't look like a rust package (no .rc files).";
    }

    for cf: str in cratefiles {
        let p = load_pkg(cf);
        alt p {
            none. { cont; }
            some(_p) {
                install_one_crate(c, path, cf, _p);
            }
        }
    }
}

fn install_file(c: cargo, _path: str) {
    let wd = tempfile::mkdtemp(c.workdir + fs::path_sep(), "");
    alt wd {
        some(p) {
            run::run_program("tar", ["-x", "--strip-components=1",
                                     "-C", p, "-f", _path]);
            install_source(c, p);
        }
        _ { fail "needed temp dir"; }
    }
}

fn cmd_install(c: cargo, argv: [str]) {
    // cargo install <pkg>
    if vec::len(argv) < 3u {
        cmd_usage();
        ret;
    }

    if str::starts_with(argv[2], "file:") {
        let path = rest(argv[2], 5u);
        install_file(c, path);
    }
}

fn cmd_usage() {
    print("Usage: cargo <verb> [args...]");
}

fn main(argv: [str]) {
    if vec::len(argv) < 2u {
        cmd_usage();
        ret;
    }
    let c = configure();
    alt argv[1] {
        "install" { cmd_install(c, argv); }
        "usage" { cmd_usage(); }
        _ { cmd_usage(); }
    }
}
<commit_msg>cargo: don't stick an extra / in CARGO_ROOT<commit_after>// cargo.rs - Rust package manager

import rustc::syntax::{ast, codemap, visit};
import rustc::syntax::parse::parser;

import std::fs;
import std::generic_os;
import std::io;
import std::option;
import std::option::{none, some};
import std::os;
import std::run;
import std::str;
import std::tempfile;
import std::vec;

type cargo = {
    root: str,
    bindir: str,
    libdir: str,
    workdir: str,
    fetchdir: str
};

type pkg = {
    name: str,
    vers: str,
    uuid: str,
    desc: option::t<str>,
    sigs: option::t<str>,
    crate_type: option::t<str>
};

fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
                                         option::t<str>,
                                         option::t<str>) {
    let name = none;
    let vers = none;
    let uuid = none;
    for a: @ast::meta_item in mis {
        alt a.node {
            ast::meta_name_value(v, {node: ast::lit_str(s), span: _}) {
                alt v {
                    "name" { name = some(s); }
                    "vers" { vers = some(s); }
                    "uuid" { uuid = some(s); }
                    _ { }
                }
            }
        }
    }
    (name, vers, uuid)
}

fn load_pkg(filename: str) -> option::t<pkg> {
    let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
    let c = parser::parse_crate_from_crate_file(filename, [], sess);

    let name = none;
    let vers = none;
    let uuid = none;
    let desc = none;
    let sigs = none;
    let crate_type = none;

    for a in c.node.attrs {
        alt a.node.value.node {
            ast::meta_name_value(v, {node: ast::lit_str(s), span: _}) {
                alt v {
                    "desc" { desc = some(v); }
                    "sigs" { sigs = some(v); }
                    "crate_type" { crate_type = some(v); }
                    _ { }
                }
            }
            ast::meta_list(v, mis) {
                if v == "link" {
                    let (n, v, u) = load_link(mis);
                    name = n;
                    vers = v;
                    uuid = u;
                }
            }
        }
    }

    alt (name, vers, uuid) {
        (some(name0), some(vers0), some(uuid0)) {
            some({
                name: name0,
                vers: vers0,
                uuid: uuid0,
                desc: desc,
                sigs: sigs,
                crate_type: crate_type})
        }
        _ { ret none; }
    }
}

fn print(s: str) {
    io::stdout().write_line(s);
}

fn rest(s: str, start: uint) -> str {
    if (start >= str::char_len(s)) {
        ""
    } else {
        str::char_slice(s, start, str::char_len(s))
    }
}

fn need_dir(s: str) {
    if fs::file_is_dir(s) { ret; }
    if !fs::make_dir(s, 0x1c0i32) {
        fail #fmt["can't make_dir %s", s];
    }
}

fn configure() -> cargo {
    let p = alt generic_os::getenv("CARGO_ROOT") {
        some(_p) { _p }
        none. {
            alt generic_os::getenv("HOME") {
                some(_q) { fs::connect(_q, ".cargo") }
                none. { fail "no CARGO_ROOT or HOME"; }
            }
        }
    };

    log #fmt["p: %s", p];

    let c = {
        root: p,
        bindir: fs::connect(p, "bin"),
        libdir: fs::connect(p, "lib"),
        workdir: fs::connect(p, "work"),
        fetchdir: fs::connect(p, "fetch")
    };

    need_dir(c.root);
    need_dir(c.fetchdir);
    need_dir(c.workdir);
    need_dir(c.libdir);
    need_dir(c.bindir);

    c
}

fn install_one_crate(c: cargo, path: str, cf: str, p: pkg) {
    let name = fs::basename(cf);
    let ri = str::index(name, '.' as u8);
    if ri != -1 {
        name = str::slice(name, 0u, ri as uint);
    }
    log #fmt["Installing: %s", name];
    let old = fs::list_dir(".");
    run::run_program("rustc", [cf]);
    let new = fs::list_dir(".");
    let created = vec::filter::<str>({ |n| !vec::member::<str>(n, old) }, new);
    for ct: str in created {
        if str::ends_with(ct, os::exec_suffix()) {
            log #fmt["  bin: %s", ct];
            // FIXME: need libstd fs::copy or something
            run::run_program("cp", [ct, c.bindir]);
        } else {
            log #fmt["  lib: %s", ct];
            run::run_program("cp", [ct, c.libdir]);
        }
    }
}

fn install_source(c: cargo, path: str) {
    log #fmt["source: %s", path];
    fs::change_dir(path);
    let contents = fs::list_dir(".");

    log #fmt["contents: %s", str::connect(contents, ", ")];

    let cratefiles = vec::filter::<str>({ |n| str::ends_with(n, ".rc") }, contents);

    if vec::is_empty(cratefiles) {
        fail "This doesn't look like a rust package (no .rc files).";
    }

    for cf: str in cratefiles {
        let p = load_pkg(cf);
        alt p {
            none. { cont; }
            some(_p) {
                install_one_crate(c, path, cf, _p);
            }
        }
    }
}

fn install_file(c: cargo, _path: str) {
    let wd = tempfile::mkdtemp(c.workdir + fs::path_sep(), "");
    alt wd {
        some(p) {
            run::run_program("tar", ["-x", "--strip-components=1",
                                     "-C", p, "-f", _path]);
            install_source(c, p);
        }
        _ { fail "needed temp dir"; }
    }
}

fn cmd_install(c: cargo, argv: [str]) {
    // cargo install <pkg>
    if vec::len(argv) < 3u {
        cmd_usage();
        ret;
    }

    if str::starts_with(argv[2], "file:") {
        let path = rest(argv[2], 5u);
        install_file(c, path);
    }
}

fn cmd_usage() {
    print("Usage: cargo <verb> [args...]");
}

fn main(argv: [str]) {
    if vec::len(argv) < 2u {
        cmd_usage();
        ret;
    }
    let c = configure();
    alt argv[1] {
        "install" { cmd_install(c, argv); }
        "usage" { cmd_usage(); }
        _ { cmd_usage(); }
    }
}
<|endoftext|>