<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#[doc(hidden)]
#[macro_export]
macro_rules! consumes_to {
    ( $_rules:ident, $tokens:expr, [] ) => ();
    ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr ) ] ) => {
        let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $start);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::Start { rule, pos } => {
                let message = format!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());

                if rule != $rules::$name || pos.pos() != $start {
                    panic!("{}", message);
                }
            },
            token => panic!("{}", format!("{} but found {:?}", expected, token))
        };

        let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $end);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::End { rule, pos } => {
                let message = format!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());

                if rule != $rules::$name || pos.pos() != $end {
                    panic!("{}", message);
                }
            },
            token => panic!("{}", format!("{} but found {:?}", expected, token))
        };
    };
    ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr ),
                                    $( $names:ident $calls:tt ),* $(,)* ] ) => {

        let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $start);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::Start { rule, pos } => {
                let message = format!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());

                if rule != $rules::$name || pos.pos() != $start {
                    panic!("{}", message);
                }
            },
            token => panic!("{}", format!("{} but found {:?}", expected, token))
        };

        let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $end);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::End { rule, pos } => {
                let message = format!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());

                if rule != $rules::$name || pos.pos() != $end {
                    panic!("{}", message);
                }
            },
            token => panic!("{}", format!("{} but found {:?}", expected, token))
        };

        consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
    };
    ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr,
                                                  [ $( $names:ident $calls:tt ),* $(,)* ] ) ] ) => {
        let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $start);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::Start { rule, pos } => {
                let message = format!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());

                if rule != $rules::$name || pos.pos() != $start {
                    panic!("{}", message);
                }
            },
            token => panic!("{}", format!("{} but found {:?}", expected, token))
        };

        consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);

        let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $end);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::End { rule, pos } => {
                let message = format!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());

                if rule != $rules::$name || pos.pos() != $end {
                    panic!("{}", message);
                }
            },
            token => panic!("{}", format!("{} but found {:?}", expected, token))
        };
    };
    ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr,
                                                  [ $( $nested_names:ident $nested_calls:tt ),*
                                                  $(,)* ] ),
                                    $( $names:ident $calls:tt ),* ] ) => {

        let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $start);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::Start { rule, pos } => {
                let message = format!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());

                if rule != $rules::$name || pos.pos() != $start {
                    panic!("{}", message);
                }
            },
            token => panic!("{}", format!("{} but found {:?}", expected, token))
        };

        consumes_to!($rules, $tokens, [ $( $nested_names $nested_calls ),* ]);

        let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $end);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::End { rule, pos } => {
                let message = format!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());

                if rule != $rules::$name || pos.pos() != $end {
                    panic!("{}", message);
                }
            },
            token => panic!("{}", format!("{} but found {:?}", expected, token))
        };

        consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
    };
}

/// Testing tool that compares produced tokens.
///
/// This macro takes several arguments:
///
/// * `parser` - name of the data structure implementing `Parser`
/// * `input` - input to be tested against
/// * `rule` - `Rule` which will be run
/// * `tokens` - token pairs of the form `name(start_pos, end_pos, [nested_child_tokens])`
///
/// *Note:* `start_pos` and `end_pos` are byte positions.
///
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate pest;
/// # use pest::Parser;
/// # use pest::error::Error;
/// # use pest::iterators::Pairs;
/// # fn main() {
/// # #[allow(non_camel_case_types)]
/// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
/// # enum Rule {
/// #     a,
/// #     b,
/// #     c
/// # }
/// #
/// # struct AbcParser;
/// #
/// # impl Parser<Rule> for AbcParser {
/// #     fn parse<'i>(_: Rule, input: &'i str) -> Result<Pairs<'i, Rule>, Error<Rule>> {
/// #         pest::state(input, |state| {
/// #             state.rule(Rule::a, |state| {
/// #                 state.skip(1).unwrap().rule(Rule::b, |state| {
/// #                     state.skip(1)
/// #                 }).unwrap().skip(1)
/// #             }).and_then(|state| {
/// #                 state.skip(1).unwrap().rule(Rule::c, |state| {
/// #                     state.skip(1)
/// #                 })
/// #             })
/// #         })
/// #     }
/// # }
/// parses_to! {
///     parser: AbcParser,
///     input:  "abcde",
///     rule:   Rule::a,
///     tokens: [
///         a(0, 3, [
///             b(1, 2)
///         ]),
///         c(4, 5)
///     ]
/// };
/// # }
/// ```
#[macro_export]
macro_rules! parses_to {
    ( parser: $parser:ident, input: $string:expr, rule: $rules:tt :: $rule:tt,
      tokens: [ $( $names:ident $calls:tt ),* $(,)* ] ) => {

        #[allow(unused_mut)]
        {
            use $crate::Parser;

            let mut tokens = $parser::parse($rules::$rule, $string).unwrap().tokens();

            consumes_to!($rules, &mut tokens, [ $( $names $calls ),* ]);

            let rest: Vec<_> = tokens.collect();

            match rest.len() {
                0 => (),
                2 => {
                    let (first, second) = (&rest[0], &rest[1]);

                    match (first, second) {
                        (
                            &$crate::Token::Start { rule: ref first_rule, .. },
                            &$crate::Token::End { rule: ref second_rule, .. }
                        ) => {
                            assert!(
                                format!("{:?}", first_rule) == "EOI",
                                format!("expected end of input, but found {:?}", rest)
                            );
                            assert!(
                                format!("{:?}", second_rule) == "EOI",
                                format!("expected end of input, but found {:?}", rest)
                            );
                        }
                        _ => panic!("expected end of input, but found {:?}", rest)
                    }
                }
                _ => panic!("expected end of input, but found {:?}", rest)
            };
        }
    };
}

/// Testing tool that compares produced errors.
///
/// This macro takes several arguments:
///
/// * `parser` - name of the data structure implementing `Parser`
/// * `input` - input to be tested against
/// * `rule` - `Rule` which will be run
/// * `positives` - positive `Rule` attempts that failed
/// * `negative` - negative `Rule` attempts that failed
/// * `pos` - byte position of failure
///
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate pest;
/// # use pest::Parser;
/// # use pest::error::Error;
/// # use pest::iterators::Pairs;
/// # fn main() {
/// # #[allow(non_camel_case_types)]
/// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
/// # enum Rule {
/// #     a,
/// #     b,
/// #     c
/// # }
/// #
/// # struct AbcParser;
/// #
/// # impl Parser<Rule> for AbcParser {
/// #     fn parse<'i>(_: Rule, input: &'i str) -> Result<Pairs<'i, Rule>, Error<Rule>> {
/// #         pest::state(input, |state| {
/// #             state.rule(Rule::a, |state| {
/// #                 state.skip(1).unwrap().rule(Rule::b, |s| {
/// #                     s.skip(1)
/// #                 }).unwrap().skip(1)
/// #             }).and_then(|state| {
/// #                 state.skip(1).unwrap().rule(Rule::c, |s| {
/// #                     s.match_string("e")
/// #                 })
/// #             })
/// #         })
/// #     }
/// # }
/// fails_with! {
///     parser: AbcParser,
///     input: "abcdf",
///     rule: Rule::a,
///     positives: vec![Rule::c],
///     negatives: vec![],
///     pos: 4
/// };
/// # }
/// ```
#[macro_export]
macro_rules! fails_with {
    ( parser: $parser:ident, input: $string:expr, rule: $rules:tt :: $rule:tt,
      positives: $positives:expr, negatives: $negatives:expr, pos: $pos:expr ) => {
        #[allow(unused_mut)]
        {
            use $crate::Parser;

            let error = $parser::parse($rules::$rule, $string).unwrap_err();

            match error.variant {
                $crate::error::ErrorVariant::ParsingError {
                    positives,
                    negatives,
                } => {
                    assert_eq!(positives, $positives);
                    assert_eq!(negatives, $negatives);
                }
                _ => unreachable!(),
            };

            match error.location {
                $crate::error::InputLocation::Pos(pos) => assert_eq!(pos, $pos),
                _ => unreachable!(),
            }
        }
    };
}

#[cfg(test)]
pub mod tests {
    use super::super::error::Error;
    use super::super::iterators::Pairs;
    use super::super::{state, Parser};

    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    pub enum Rule {
        a,
        b,
        c,
    }

    pub struct AbcParser;

    impl Parser<Rule> for AbcParser {
        fn parse<'i>(_: Rule, input: &'i str) -> Result<Pairs<'i, Rule>, Error<Rule>> {
            state(input, |state| {
                state
                    .rule(Rule::a, |s| {
                        s.skip(1)
                            .unwrap()
                            .rule(Rule::b, |s| s.skip(1))
                            .unwrap()
                            .skip(1)
                    })
                    .and_then(|s| s.skip(1).unwrap().rule(Rule::c, |s| s.match_string("e")))
            })
        }
    }

    #[test]
    fn parses_to() {
        parses_to! {
            parser: AbcParser,
            input: "abcde",
            rule: Rule::a,
            tokens: [
                a(0, 3, [
                    b(1, 2),
                ]),
                c(4, 5)
            ]
        };
    }

    #[test]
    #[should_panic]
    fn missing_end() {
        parses_to! {
            parser: AbcParser,
            input: "abcde",
            rule: Rule::a,
            tokens: [
                a(0, 3, [
                    b(1, 2)
                ])
            ]
        };
    }

    #[test]
    #[should_panic]
    fn empty() {
        parses_to! {
            parser: AbcParser,
            input: "abcde",
            rule: Rule::a,
            tokens: []
        };
    }

    #[test]
    fn fails_with() {
        fails_with! {
            parser: AbcParser,
            input: "abcdf",
            rule: Rule::a,
            positives: vec![Rule::c],
            negatives: vec![],
            pos: 4
        };
    }

    #[test]
    #[should_panic]
    fn wrong_positives() {
        fails_with! {
            parser: AbcParser,
            input: "abcdf",
            rule: Rule::a,
            positives: vec![Rule::a],
            negatives: vec![],
            pos: 4
        };
    }

    #[test]
    #[should_panic]
    fn wrong_negatives() {
        fails_with! {
            parser: AbcParser,
            input: "abcdf",
            rule: Rule::a,
            positives: vec![Rule::c],
            negatives: vec![Rule::c],
            pos: 4
        };
    }

    #[test]
    #[should_panic]
    fn wrong_pos() {
        fails_with! {
            parser: AbcParser,
            input: "abcdf",
            rule: Rule::a,
            positives: vec![Rule::c],
            negatives: vec![],
            pos: 3
        };
    }
}
<commit_msg>remove redundant calls to format in macros<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#[doc(hidden)]
#[macro_export]
macro_rules! consumes_to {
    ( $_rules:ident, $tokens:expr, [] ) => ();
    ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr ) ] ) => {
        let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $start);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::Start { rule, pos } => {
                if rule != $rules::$name || pos.pos() != $start {
                    panic!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());
                }
            },
            token => panic!("{} but found {:?}", expected, token)
        };

        let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $end);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::End { rule, pos } => {
                if rule != $rules::$name || pos.pos() != $end {
                    panic!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());
                }
            },
            token => panic!("{} but found {:?}", expected, token)
        };
    };
    ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr ),
                                    $( $names:ident $calls:tt ),* $(,)* ] ) => {

        let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $start);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::Start { rule, pos } => {
                if rule != $rules::$name || pos.pos() != $start {
                    panic!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());
                }
            },
            token => panic!("{} but found {:?}", expected, token)
        };

        let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $end);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::End { rule, pos } => {
                if rule != $rules::$name || pos.pos() != $end {
                    panic!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());
                }
            },
            token => panic!("{} but found {:?}", expected, token)
        };

        consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
    };
    ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr,
                                                  [ $( $names:ident $calls:tt ),* $(,)* ] ) ] ) => {
        let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $start);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::Start { rule, pos } => {
                if rule != $rules::$name || pos.pos() != $start {
                    panic!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());
                }
            },
            token => panic!("{} but found {:?}", expected, token)
        };

        consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);

        let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $end);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::End { rule, pos } => {
                if rule != $rules::$name || pos.pos() != $end {
                    panic!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());
                }
            },
            token => panic!("{} but found {:?}", expected, token)
        };
    };
    ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr,
                                                  [ $( $nested_names:ident $nested_calls:tt ),*
                                                  $(,)* ] ),
                                    $( $names:ident $calls:tt ),* ] ) => {

        let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $start);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::Start { rule, pos } => {
                if rule != $rules::$name || pos.pos() != $start {
                    panic!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());
                }
            },
            token => panic!("{} but found {:?}", expected, token)
        };

        consumes_to!($rules, $tokens, [ $( $nested_names $nested_calls ),* ]);

        let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
                               $rules::$name, $end);
        match $tokens.next().expect(&format!("{} but found nothing", expected)) {
            $crate::Token::End { rule, pos } => {
                if rule != $rules::$name || pos.pos() != $end {
                    panic!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
                                      expected, rule, pos.pos());
                }
            },
            token => panic!("{} but found {:?}", expected, token)
        };

        consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
    };
}

/// Testing tool that compares produced tokens.
///
/// This macro takes several arguments:
///
/// * `parser` - name of the data structure implementing `Parser`
/// * `input` - input to be tested against
/// * `rule` - `Rule` which will be run
/// * `tokens` - token pairs of the form `name(start_pos, end_pos, [nested_child_tokens])`
///
/// *Note:* `start_pos` and `end_pos` are byte positions.
///
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate pest;
/// # use pest::Parser;
/// # use pest::error::Error;
/// # use pest::iterators::Pairs;
/// # fn main() {
/// # #[allow(non_camel_case_types)]
/// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
/// # enum Rule {
/// #     a,
/// #     b,
/// #     c
/// # }
/// #
/// # struct AbcParser;
/// #
/// # impl Parser<Rule> for AbcParser {
/// #     fn parse<'i>(_: Rule, input: &'i str) -> Result<Pairs<'i, Rule>, Error<Rule>> {
/// #         pest::state(input, |state| {
/// #             state.rule(Rule::a, |state| {
/// #                 state.skip(1).unwrap().rule(Rule::b, |state| {
/// #                     state.skip(1)
/// #                 }).unwrap().skip(1)
/// #             }).and_then(|state| {
/// #                 state.skip(1).unwrap().rule(Rule::c, |state| {
/// #                     state.skip(1)
/// #                 })
/// #             })
/// #         })
/// #     }
/// # }
/// parses_to! {
///     parser: AbcParser,
///     input:  "abcde",
///     rule:   Rule::a,
///     tokens: [
///         a(0, 3, [
///             b(1, 2)
///         ]),
///         c(4, 5)
///     ]
/// };
/// # }
/// ```
#[macro_export]
macro_rules! parses_to {
    ( parser: $parser:ident, input: $string:expr, rule: $rules:tt :: $rule:tt,
      tokens: [ $( $names:ident $calls:tt ),* $(,)* ] ) => {

        #[allow(unused_mut)]
        {
            use $crate::Parser;

            let mut tokens = $parser::parse($rules::$rule, $string).unwrap().tokens();

            consumes_to!($rules, &mut tokens, [ $( $names $calls ),* ]);

            let rest: Vec<_> = tokens.collect();

            match rest.len() {
                0 => (),
                2 => {
                    let (first, second) = (&rest[0], &rest[1]);

                    match (first, second) {
                        (
                            &$crate::Token::Start { rule: ref first_rule, .. },
                            &$crate::Token::End { rule: ref second_rule, .. }
                        ) => {
                            assert!(
                                format!("{:?}", first_rule) == "EOI",
                                "expected end of input, but found {:?}", rest
                            );
                            assert!(
                                format!("{:?}", second_rule) == "EOI",
                                "expected end of input, but found {:?}", rest
                            );
                        }
                        _ => panic!("expected end of input, but found {:?}", rest)
                    }
                }
                _ => panic!("expected end of input, but found {:?}", rest)
            };
        }
    };
}

/// Testing tool that compares produced errors.
///
/// This macro takes several arguments:
///
/// * `parser` - name of the data structure implementing `Parser`
/// * `input` - input to be tested against
/// * `rule` - `Rule` which will be run
/// * `positives` - positive `Rule` attempts that failed
/// * `negative` - negative `Rule` attempts that failed
/// * `pos` - byte position of failure
///
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate pest;
/// # use pest::Parser;
/// # use pest::error::Error;
/// # use pest::iterators::Pairs;
/// # fn main() {
/// # #[allow(non_camel_case_types)]
/// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
/// # enum Rule {
/// #     a,
/// #     b,
/// #     c
/// # }
/// #
/// # struct AbcParser;
/// #
/// # impl Parser<Rule> for AbcParser {
/// #     fn parse<'i>(_: Rule, input: &'i str) -> Result<Pairs<'i, Rule>, Error<Rule>> {
/// #         pest::state(input, |state| {
/// #             state.rule(Rule::a, |state| {
/// #                 state.skip(1).unwrap().rule(Rule::b, |s| {
/// #                     s.skip(1)
/// #                 }).unwrap().skip(1)
/// #             }).and_then(|state| {
/// #                 state.skip(1).unwrap().rule(Rule::c, |s| {
/// #                     s.match_string("e")
/// #                 })
/// #             })
/// #         })
/// #     }
/// # }
/// fails_with! {
///     parser: AbcParser,
///     input: "abcdf",
///     rule: Rule::a,
///     positives: vec![Rule::c],
///     negatives: vec![],
///     pos: 4
/// };
/// # }
/// ```
#[macro_export]
macro_rules! fails_with {
    ( parser: $parser:ident, input: $string:expr, rule: $rules:tt :: $rule:tt,
      positives: $positives:expr, negatives: $negatives:expr, pos: $pos:expr ) => {
        #[allow(unused_mut)]
        {
            use $crate::Parser;

            let error = $parser::parse($rules::$rule, $string).unwrap_err();

            match error.variant {
                $crate::error::ErrorVariant::ParsingError {
                    positives,
                    negatives,
                } => {
                    assert_eq!(positives, $positives);
                    assert_eq!(negatives, $negatives);
                }
                _ => unreachable!(),
            };

            match error.location {
                $crate::error::InputLocation::Pos(pos) => assert_eq!(pos, $pos),
                _ => unreachable!(),
            }
        }
    };
}

#[cfg(test)]
pub mod tests {
    use super::super::error::Error;
    use super::super::iterators::Pairs;
    use super::super::{state, Parser};

    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    pub enum Rule {
        a,
        b,
        c,
    }

    pub struct AbcParser;

    impl Parser<Rule> for AbcParser {
        fn parse<'i>(_: Rule, input: &'i str) -> Result<Pairs<'i, Rule>, Error<Rule>> {
            state(input, |state| {
                state
                    .rule(Rule::a, |s| {
                        s.skip(1)
                            .unwrap()
                            .rule(Rule::b, |s| s.skip(1))
                            .unwrap()
                            .skip(1)
                    })
                    .and_then(|s| s.skip(1).unwrap().rule(Rule::c, |s| s.match_string("e")))
            })
        }
    }

    #[test]
    fn parses_to() {
        parses_to! {
            parser: AbcParser,
            input: "abcde",
            rule: Rule::a,
            tokens: [
                a(0, 3, [
                    b(1, 2),
                ]),
                c(4, 5)
            ]
        };
    }

    #[test]
    #[should_panic]
    fn missing_end() {
        parses_to! {
            parser: AbcParser,
            input: "abcde",
            rule: Rule::a,
            tokens: [
                a(0, 3, [
                    b(1, 2)
                ])
            ]
        };
    }

    #[test]
    #[should_panic]
    fn empty() {
        parses_to! {
            parser: AbcParser,
            input: "abcde",
            rule: Rule::a,
            tokens: []
        };
    }

    #[test]
    fn fails_with() {
        fails_with! {
            parser: AbcParser,
            input: "abcdf",
            rule: Rule::a,
            positives: vec![Rule::c],
            negatives: vec![],
            pos: 4
        };
    }

    #[test]
    #[should_panic]
    fn wrong_positives() {
        fails_with! {
            parser: AbcParser,
            input: "abcdf",
            rule: Rule::a,
            positives: vec![Rule::a],
            negatives: vec![],
            pos: 4
        };
    }

    #[test]
    #[should_panic]
    fn wrong_negatives() {
        fails_with! {
            parser: AbcParser,
            input: "abcdf",
            rule: Rule::a,
            positives: vec![Rule::c],
            negatives: vec![Rule::c],
            pos: 4
        };
    }

    #[test]
    #[should_panic]
    fn wrong_pos() {
        fails_with! {
            parser: AbcParser,
            input: "abcdf",
            rule: Rule::a,
            positives: vec![Rule::c],
            negatives: vec![],
            pos: 3
        };
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate time;
extern crate timely;
extern crate differential_dataflow;

use timely::dataflow::*;
use timely::dataflow::operators::*;

use rand::{Rng, SeedableRng, StdRng};

use differential_dataflow::collection_trace::lookup::UnsignedInt;
use differential_dataflow::collection_trace::LeastUpperBound;
use differential_dataflow::operators::*;

fn main() {

    // define a new computational scope, in which to run BFS
    timely::execute_from_args(std::env::args(), |computation| {
        let start = time::precise_time_s();

        // define BFS dataflow; return handles to roots and edges inputs
        let (mut roots, mut graph) = computation.scoped(|scope| {

            let (edge_input, graph) = scope.new_input();
            let (node_input, roots) = scope.new_input();

            let dists = bfs(&graph, &roots);    // determine distances to each graph node

            dists.map(|((_,s),w)| (s,w))        // keep only the distances, not node ids
                 .consolidate(|x| *x)           // aggregate into one record per distance
                 .inspect_batch(move |t, x| {   // print up something neat for each update
                     println!("observed at {:?}:", t);
                     println!("elapsed: {}s", time::precise_time_s() - (start + t.inner as f64));
                     for y in x {
                         println!("\t{:?}", y);
                     }
                 });

            (node_input, edge_input)
        });

        let nodes = 100_000_000u32; // the u32 helps type inference understand what nodes are
        let edges = 200_000_000;

        let seed: &[_] = &[1, 2, 3, 4];
        let mut rng1: StdRng = SeedableRng::from_seed(seed);    // rng for edge additions
        let mut _rng2: StdRng = SeedableRng::from_seed(seed);    // rng for edge deletions

        println!("performing BFS on {} nodes, {} edges:", nodes, edges);

        // trickle edges in to dataflow
        for _ in 0..(edges/1000) {
            for _ in 0..1000 {
                graph.send(((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), 1));
            }
            computation.step();
        }

        // start the root set out with roots 0, 1, and 2
        roots.advance_to(0);
        computation.step();
        computation.step();
        computation.step();
        println!("loaded; elapsed: {}s", time::precise_time_s() - start);

        roots.send((0,1));
        roots.send((1,1));
        roots.send((2,1));
        roots.advance_to(1);
        roots.close();

        // // repeatedly change edges
        // let mut round = 0 as u32;
        // while computation.step() {
        //     // once each full second ticks, change an edge
        //     if time::precise_time_s() - start >= round as f64 {
        //         // add edges using prior rng; remove edges using fresh rng with the same seed
        //         let changes = vec![((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), 1),
        //                            ((rng2.gen_range(0, nodes), rng2.gen_range(0, nodes)),-1)];
        //         graph.send_at(round, changes.into_iter());
        //         graph.advance_to(round + 1);
        //         round += 1;
        //     }
        // }

        graph.close();                  // seal the source of edges
        while computation.step() { }    // wind down the computation
    });
}

// returns pairs (n, s) indicating node n can be reached from a root in s steps.
fn bfs<G: Scope, U>(edges: &Stream<G, ((U, U), i32)>, roots: &Stream<G, (U, i32)>)
    -> Stream<G, ((U, u32), i32)>
where G::Timestamp: LeastUpperBound,
      U: UnsignedInt {

    // initialize roots as reaching themselves at distance 0
    let nodes = roots.map(|(x,w)| ((x, 0), w));

    // repeatedly update minimal distances each node can be reached from each root
    nodes.iterate(u32::max_value(), |x| x.0, |inner| {

        let edges = inner.scope().enter(&edges);
        let nodes = inner.scope().enter(&nodes);

        inner.join_u(&edges, |l| l, |e| e, |_k,l,d| (*d, l+1))
             .concat(&nodes)
             .group_by_u(|x| x, |k,v| (*k, *v), |_, s, t| {
                 t.push((*s.peek().unwrap().0, 1));
             })
     })
}
<commit_msg>correcting for more rigid timely dataflow input operator<commit_after>extern crate rand;
extern crate time;
extern crate timely;
extern crate differential_dataflow;

use timely::dataflow::*;
use timely::dataflow::operators::*;

use rand::{Rng, SeedableRng, StdRng};

use differential_dataflow::collection_trace::lookup::UnsignedInt;
use differential_dataflow::collection_trace::LeastUpperBound;
use differential_dataflow::operators::*;

fn main() {

    // define a new computational scope, in which to run BFS
    timely::execute_from_args(std::env::args(), |computation| {
        let start = time::precise_time_s();

        // define BFS dataflow; return handles to roots and edges inputs
        let (mut roots, mut graph) = computation.scoped(|scope| {

            let (edge_input, graph) = scope.new_input();
            let (node_input, roots) = scope.new_input();

            let dists = bfs(&graph, &roots);    // determine distances to each graph node

            dists.map(|((_,s),w)| (s,w))        // keep only the distances, not node ids
                 .consolidate(|x| *x)           // aggregate into one record per distance
                 .inspect_batch(move |t, x| {   // print up something neat for each update
                     println!("observed at {:?}:", t);
                     println!("elapsed: {}s", time::precise_time_s() - (start + t.inner as f64));
                     for y in x {
                         println!("\t{:?}", y);
                     }
                 });

            (node_input, edge_input)
        });

        let nodes = 100_000_000u32; // the u32 helps type inference understand what nodes are
        let edges = 200_000_000;

        let seed: &[_] = &[1, 2, 3, 4];
        let mut rng1: StdRng = SeedableRng::from_seed(seed);    // rng for edge additions
        let mut _rng2: StdRng = SeedableRng::from_seed(seed);    // rng for edge deletions

        println!("performing BFS on {} nodes, {} edges:", nodes, edges);

        // trickle edges in to dataflow
        for _ in 0..(edges/1000) {
            for _ in 0..1000 {
                graph.send(((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), 1));
            }
            computation.step();
        }

        // start the root set out with roots 0, 1, and 2
        // roots.advance_to(0);
        computation.step();
        computation.step();
        computation.step();
        println!("loaded; elapsed: {}s", time::precise_time_s() - start);

        roots.send((0,1));
        roots.send((1,1));
        roots.send((2,1));
        roots.advance_to(1);
        roots.close();

        // // repeatedly change edges
        // let mut round = 0 as u32;
        // while computation.step() {
        //     // once each full second ticks, change an edge
        //     if time::precise_time_s() - start >= round as f64 {
        //         // add edges using prior rng; remove edges using fresh rng with the same seed
        //         let changes = vec![((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), 1),
        //                            ((rng2.gen_range(0, nodes), rng2.gen_range(0, nodes)),-1)];
        //         graph.send_at(round, changes.into_iter());
        //         graph.advance_to(round + 1);
        //         round += 1;
        //     }
        // }

        graph.close();                  // seal the source of edges
        while computation.step() { }    // wind down the computation
    });
}

// returns pairs (n, s) indicating node n can be reached from a root in s steps.
fn bfs<G: Scope, U>(edges: &Stream<G, ((U, U), i32)>, roots: &Stream<G, (U, i32)>)
    -> Stream<G, ((U, u32), i32)>
where G::Timestamp: LeastUpperBound,
      U: UnsignedInt {

    // initialize roots as reaching themselves at distance 0
    let nodes = roots.map(|(x,w)| ((x, 0), w));

    // repeatedly update minimal distances each node can be reached from each root
    nodes.iterate(u32::max_value(), |x| x.0, |inner| {

        let edges = inner.scope().enter(&edges);
        let nodes = inner.scope().enter(&nodes);

        inner.join_u(&edges, |l| l, |e| e, |_k,l,d| (*d, l+1))
             .concat(&nodes)
             .group_by_u(|x| x, |k,v| (*k, *v), |_, s, t| {
                 t.push((*s.peek().unwrap().0, 1));
             })
     })
}
<|endoftext|>


<commit_before>use super::scope::CowScope;
use super::CompileError;
use super::lexer::{Token, Symbol, Operator};
use super::function::Function;
use super::parser::{self, Parser, TokenStream};
use super::identifier::{IdMap, Identifier};
use super::expr::Expression;
use std::collections::VecMap;

/// Represents a function definition written in synthizer
#[derive(Show)]
pub struct FunctionDef {
	statement: Statement,
	args: VecMap<Option<f32>>, // Default arguments
	pub ident: Identifier,
}
impl<'a> Parser<'a> for FunctionDef {
	/// Parse a function definition from a token stream. Scope is used to find function definitions
	fn parse(tokens: TokenStream<'a>, scope: CowScope<'a>) -> Result<FunctionDef, CompileError> {
		let mut tokens = tokens;
		let mut args = VecMap::new();

		try!(expect!(tokens.next(), Token::Symbol(Symbol::LeftBracket), "expected `[`, got `{}`"));

		let fn_ident = try!(expect_value!(tokens.next(), Token::Ident, "expected function name, got `{}`"));

		loop {
			let next = tokens.next();
			let pos = next.map(|x| x.pos);
			let arg_ident = try!(expect_value!(next, Token::Ident, "expected argument name, got `{}`"));
			if args.contains_key(&arg_ident) {
				return Err(CompileError::new(format!("argument {} defined twice", arg_ident)).with_pos(pos.unwrap()));
			}

			let next = tokens.next();
			let (pos, mut token) = (next.map(|x| x.pos), next.map(|x| x.token));
			if let Some(Token::Symbol(Symbol::Equals)) = token {
				let nexttoken = tokens.next();
				let value = if let Ok(_) = expect!(nexttoken, Token::Operator(Operator::Sub)) {
					-try!(expect_value!(tokens.next(), Token::Const, "expected numerical constant, got `{}`"))
				} else {
					try!(expect_value!(nexttoken, Token::Const, "expected numerical constant, got `{}`"))
				};
				args.insert(arg_ident, Some(value));
				token = tokens.next().map(|x| x.token);
			}
			match token {
				Some(Token::Symbol(Symbol::Comma)) => {
					if !args.contains_key(&arg_ident) {
						args.insert(arg_ident, None);
					}
				}
				Some(Token::Symbol(Symbol::RightBracket)) => {
					if !args.contains_key(&arg_ident) {
						args.insert(arg_ident, None);
					}
					break;
				}
				Some(token) => return Err(CompileError::new(format!("expected `=`, `,` or `]`, got `{}`", token)).with_pos(pos.unwrap())),
				None => return Err(CompileError::new_static("expected `=`, `,` or `]`, got EOF")),
			}
		}
		//try!(expect!(iter.next().map(|(_, x)| x), Token::Symbol(Symbol::Colon), "expected `:` following function argument declaration, got `{}`"));

		let statement = if !tokens.is_empty() {
			try!(Parser::parse(tokens, scope))
		} else {
			return Err(CompileError::new_static("expected block, got EOF"));
		};

		Ok(FunctionDef {
			statement: statement,
			args: args,
			ident: fn_ident,
		})
	}
}
impl Function for FunctionDef {
	fn call(&self, _: CowScope, _: &IdMap) -> Result<f32, CompileError> {
		unimplemented!();
	}
}

#[derive(Show)]
enum Statement {
	Block(Vec<(Option<Expression>, Operator, Statement)>),
	Expr(Expression),
}

impl<'a> Parser<'a> for Statement {
	fn parse(tokens: TokenStream<'a>, scope: CowScope<'a>) -> Result<Statement, CompileError> {
		let mut tokens = tokens;
		let mut statements = Vec::new();
		match expect!(tokens.peek(0), Token::Symbol(Symbol::LeftBrace)) {
			// If it starts with `{` it's a block
			Ok(_) => {
				tokens.next(); // consume brace
				loop {
					let operator = match tokens.next().map(|x| x.token) {
						Some(Token::Operator(op)) => op,
						Some(Token::Newline) => continue,
						Some(Token::Symbol(Symbol::RightBrace)) => break,
						Some(x) =>
							return Err(CompileError::new(format!("expected operator, newline or }}, got {}", x)).with_pos(tokens.peek(0).map(|x| x.pos).unwrap())),
						None =>
							return Err(CompileError::new_static("expected operator, newline or `}`, got EOF"))
					};
					let mut condition = None;
					let start_pos = tokens.pos();
					let mut pos;
					if let Some(Token::Symbol(Symbol::LeftBrace)) = tokens.peek(0).map(|x| x.token) {
						tokens = try!(parser::match_paren(tokens, Token::Symbol(Symbol::LeftBrace), Token::Symbol(Symbol::RightBrace)));
					}
					loop {
						pos = tokens.pos();
						match tokens.next().map(|x| x.token) {
							Some(Token::Newline) => break,
							Some(Token::Symbol(Symbol::QuestionMark)) => {
								// parse condition
								let start_pos = pos;
								let mut pos;
								loop {
									pos = tokens.pos();
									match tokens.next().map(|x| x.token) {
										Some(Token::Newline) => break,
										Some(_) => { },
										None => return Err(CompileError::new_static("expected newline to end condition, got EOF")),
									}
								}
								condition = Some(try!(Parser::parse(tokens.slice(start_pos+1, pos), scope.clone())));
								break;
							}
							Some(_) => { }
							None =>
								return Err(CompileError::new_static("expected newline or `?` to end expression, got EOF")),
						}
					}
					let statement = try!(Parser::parse(tokens.slice(start_pos, pos), scope.clone()));
					statements.push((condition, operator, statement));
				}
			}

			// otherwise it's an expression
			Err(_) => {
				return Ok(Statement::Expr(try!(Parser::parse(tokens, scope))));
			}
		}
		Ok(Statement::Block(statements))
	}
}
impl Function for Statement {
	fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError> {
		match self {
			&Statement::Expr(ref x) =>
				x.call(scope, idmap),
			_ => unimplemented!(),
		}
	}
}
<commit_msg>fix a bug with const functions (functions that take no arguments).<commit_after>use super::scope::CowScope;
use super::CompileError;
use super::lexer::{Token, Symbol, Operator};
use super::function::Function;
use super::parser::{self, Parser, TokenStream};
use super::identifier::{IdMap, Identifier};
use super::expr::Expression;
use std::collections::VecMap;

/// Represents a function definition written in synthizer
#[derive(Show)]
pub struct FunctionDef {
	statement: Statement,
	args: VecMap<Option<f32>>, // Default arguments
	pub ident: Identifier,
}
impl<'a> Parser<'a> for FunctionDef {
	/// Parse a function definition from a token stream. Scope is used to find function definitions
	fn parse(tokens: TokenStream<'a>, scope: CowScope<'a>) -> Result<FunctionDef, CompileError> {
		let mut tokens = tokens;
		let mut args = VecMap::new();

		try!(expect!(tokens.next(), Token::Symbol(Symbol::LeftBracket), "expected `[`, got `{}`"));

		let fn_ident = try!(expect_value!(tokens.next(), Token::Ident, "expected function name, got `{}`"));

		loop {
			let next = tokens.next();
			if expect!(next, Token::Symbol(Symbol::RightBracket)).is_ok() {
				break;
			}
			let pos = next.map(|x| x.pos);
			let arg_ident = try!(expect_value!(next, Token::Ident, "expected argument name, got `{}`"));
			if args.contains_key(&arg_ident) {
				return Err(CompileError::new(format!("argument {} defined twice", arg_ident)).with_pos(pos.unwrap()));
			}

			let next = tokens.next();
			let (pos, mut token) = (next.map(|x| x.pos), next.map(|x| x.token));
			if let Some(Token::Symbol(Symbol::Equals)) = token {
				let nexttoken = tokens.next();
				let value = if let Ok(_) = expect!(nexttoken, Token::Operator(Operator::Sub)) {
					-try!(expect_value!(tokens.next(), Token::Const, "expected numerical constant, got `{}`"))
				} else {
					try!(expect_value!(nexttoken, Token::Const, "expected numerical constant, got `{}`"))
				};
				args.insert(arg_ident, Some(value));
				token = tokens.next().map(|x| x.token);
			}
			match token {
				Some(Token::Symbol(Symbol::Comma)) => {
					if !args.contains_key(&arg_ident) {
						args.insert(arg_ident, None);
					}
				}
				Some(Token::Symbol(Symbol::RightBracket)) => {
					if !args.contains_key(&arg_ident) {
						args.insert(arg_ident, None);
					}
					break;
				}
				Some(token) => return Err(CompileError::new(format!("expected `=`, `,` or `]`, got `{}`", token)).with_pos(pos.unwrap())),
				None => return Err(CompileError::new_static("expected `=`, `,` or `]`, got EOF")),
			}
		}
		//try!(expect!(iter.next().map(|(_, x)| x), Token::Symbol(Symbol::Colon), "expected `:` following function argument declaration, got `{}`"));

		let statement = if !tokens.is_empty() {
			try!(Parser::parse(tokens, scope))
		} else {
			return Err(CompileError::new_static("expected block, got EOF"));
		};

		Ok(FunctionDef {
			statement: statement,
			args: args,
			ident: fn_ident,
		})
	}
}
impl Function for FunctionDef {
	fn call(&self, _: CowScope, _: &IdMap) -> Result<f32, CompileError> {
		unimplemented!();
	}
}

#[derive(Show)]
enum Statement {
	Block(Vec<(Option<Expression>, Operator, Statement)>),
	Expr(Expression),
}

impl<'a> Parser<'a> for Statement {
	fn parse(tokens: TokenStream<'a>, scope: CowScope<'a>) -> Result<Statement, CompileError> {
		let mut tokens = tokens;
		let mut statements = Vec::new();
		match expect!(tokens.peek(0), Token::Symbol(Symbol::LeftBrace)) {
			// If it starts with `{` it's a block
			Ok(_) => {
				tokens.next(); // consume brace
				loop {
					let operator = match tokens.next().map(|x| x.token) {
						Some(Token::Operator(op)) => op,
						Some(Token::Newline) => continue,
						Some(Token::Symbol(Symbol::RightBrace)) => break,
						Some(x) =>
							return Err(CompileError::new(format!("expected operator, newline or }}, got {}", x)).with_pos(tokens.peek(0).map(|x| x.pos).unwrap())),
						None =>
							return Err(CompileError::new_static("expected operator, newline or `}`, got EOF"))
					};
					let mut condition = None;
					let start_pos = tokens.pos();
					let mut pos;
					if let Some(Token::Symbol(Symbol::LeftBrace)) = tokens.peek(0).map(|x| x.token) {
						tokens = try!(parser::match_paren(tokens, Token::Symbol(Symbol::LeftBrace), Token::Symbol(Symbol::RightBrace)));
					}
					loop {
						pos = tokens.pos();
						match tokens.next().map(|x| x.token) {
							Some(Token::Newline) => break,
							Some(Token::Symbol(Symbol::QuestionMark)) => {
								// parse condition
								let start_pos = pos;
								let mut pos;
								loop {
									pos = tokens.pos();
									match tokens.next().map(|x| x.token) {
										Some(Token::Newline) => break,
										Some(_) => { },
										None => return Err(CompileError::new_static("expected newline to end condition, got EOF")),
									}
								}
								condition = Some(try!(Parser::parse(tokens.slice(start_pos+1, pos), scope.clone())));
								break;
							}
							Some(_) => { }
							None =>
								return Err(CompileError::new_static("expected newline or `?` to end expression, got EOF")),
						}
					}
					let statement = try!(Parser::parse(tokens.slice(start_pos, pos), scope.clone()));
					statements.push((condition, operator, statement));
				}
			}

			// otherwise it's an expression
			Err(_) => {
				return Ok(Statement::Expr(try!(Parser::parse(tokens, scope))));
			}
		}
		Ok(Statement::Block(statements))
	}
}
impl Function for Statement {
	fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError> {
		match self {
			&Statement::Expr(ref x) =>
				x.call(scope, idmap),
			_ => unimplemented!(),
		}
	}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate futures_io;
extern crate futures_mio;
extern crate futures_tls;
extern crate net2;
#[macro_use]
extern crate futures;
extern crate httparse;
extern crate time;
#[macro_use]
extern crate log;

use std::io::{self, Read, Write};
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use futures::Future;
use futures::stream::Stream;
use futures_io::{TaskIo, Ready, IoFuture};
use futures_mio::{Loop, LoopHandle, TcpStream, TcpListener};
use futures_tls::ServerContext;

mod request;
pub use self::request::{Request, RequestHeaders};

mod response;
pub use self::response::Response;

mod io2;
pub use io2::{Parse, Serialize};
use io2::{ParseStream, StreamWriter};

mod date;

pub trait Service<Req, Resp>: Send + Sync + 'static
    where Req: Send + 'static,
          Resp: Send + 'static
{
    type Fut: Future<Item = Resp>;

    fn process(&self, req: Req) -> Self::Fut;
}

impl<Req, Resp, Fut, F> Service<Req, Resp> for F
    where F: Fn(Req) -> Fut + Send + Sync + 'static,
          Fut: Future<Item = Resp>,
          Req: Send + 'static,
          Resp: Send + 'static
{
    type Fut = Fut;

    fn process(&self, req: Req) -> Fut {
        (self)(req)
    }
}

pub struct Server {
    addr: SocketAddr,
    workers: u32,
    tls: Option<Box<Fn() -> io::Result<ServerContext> + Send + Sync>>,
}

struct ServerData<S> {
    service: S,
    tls: Option<Box<Fn() -> io::Result<ServerContext> + Send + Sync>>,
}

impl Server {
    pub fn new(addr: &SocketAddr) -> Server {
        Server {
            addr: *addr,
            workers: 1,
            tls: None,
        }
    }

    pub fn workers(&mut self, workers: u32) -> &mut Server {
        if cfg!(unix) {
            self.workers = workers;
        }
        self
    }

    pub fn tls<F>(&mut self, tls: F) -> &mut Server
        where F: Fn() -> io::Result<ServerContext> + Send + Sync + 'static,
    {
        self.tls = Some(Box::new(tls));
        self
    }

    pub fn serve<Req, Resp, S>(&mut self, s: S) -> io::Result<()>
        where Req: Parse,
              Resp: Serialize,
              S: Service<Req, Resp>,
              <S::Fut as Future>::Error: From<Req::Error> + From<io::Error>, // TODO: simplify this?
    {
        let data = Arc::new(ServerData {
            service: s,
            tls: self.tls.take(),
        });

        let threads = (0..self.workers - 1).map(|i| {
            let mut lp = Loop::new().unwrap();
            let data = data.clone();
            let listener = self.listener(lp.handle());
            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                lp.run(listener.and_then(move |l| {
                    l.incoming().for_each(move |(stream, _)| {
                        handle(stream, data.clone());
                        Ok(()) // TODO: error handling
                    })
                }))
            }).unwrap()
        }).collect::<Vec<_>>();

        let mut lp = Loop::new().unwrap();
        let listener = self.listener(lp.handle());
        lp.run(listener.and_then(move |l| {
            l.incoming().for_each(move |(stream, _)| {
                handle(stream, data.clone());
                Ok(()) // TODO: error handling
            })
        })).unwrap();

        for thread in threads {
            thread.join().unwrap().unwrap();
        }

        Ok(())
    }

    fn listener(&self, handle: LoopHandle) -> Box<IoFuture<TcpListener>> {
        let listener = (|| {
            let listener = try!(net2::TcpBuilder::new_v4());
            try!(self.configure_tcp(&listener));
            try!(listener.reuse_address(true));
            try!(listener.bind(&self.addr));
            listener.listen(1024)
        })();

        match listener {
            Ok(l) => TcpListener::from_listener(l, &self.addr, handle),
            Err(e) => futures::failed(e).boxed()
        }
    }

    #[cfg(unix)]
    fn configure_tcp(&self, tcp: &net2::TcpBuilder) -> io::Result<()> {
        use net2::unix::*;

        if self.workers > 1 {
            try!(tcp.reuse_port(true));
        }

        Ok(())
    }

    #[cfg(windows)]
    fn configure_tcp(&self, _tcp: &net2::TcpBuilder) -> io::Result<()> {
        Ok(())
    }
}

trait IoStream: Read + Write + Stream<Item=Ready, Error=io::Error> {}

impl<T: ?Sized> IoStream for T
    where T: Read + Write + Stream<Item=Ready, Error=io::Error>
{}

fn handle<Req, Resp, S>(stream: TcpStream, data: Arc<ServerData<S>>)
    where Req: Parse,
          Resp: Serialize,
          S: Service<Req, Resp>,
          <S::Fut as Future>::Error: From<Req::Error> + From<io::Error>,
{
    let io = match data.tls {
        Some(ref tls) => {
            tls().unwrap().handshake(stream).map(|b| {
                Box::new(b) as
                    Box<IoStream<Item=Ready, Error=io::Error>>
            }).boxed()
        }
        None => {
            let stream = Box::new(stream) as
                    Box<IoStream<Item=Ready, Error=io::Error>>;
            futures::finished(stream).boxed()
        }
    };
    let io = io.and_then(|io| TaskIo::new(io)).map_err(From::from).and_then(|io| {
        let (reader, writer) = io.split();

        let input = ParseStream::new(reader).map_err(From::from);
        let responses = input.and_then(move |req| data.service.process(req));
        StreamWriter::new(writer, responses)
    });

    // Crucially use `.forget()` here instead of returning the future, allows
    // processing multiple separate connections concurrently.
    io.forget();
}
<commit_msg>Fix compile of minihttp<commit_after>#[macro_use]
extern crate futures_io;
extern crate futures_mio;
extern crate futures_tls;
extern crate net2;
#[macro_use]
extern crate futures;
extern crate httparse;
extern crate time;
#[macro_use]
extern crate log;

use std::io::{self, Read, Write};
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use futures::Future;
use futures::stream::Stream;
use futures_io::{TaskIo, Ready, IoFuture};
use futures_mio::{Loop, LoopHandle, TcpStream, TcpListener};
use futures_tls::ServerContext;

mod request;
pub use self::request::{Request, RequestHeaders};

mod response;
pub use self::response::Response;

mod io2;
pub use io2::{Parse, Serialize};
use io2::{ParseStream, StreamWriter};

mod date;

pub trait Service<Req, Resp>: Send + Sync + 'static
    where Req: Send + 'static,
          Resp: Send + 'static
{
    type Fut: Future<Item = Resp>;

    fn process(&self, req: Req) -> Self::Fut;
}

impl<Req, Resp, Fut, F> Service<Req, Resp> for F
    where F: Fn(Req) -> Fut + Send + Sync + 'static,
          Fut: Future<Item = Resp>,
          Req: Send + 'static,
          Resp: Send + 'static
{
    type Fut = Fut;

    fn process(&self, req: Req) -> Fut {
        (self)(req)
    }
}

pub struct Server {
    addr: SocketAddr,
    workers: u32,
    tls: Option<Box<Fn() -> io::Result<ServerContext> + Send + Sync>>,
}

struct ServerData<S> {
    service: S,
    tls: Option<Box<Fn() -> io::Result<ServerContext> + Send + Sync>>,
}

impl Server {
    pub fn new(addr: &SocketAddr) -> Server {
        Server {
            addr: *addr,
            workers: 1,
            tls: None,
        }
    }

    pub fn workers(&mut self, workers: u32) -> &mut Server {
        if cfg!(unix) {
            self.workers = workers;
        }
        self
    }

    pub fn tls<F>(&mut self, tls: F) -> &mut Server
        where F: Fn() -> io::Result<ServerContext> + Send + Sync + 'static,
    {
        self.tls = Some(Box::new(tls));
        self
    }

    pub fn serve<Req, Resp, S>(&mut self, s: S) -> io::Result<()>
        where Req: Parse,
              Resp: Serialize,
              S: Service<Req, Resp>,
              <S::Fut as Future>::Error: From<Req::Error> + From<io::Error>, // TODO: simplify this?
    {
        let data = Arc::new(ServerData {
            service: s,
            tls: self.tls.take(),
        });

        let threads = (0..self.workers - 1).map(|i| {
            let (addr, workers) = (self.addr, self.workers);
            let data = data.clone();
            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                let mut lp = Loop::new().unwrap();
                let listener = listener(&addr, workers, lp.handle());
                lp.run(listener.and_then(move |l| {
                    l.incoming().for_each(move |(stream, _)| {
                        handle(stream, data.clone());
                        Ok(()) // TODO: error handling
                    })
                }))
            }).unwrap()
        }).collect::<Vec<_>>();

        let mut lp = Loop::new().unwrap();
        let listener = listener(&self.addr, self.workers, lp.handle());
        lp.run(listener.and_then(move |l| {
            l.incoming().for_each(move |(stream, _)| {
                handle(stream, data.clone());
                Ok(()) // TODO: error handling
            })
        })).unwrap();

        for thread in threads {
            thread.join().unwrap().unwrap();
        }

        Ok(())
    }
}

fn listener(addr: &SocketAddr,
            workers: u32,
            handle: LoopHandle) -> Box<IoFuture<TcpListener>> {
    let listener = (|| {
        let listener = try!(net2::TcpBuilder::new_v4());
        try!(configure_tcp(workers, &listener));
        try!(listener.reuse_address(true));
        try!(listener.bind(addr));
        listener.listen(1024)
    })();

    match listener {
        Ok(l) => TcpListener::from_listener(l, addr, handle),
        Err(e) => futures::failed(e).boxed()
    }
}

#[cfg(unix)]
fn configure_tcp(workers: u32, tcp: &net2::TcpBuilder) -> io::Result<()> {
    use net2::unix::*;

    if workers > 1 {
        try!(tcp.reuse_port(true));
    }

    Ok(())
}

#[cfg(windows)]
fn configure_tcp(workers: u32, _tcp: &net2::TcpBuilder) -> io::Result<()> {
    Ok(())
}

trait IoStream: Read + Write + Stream<Item=Ready, Error=io::Error> {}

impl<T: ?Sized> IoStream for T
    where T: Read + Write + Stream<Item=Ready, Error=io::Error>
{}

fn handle<Req, Resp, S>(stream: TcpStream, data: Arc<ServerData<S>>)
    where Req: Parse,
          Resp: Serialize,
          S: Service<Req, Resp>,
          <S::Fut as Future>::Error: From<Req::Error> + From<io::Error>,
{
    let io = match data.tls {
        Some(ref tls) => {
            tls().unwrap().handshake(stream).map(|b| {
                Box::new(b) as
                    Box<IoStream<Item=Ready, Error=io::Error>>
            }).boxed()
        }
        None => {
            let stream = Box::new(stream) as
                    Box<IoStream<Item=Ready, Error=io::Error>>;
            futures::finished(stream).boxed()
        }
    };
    let io = io.and_then(|io| TaskIo::new(io)).map_err(From::from).and_then(|io| {
        let (reader, writer) = io.split();

        let input = ParseStream::new(reader).map_err(From::from);
        let responses = input.and_then(move |req| data.service.process(req));
        StreamWriter::new(writer, responses)
    });

    // Crucially use `.forget()` here instead of returning the future, allows
    // processing multiple separate connections concurrently.
    io.forget();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate mioco;
extern crate env_logger;

use std::thread;
use std::io::{self, BufRead};
use std::time::Duration;

fn main() {
    env_logger::init().unwrap();
    let (mail_send, mail_recv) = mioco::sync::mpsc::sync_channel::<String>(5);

    thread::spawn(move|| {
        loop {
            println!("Enter something:");
            let stdin = io::stdin();
            let mut line = String::new();
            stdin.lock().read_line(&mut line).ok().expect("Failed to read line");
            let line = line.parse::<String>().expect("Not a number");
            let _ = mail_send.send(line);
        }
    });

    mioco::start(move || {
                loop {
                    let mut timer = mioco::timer::Timer::new();
                    timer.set_timeout(5000);
                    select!(
                        r:timer => {
                            println!("TIMEOUT");
                        },
                        r:mail_recv => {
                            thread::sleep(Duration::new(2, 0));
                            let message = mail_recv.recv();
                            println!("{:?}", message);
                        },
                    );
                }
    }).unwrap();
}
<commit_msg>adding print to see sync channel notification<commit_after>#[macro_use]
extern crate mioco;
extern crate env_logger;

use std::thread;
use std::io::{self, BufRead};
use std::time::Duration;

fn main() {
    env_logger::init().unwrap();
    let (mail_send, mail_recv) = mioco::sync::mpsc::sync_channel::<String>(5);

    thread::spawn(move|| {
        loop {
            println!("Enter something:");
            let stdin = io::stdin();
            let mut line = String::new();
            stdin.lock().read_line(&mut line).ok().expect("Failed to read line");
            let line = line.parse::<String>().expect("Not a number");
            let _ = mail_send.send(line);
        }
    });

    mioco::start(move || {
                loop {
                    let mut timer = mioco::timer::Timer::new();
                    timer.set_timeout(5000);
                    select!(
                        r:timer => {
                            println!("TIMEOUT");
                        },
                        r:mail_recv => {
                            println!("Reading ...");
                            thread::sleep(Duration::new(2, 0));
                            let message = mail_recv.recv();
                            println!("{:?}", message);
                        },
                    );
                }
    }).unwrap();
}
<|endoftext|>


<commit_before>

extern crate clap;
extern crate imageflow_helpers;
extern crate imageflow_types as s;
extern crate imageflow_core as fc;
extern crate serde_json;

use imageflow_helpers as hlp;

use std::path::{Path,PathBuf};
mod cmd_build;
pub mod self_test;

use clap::{App, Arg, SubCommand, AppSettings, Command};

fn artifact_source() -> hlp::process_capture::IncludeBinary{
    hlp::process_capture::IncludeBinary::UrlOrCopy(s::version::get_build_env_value("ESTIMATED_ARTIFACT_URL").map(|v| v.to_owned()))
}

pub fn main_with_exit_code() -> i32 {
    imageflow_helpers::debug::set_panic_hook_once();

    let version = s::version::one_line_version();
    let app = Command::new("imageflow_tool").version(version.as_ref())
        .arg(  Arg::new("capture-to").long("capture-to").takes_value(true)
            .help("Run whatever you're doing in a sub-process, capturing output, input, and version detail")
        ).subcommand_required(true).arg_required_else_help(true)
        .subcommand(
            Command::new("diagnose").arg_required_else_help(true)
                .about("Diagnostic utilities")
                .arg(
                    Arg::new("show-compilation-info").long("show-compilation-info")
                        .help("Show all the information stored in this executable about the environment in which it was compiled.")
                ).arg(
                Arg::new("self-test").long("self-test")
                    .help("Creates a 'self_tests' directory and runs self-tests"))
                .arg(
                    Arg::new("wait").long("wait")
                        .help("Process stays in memory until you press the enter key.")
                )
                .arg(
                    Arg::new("call-panic").long("call-panic")
                        .help("Triggers a Rust panic (so you can observe failure/backtrace behavior)")
                )
        )
        .subcommand(
            Command::new("examples")
                .about("Generate usage examples")
                .arg(
                    Arg::new("generate").long("generate").required(true)
                        .help("Create an 'examples' directory")
                )
        )

        // --json [path]
        // --response [response_json_path]
        // --demo [name]
        // --in 0 a.png b.png
        // --out a.png

        //Eventually:
        // --local-only (prevent remote URL requests)
        // --no-io-ids (Disables interpretation of numbers in --in and --out as io_id assignment).
        // --no-clobber
        // --debug (verbose, graph export, frame export?)
        // --debug-package

        // file.json --in a.png a.png --out s.png
        // file.json --in 0 a.png 1 b.png --out 3 base64

        .subcommand(Command::new("v1/build").alias("v0.1/build")
            .about("Runs the given operation file")
            .arg(
                Arg::new("in").long("in").min_values(1)
                    .multiple_occurrences(true)
                    .help("Replace/add inputs for the operation file")
            )
            .arg(Arg::new("out").long("out").multiple_occurrences(true).min_values(1)
                .help("Replace/add outputs for the operation file"))
            //.arg(Arg::new("demo").long("demo").takes_value(true).possible_values(&["example:200x200_png"]))
            .arg(Arg::new("json").long("json").takes_value(true).required(true).help("The JSON operation file."))
            .arg(Arg::new("quiet").long("quiet").takes_value(false).help("Don't write the JSON response to stdout"))
            .arg(Arg::new("response").long("response").takes_value(true).help("Write the JSON job result to file instead of stdout"))
            .arg(Arg::new("bundle-to").long("bundle-to").takes_value(true).help("Copies the recipe and all dependencies into the given folder, simplifying it."))
            .arg(Arg::new("debug-package").long("debug-package").takes_value(true).help("Creates a debug package in the given folder so others can reproduce the behavior you are seeing"))

        )
        .subcommand(Command::new("v1/querystring").aliases(&["v0.1/ir4","v1/ir4"])
            .about("Run an command querystring")
            .arg(
                Arg::new("in").long("in").min_values(1)
                    .multiple(true).required(true)
                    .help("Input image")
            )
            .arg(Arg::new("out").long("out").multiple(true).min_values(1).required(true)
                .help("Output image"))
            .arg(Arg::new("quiet").long("quiet").takes_value(false).help("Don't write the JSON response to stdout"))
            .arg(Arg::new("response").long("response").takes_value(true).help("Write the JSON job result to file instead of stdout"))
            .arg(Arg::new("command").long("command").takes_value(true).required(true).help("w=200&h=200&mode=crop&format=png&rotate=90&flip=v - querystring style command"))
            .arg(Arg::new("bundle-to").long("bundle-to").takes_value(true).help("Copies the recipe and all dependencies into the given folder, simplifying it."))
            .arg(Arg::new("debug-package").long("debug-package").takes_value(true).help("Creates a debug package in the given folder so others can reproduce the behavior you are seeing"))

        );
    let matches = app.get_matches();
    if matches.is_present("capture-to"){
        let mut filtered_args = std::env::args().collect::<Vec<String>>();
        for ix in 0..filtered_args.len() {
            if filtered_args[ix] == "--capture-to"{
                //Remove this and the next arg
                filtered_args.remove(ix);
                if ix < filtered_args.len() - 1{
                    filtered_args.remove(ix);
                }
                break;
            }
        }
        filtered_args.remove(0); //Remove the tool executable itself

        let cap = hlp::process_capture::CaptureTo::create(matches.value_of("capture-to").unwrap(), None, filtered_args, artifact_source());
        cap.run();
        return cap.exit_code();
    }

    let build_triple = if let Some(m) = matches.subcommand_matches("v1/build") {
        let source = if m.is_present("demo") {
            cmd_build::JobSource::NamedDemo(m.value_of("demo").unwrap().to_owned())
        } else {
            cmd_build::JobSource::JsonFile(m.value_of("json").unwrap().to_owned())
        };
        Some((m, source, "v1/build"))
    }else if let Some(m) = matches.subcommand_matches("v1/querystring"){
        Some((m,cmd_build::JobSource::Ir4QueryString(m.value_of("command").unwrap().to_owned()), "v1/querystring"))
    }else{ None };

    if let Some((m, source, subcommand_name)) = build_triple{

        let builder =
            cmd_build::CmdBuild::parse(source, m.values_of_lossy("in"), m.values_of_lossy("out"))
                .build_maybe();
        if let Some(dir_str) = m.value_of("debug-package").and_then(|v| Some(v.to_owned())){
            builder.write_errors_maybe().unwrap();
            let dir = Path::new(&dir_str);
            builder.bundle_to(dir);
            let curdir = std::env::current_dir().unwrap();
            std::env::set_current_dir(&dir).unwrap();
            let cap = hlp::process_capture::CaptureTo::create("recipe", None, vec![subcommand_name.to_owned(), "--json".to_owned(), "recipe.json".to_owned()], artifact_source());
            cap.run();
            //Restore current directory
            std::env::set_current_dir(&curdir).unwrap();
            let archive_name = PathBuf::from(format!("{}.zip", &dir_str));
            hlp::filesystem::zip_directory_nonrecursive(&dir,&archive_name.as_path()).unwrap();
            return cap.exit_code();
        } else if let Some(dir) = m.value_of("bundle-to").and_then(|v| Some(v.to_owned())) {
                builder.write_errors_maybe().unwrap();
                let dir = Path::new(&dir);
                return builder.bundle_to(dir);
        } else {
            builder.write_response_maybe(m.value_of("response"), !m.is_present("quiet"))
                .expect("IO error writing JSON output file. Does the directory exist?");
            builder.write_errors_maybe().expect("Writing to stderr failed!");
            return builder.get_exit_code().unwrap();
        }

    }

    if let Some(matches) = matches.subcommand_matches("diagnose") {
        let m: &clap::ArgMatches = matches;

        if m.is_present("show-compilation-info") {
            println!("{}\n{}\n",
                     s::version::one_line_version(),
                     s::version::all_build_info_pairs());
            return 0;
        }

        if m.is_present("self-test") {
            return self_test::run(None);
        }
        if m.is_present("wait") {
            let mut input_buf = String::new();
            let input = std::io::stdin().read_line(&mut input_buf).expect("Failed to read from stdin. Are you using --wait in a non-interactive shell?");
            println!("{}", input);
            return 0;
        }
        if m.is_present("call-panic") {
            panic!("Panicking on command");
        }
    }
    if let Some(matches) = matches.subcommand_matches("examples") {
        let m: &clap::ArgMatches = matches;

        if m.is_present("generate") {
            self_test::export_examples(None);
            return 0;
        }
    }

    64
}

#[test]
fn test_file_macro_for_this_build(){
    assert!(file!().starts_with("imageflow_tool"))
}
<commit_msg>Fix clap 3.0 deprecation warnings<commit_after>

extern crate clap;
extern crate imageflow_helpers;
extern crate imageflow_types as s;
extern crate imageflow_core as fc;
extern crate serde_json;

use imageflow_helpers as hlp;

use std::path::{Path,PathBuf};
mod cmd_build;
pub mod self_test;

use clap::{Arg,AppSettings, Command};

fn artifact_source() -> hlp::process_capture::IncludeBinary{
    hlp::process_capture::IncludeBinary::UrlOrCopy(s::version::get_build_env_value("ESTIMATED_ARTIFACT_URL").map(|v| v.to_owned()))
}

pub fn main_with_exit_code() -> i32 {
    imageflow_helpers::debug::set_panic_hook_once();

    let version = s::version::one_line_version();
    let app = Command::new("imageflow_tool").version(version.as_ref())
        .arg(  Arg::new("capture-to").long("capture-to").takes_value(true)
            .help("Run whatever you're doing in a sub-process, capturing output, input, and version detail")
        ).subcommand_required(true).arg_required_else_help(true)
        .subcommand(
            Command::new("diagnose").arg_required_else_help(true)
                .about("Diagnostic utilities")
                .arg(
                    Arg::new("show-compilation-info").long("show-compilation-info")
                        .help("Show all the information stored in this executable about the environment in which it was compiled.")
                ).arg(
                Arg::new("self-test").long("self-test")
                    .help("Creates a 'self_tests' directory and runs self-tests"))
                .arg(
                    Arg::new("wait").long("wait")
                        .help("Process stays in memory until you press the enter key.")
                )
                .arg(
                    Arg::new("call-panic").long("call-panic")
                        .help("Triggers a Rust panic (so you can observe failure/backtrace behavior)")
                )
        )
        .subcommand(
            Command::new("examples")
                .about("Generate usage examples")
                .arg(
                    Arg::new("generate").long("generate").required(true)
                        .help("Create an 'examples' directory")
                )
        )

        // --json [path]
        // --response [response_json_path]
        // --demo [name]
        // --in 0 a.png b.png
        // --out a.png

        //Eventually:
        // --local-only (prevent remote URL requests)
        // --no-io-ids (Disables interpretation of numbers in --in and --out as io_id assignment).
        // --no-clobber
        // --debug (verbose, graph export, frame export?)
        // --debug-package

        // file.json --in a.png a.png --out s.png
        // file.json --in 0 a.png 1 b.png --out 3 base64

        .subcommand(Command::new("v1/build").alias("v0.1/build")
            .about("Runs the given operation file")
            .arg(
                Arg::new("in").long("in").min_values(1)
                    .multiple_occurrences(true)
                    .help("Replace/add inputs for the operation file")
            )
            .arg(Arg::new("out").long("out").multiple_occurrences(true).min_values(1)
                .help("Replace/add outputs for the operation file"))
            //.arg(Arg::new("demo").long("demo").takes_value(true).possible_values(&["example:200x200_png"]))
            .arg(Arg::new("json").long("json").takes_value(true).required(true).help("The JSON operation file."))
            .arg(Arg::new("quiet").long("quiet").takes_value(false).help("Don't write the JSON response to stdout"))
            .arg(Arg::new("response").long("response").takes_value(true).help("Write the JSON job result to file instead of stdout"))
            .arg(Arg::new("bundle-to").long("bundle-to").takes_value(true).help("Copies the recipe and all dependencies into the given folder, simplifying it."))
            .arg(Arg::new("debug-package").long("debug-package").takes_value(true).help("Creates a debug package in the given folder so others can reproduce the behavior you are seeing"))

        )
        .subcommand(Command::new("v1/querystring").aliases(&["v0.1/ir4","v1/ir4"])
            .about("Run an command querystring")
            .arg(
                Arg::new("in").long("in").min_values(1)
                    .multiple_occurrences(true).required(true)
                    .help("Input image")
            )
            .arg(Arg::new("out").long("out").multiple_occurrences(true).min_values(1).required(true)
                .help("Output image"))
            .arg(Arg::new("quiet").long("quiet").takes_value(false).help("Don't write the JSON response to stdout"))
            .arg(Arg::new("response").long("response").takes_value(true).help("Write the JSON job result to file instead of stdout"))
            .arg(Arg::new("command").long("command").takes_value(true).required(true).help("w=200&h=200&mode=crop&format=png&rotate=90&flip=v - querystring style command"))
            .arg(Arg::new("bundle-to").long("bundle-to").takes_value(true).help("Copies the recipe and all dependencies into the given folder, simplifying it."))
            .arg(Arg::new("debug-package").long("debug-package").takes_value(true).help("Creates a debug package in the given folder so others can reproduce the behavior you are seeing"))

        );
    let matches = app.get_matches();
    if matches.is_present("capture-to"){
        let mut filtered_args = std::env::args().collect::<Vec<String>>();
        for ix in 0..filtered_args.len() {
            if filtered_args[ix] == "--capture-to"{
                //Remove this and the next arg
                filtered_args.remove(ix);
                if ix < filtered_args.len() - 1{
                    filtered_args.remove(ix);
                }
                break;
            }
        }
        filtered_args.remove(0); //Remove the tool executable itself

        let cap = hlp::process_capture::CaptureTo::create(matches.value_of("capture-to").unwrap(), None, filtered_args, artifact_source());
        cap.run();
        return cap.exit_code();
    }

    let build_triple = if let Some(m) = matches.subcommand_matches("v1/build") {
        let source = if m.is_present("demo") {
            cmd_build::JobSource::NamedDemo(m.value_of("demo").unwrap().to_owned())
        } else {
            cmd_build::JobSource::JsonFile(m.value_of("json").unwrap().to_owned())
        };
        Some((m, source, "v1/build"))
    }else if let Some(m) = matches.subcommand_matches("v1/querystring"){
        Some((m,cmd_build::JobSource::Ir4QueryString(m.value_of("command").unwrap().to_owned()), "v1/querystring"))
    }else{ None };

    if let Some((m, source, subcommand_name)) = build_triple{

        let builder =
            cmd_build::CmdBuild::parse(source, m.values_of_lossy("in"), m.values_of_lossy("out"))
                .build_maybe();
        if let Some(dir_str) = m.value_of("debug-package").and_then(|v| Some(v.to_owned())){
            builder.write_errors_maybe().unwrap();
            let dir = Path::new(&dir_str);
            builder.bundle_to(dir);
            let curdir = std::env::current_dir().unwrap();
            std::env::set_current_dir(&dir).unwrap();
            let cap = hlp::process_capture::CaptureTo::create("recipe", None, vec![subcommand_name.to_owned(), "--json".to_owned(), "recipe.json".to_owned()], artifact_source());
            cap.run();
            //Restore current directory
            std::env::set_current_dir(&curdir).unwrap();
            let archive_name = PathBuf::from(format!("{}.zip", &dir_str));
            hlp::filesystem::zip_directory_nonrecursive(&dir,&archive_name.as_path()).unwrap();
            return cap.exit_code();
        } else if let Some(dir) = m.value_of("bundle-to").and_then(|v| Some(v.to_owned())) {
                builder.write_errors_maybe().unwrap();
                let dir = Path::new(&dir);
                return builder.bundle_to(dir);
        } else {
            builder.write_response_maybe(m.value_of("response"), !m.is_present("quiet"))
                .expect("IO error writing JSON output file. Does the directory exist?");
            builder.write_errors_maybe().expect("Writing to stderr failed!");
            return builder.get_exit_code().unwrap();
        }

    }

    if let Some(matches) = matches.subcommand_matches("diagnose") {
        let m: &clap::ArgMatches = matches;

        if m.is_present("show-compilation-info") {
            println!("{}\n{}\n",
                     s::version::one_line_version(),
                     s::version::all_build_info_pairs());
            return 0;
        }

        if m.is_present("self-test") {
            return self_test::run(None);
        }
        if m.is_present("wait") {
            let mut input_buf = String::new();
            let input = std::io::stdin().read_line(&mut input_buf).expect("Failed to read from stdin. Are you using --wait in a non-interactive shell?");
            println!("{}", input);
            return 0;
        }
        if m.is_present("call-panic") {
            panic!("Panicking on command");
        }
    }
    if let Some(matches) = matches.subcommand_matches("examples") {
        let m: &clap::ArgMatches = matches;

        if m.is_present("generate") {
            self_test::export_examples(None);
            return 0;
        }
    }

    64
}

#[test]
fn test_file_macro_for_this_build(){
    assert!(file!().starts_with("imageflow_tool"))
}
<|endoftext|>