<commit_before>use message::Message;
use state::State;
use std::time::Duration;

const FIRST_OPENS_DEFAULT: bool = false;
const LAST_CLOSES_DEFAULT: bool = false;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Conditions {
    pub timeout: Duration,
    pub renew_timeout: Option<Duration>,
    pub first_opens: bool,
    pub last_closes: bool,
    pub max_size: Option<usize>,
    pub patterns: Vec<String>,
}

impl Conditions {
    fn new(timeout: Duration) -> Conditions {
        Conditions {
            timeout: timeout,
            renew_timeout: None,
            first_opens: FIRST_OPENS_DEFAULT,
            last_closes: LAST_CLOSES_DEFAULT,
            max_size: None,
            patterns: Vec::new(),
        }
    }

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens {
            message.ids().any(|x| x == self.patterns.first().unwrap())
        } else {
            true
        }
    }

    pub fn is_closing(&self, state: &State) -> bool {
        trace!("Conditions: shoud we close this context?");
        state.is_open() && self.is_closing_condition_met(state)
    }

    fn is_closing_condition_met(&self, state: &State) -> bool {
        self.is_max_size_reached(state) || self.is_closing_message(state) ||
        self.is_any_timer_expired(state)
    }

    fn is_max_size_reached(&self, state: &State) -> bool {
        self.max_size.map_or(false, |max_size| state.messages().len() >= max_size)
    }

    fn is_closing_message(&self, state: &State) -> bool {
        if self.last_closes {
            let last_message = state.messages().last().unwrap();
            last_message.ids().any(|x| x == self.patterns.last().unwrap())
        } else {
            false
        }
    }

    fn is_any_timer_expired(&self, state: &State) -> bool {
        self.is_timeout_expired(state) || self.is_renew_timeout_expired(state)
    }

    fn is_timeout_expired(&self, state: &State) -> bool {
        state.elapsed_time() >= self.timeout
    }

    fn is_renew_timeout_expired(&self, state: &State) -> bool {
        self.renew_timeout.map_or(false, |renew_timeout| {
            state.elapsed_time_since_last_message() >= renew_timeout
        })
    }
}

pub struct ConditionsBuilder {
    conditions: Conditions,
}

impl ConditionsBuilder {
    pub fn new(timeout: Duration) -> ConditionsBuilder {
        ConditionsBuilder { conditions: Conditions::new(timeout) }
    }

    pub fn renew_timeout(&mut self, timeout: Duration) -> &mut ConditionsBuilder {
        self.conditions.renew_timeout = Some(timeout);
        self
    }

    pub fn first_opens(&mut self, first_opens: bool) -> &mut ConditionsBuilder {
        self.conditions.first_opens = first_opens;
        self
    }

    pub fn last_closes(&mut self, last_closes: bool) -> &mut ConditionsBuilder {
        self.conditions.last_closes = last_closes;
        self
    }
    pub fn max_size(&mut self, max_size: usize) -> &mut ConditionsBuilder {
        self.conditions.max_size = Some(max_size);
        self
    }

    pub fn patterns(&mut self, patterns: Vec<String>) -> &mut ConditionsBuilder {
        self.conditions.patterns = patterns;
        self
    }

    pub fn build(&mut self) -> Conditions {
        self.conditions.clone()
    }
}

#[cfg(test)]
mod test {
    use serde_json::from_str;
    use super::Conditions;
    use std::rc::Rc;

    use message::MessageBuilder;
    use state::State;
    use super::ConditionsBuilder;
    use context::BaseContextBuilder;
    use uuid::Uuid;
    use std::time::Duration;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = Duration::from_millis(100);
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
        ];
        let condition = ConditionsBuilder::new(timeout)
                            .patterns(patterns)
                            .first_opens(true)
                            .build();
        let msg_which_should_not_be_ignored = MessageBuilder::new(&msg_id1, "message").build();
        let msg_which_should_be_ignored = MessageBuilder::new(&msg_id2, "message").build();
        assert_false!(condition.is_opening(&msg_which_should_be_ignored));
        assert_true!(condition.is_opening(&msg_which_should_not_be_ignored));
    }

    #[test]
    fn test_given_condition_when_a_closing_message_is_received_then_the_state_becomes_closed() {
        let timeout = Duration::from_millis(100);
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
            msg_id2.clone(),
        ];
        let mut state = State::new();
        let conditions = ConditionsBuilder::new(timeout)
                             .patterns(patterns)
                             .last_closes(true)
                             .build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        let msg_opening = Rc::new(MessageBuilder::new(&msg_id1, "message").build());
        let msg_closing = Rc::new(MessageBuilder::new(&msg_id2, "message").build());
        assert_false!(state.is_open());
        state.on_message(msg_opening, &context);
        assert_true!(state.is_open());
        state.on_message(msg_closing, &context);
        assert_false!(state.is_open());
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_only_the_required_ones_then_we_get_the_expected_result
        () {
        let json = r#"
        {
            "timeout": 100
        }
        "#;

        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok().expect("Failed to deserialize a Conditions \
                                                             struct with only a timeout field");
        assert_eq!(conditions.timeout, Duration::from_millis(100));
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_all_fields_then_we_get_the_expected_result() {
        let json = r#"
        {
            "timeout": 100,
            "renew_timeout": 50,
            "first_opens": true,
            "last_closes": false,
            "max_size": 42,
            "patterns": [
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "PATTERN_NAME"
            ]
        }
        "#;

        let expected_patterns = vec![
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "PATTERN_NAME".to_string(),
        ];
        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok()
                                               .expect("Failed to deserialize a Conditions struct");
        assert_eq!(conditions.timeout, Duration::from_millis(100));
        assert_eq!(conditions.renew_timeout, Some(Duration::from_millis(50)));
        assert_eq!(conditions.first_opens, true);
        assert_eq!(conditions.last_closes, false);
        assert_eq!(conditions.max_size, Some(42));
        assert_eq!(conditions.patterns, expected_patterns);
    }

    #[test]
    fn test_given_condition_when_there_are_no_patterns_then_any_message_can_open_the_context() {
        let timeout = Duration::from_millis(100);
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let condition = ConditionsBuilder::new(timeout).build();
        let msg = MessageBuilder::new(&msg_id, "message").build();
        assert_true!(condition.is_opening(&msg));
    }

    #[test]
    fn test_given_condition_when_first_opens_is_set_then_the_right_message_can_open_the_context
        () {
        let timeout = Duration::from_millis(100);
        let patterns = vec![
                "p1".to_string(),
                "p2".to_string(),
                "p3".to_string(),
        ];
        let uuid = "e4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let msg_id = "p1".to_string();
        let condition = ConditionsBuilder::new(timeout)
                            .patterns(patterns)
                            .first_opens(true)
                            .build();
        let msg = MessageBuilder::new(&uuid, "message").name(Some(&msg_id)).build();
        assert_true!(condition.is_opening(&msg));
    }

    #[test]
    fn test_given_conditions_when_last_closes_is_set_and_the_message_has_a_name_then_we_check_that_name
        () {
        let timeout = Duration::from_millis(100);
        let patterns = vec!["p1".to_string(), "p2".to_string()];
        let p1_uuid = "e4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let p2_uuid = "f4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let p1 = "p1".to_string();
        let p2 = "p2".to_string();
        let mut state = State::new();
        let conditions = ConditionsBuilder::new(timeout)
                             .patterns(patterns)
                             .first_opens(true)
                             .last_closes(true)
                             .build();
        let p1_msg = MessageBuilder::new(&p1_uuid, "message").name(Some(&p1)).build();
        let p2_msg = MessageBuilder::new(&p2_uuid, "message").name(Some(&p2)).build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        assert_false!(state.is_open());
        state.on_message(Rc::new(p1_msg), &context);
        state.on_message(Rc::new(p2_msg), &context);
        assert_false!(state.is_open());
    }
}

mod deser {
    use super::{Conditions, FIRST_OPENS_DEFAULT, LAST_CLOSES_DEFAULT};
    use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Visitor};
    use std::time::Duration;
    use duration::SerializableDuration;

    impl Deserialize for Conditions {
        fn deserialize<D>(deserializer: &mut D) -> Result<Conditions, D::Error>
            where D: Deserializer
        {
            deserializer.visit_struct("Conditions", &[], ConditionsVisitor)
        }
    }

    enum Field {
        Timeout,
        RenewTimeout,
        FirstOpens,
        LastCloses,
        MaxSize,
        Patterns,
    }

    impl Deserialize for Field {
        fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
            where D: Deserializer
        {
            struct FieldVisitor;

            impl Visitor for FieldVisitor {
                type Value = Field;

                fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                    where E: Error
                {
                    match value {
                        "timeout" => Ok(Field::Timeout),
                        "renew_timeout" => Ok(Field::RenewTimeout),
                        "first_opens" => Ok(Field::FirstOpens),
                        "last_closes" => Ok(Field::LastCloses),
                        "max_size" => Ok(Field::MaxSize),
                        "patterns" => Ok(Field::Patterns),
                        name @ _ => Err(Error::syntax(&format!("Unexpected field: {}", name))),
                    }
                }
            }

            deserializer.visit(FieldVisitor)
        }
    }

    struct ConditionsVisitor;

    impl Visitor for ConditionsVisitor {
        type Value = Conditions;

        fn visit_map<V>(&mut self, mut visitor: V) -> Result<Conditions, V::Error>
            where V: MapVisitor
        {
            let mut timeout: Option<SerializableDuration> = None;
            let mut renew_timeout: Option<SerializableDuration> = None;
            let mut first_opens = FIRST_OPENS_DEFAULT;
            let mut last_closes = LAST_CLOSES_DEFAULT;
            let mut max_size = None;
            let mut patterns = None;

            while let Some(field) = try!(visitor.visit_key()) {
                match field {
                    Field::Timeout => timeout = Some(try!(visitor.visit_value())),
                    Field::RenewTimeout => renew_timeout = Some(try!(visitor.visit_value())),
                    Field::FirstOpens => first_opens = try!(visitor.visit_value()),
                    Field::LastCloses => last_closes = try!(visitor.visit_value()),
                    Field::MaxSize => max_size = Some(try!(visitor.visit_value())),
                    Field::Patterns => patterns = Some(try!(visitor.visit_value())),
                }
            }

            let timeout: Duration = match timeout {
                Some(timeout) => timeout.0,
                None => return visitor.missing_field("timeout"),
            };

            let renew_timeout = renew_timeout.map(|timeout| timeout.0);

            try!(visitor.end());

            Ok(Conditions {
                timeout: timeout,
                renew_timeout: renew_timeout,
                first_opens: first_opens,
                last_closes: last_closes,
                max_size: max_size,
                patterns: patterns.unwrap_or(Vec::new()),
            })
        }
    }
}
<commit_msg>Conditions: ensure first_opens doesn't cause panic<commit_after>use message::Message;
use state::State;
use std::time::Duration;

const FIRST_OPENS_DEFAULT: bool = false;
const LAST_CLOSES_DEFAULT: bool = false;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Conditions {
    pub timeout: Duration,
    pub renew_timeout: Option<Duration>,
    pub first_opens: bool,
    pub last_closes: bool,
    pub max_size: Option<usize>,
    pub patterns: Vec<String>,
}

impl Conditions {
    fn new(timeout: Duration) -> Conditions {
        Conditions {
            timeout: timeout,
            renew_timeout: None,
            first_opens: FIRST_OPENS_DEFAULT,
            last_closes: LAST_CLOSES_DEFAULT,
            max_size: None,
            patterns: Vec::new(),
        }
    }

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens {
            message.ids().any(|x| x == self.patterns.first().unwrap())
        } else {
            true
        }
    }

    pub fn is_closing(&self, state: &State) -> bool {
        trace!("Conditions: shoud we close this context?");
        state.is_open() && self.is_closing_condition_met(state)
    }

    fn is_closing_condition_met(&self, state: &State) -> bool {
        self.is_max_size_reached(state) || self.is_closing_message(state) ||
        self.is_any_timer_expired(state)
    }

    fn is_max_size_reached(&self, state: &State) -> bool {
        self.max_size.map_or(false, |max_size| state.messages().len() >= max_size)
    }

    fn is_closing_message(&self, state: &State) -> bool {
        if self.last_closes {
            let last_message = state.messages().last().unwrap();
            last_message.ids().any(|x| x == self.patterns.last().unwrap())
        } else {
            false
        }
    }

    fn is_any_timer_expired(&self, state: &State) -> bool {
        self.is_timeout_expired(state) || self.is_renew_timeout_expired(state)
    }

    fn is_timeout_expired(&self, state: &State) -> bool {
        state.elapsed_time() >= self.timeout
    }

    fn is_renew_timeout_expired(&self, state: &State) -> bool {
        self.renew_timeout.map_or(false, |renew_timeout| {
            state.elapsed_time_since_last_message() >= renew_timeout
        })
    }
}

pub struct ConditionsBuilder {
    conditions: Conditions,
}

impl ConditionsBuilder {
    pub fn new(timeout: Duration) -> ConditionsBuilder {
        ConditionsBuilder { conditions: Conditions::new(timeout) }
    }

    pub fn renew_timeout(&mut self, timeout: Duration) -> &mut ConditionsBuilder {
        self.conditions.renew_timeout = Some(timeout);
        self
    }

    pub fn first_opens(&mut self, first_opens: bool) -> &mut ConditionsBuilder {
        self.conditions.first_opens = first_opens;
        self
    }

    pub fn last_closes(&mut self, last_closes: bool) -> &mut ConditionsBuilder {
        self.conditions.last_closes = last_closes;
        self
    }
    pub fn max_size(&mut self, max_size: usize) -> &mut ConditionsBuilder {
        self.conditions.max_size = Some(max_size);
        self
    }

    pub fn patterns(&mut self, patterns: Vec<String>) -> &mut ConditionsBuilder {
        self.conditions.patterns = patterns;
        self
    }

    pub fn build(&mut self) -> Conditions {
        self.conditions.clone()
    }
}

#[cfg(test)]
mod test {
    use serde_json::from_str;
    use super::Conditions;
    use std::rc::Rc;

    use message::MessageBuilder;
    use state::State;
    use super::ConditionsBuilder;
    use context::BaseContextBuilder;
    use uuid::Uuid;
    use std::time::Duration;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = Duration::from_millis(100);
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
        ];
        let condition = ConditionsBuilder::new(timeout)
                            .patterns(patterns)
                            .first_opens(true)
                            .build();
        let msg_which_should_not_be_ignored = MessageBuilder::new(&msg_id1, "message").build();
        let msg_which_should_be_ignored = MessageBuilder::new(&msg_id2, "message").build();
        assert_false!(condition.is_opening(&msg_which_should_be_ignored));
        assert_true!(condition.is_opening(&msg_which_should_not_be_ignored));
    }

    #[test]
    fn test_given_condition_when_a_closing_message_is_received_then_the_state_becomes_closed() {
        let timeout = Duration::from_millis(100);
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
            msg_id2.clone(),
        ];
        let mut state = State::new();
        let conditions = ConditionsBuilder::new(timeout)
                             .patterns(patterns)
                             .last_closes(true)
                             .build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        let msg_opening = Rc::new(MessageBuilder::new(&msg_id1, "message").build());
        let msg_closing = Rc::new(MessageBuilder::new(&msg_id2, "message").build());
        assert_false!(state.is_open());
        state.on_message(msg_opening, &context);
        assert_true!(state.is_open());
        state.on_message(msg_closing, &context);
        assert_false!(state.is_open());
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_only_the_required_ones_then_we_get_the_expected_result
        () {
        let json = r#"
        {
            "timeout": 100
        }
        "#;

        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok().expect("Failed to deserialize a Conditions \
                                                             struct with only a timeout field");
        assert_eq!(conditions.timeout, Duration::from_millis(100));
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_all_fields_then_we_get_the_expected_result() {
        let json = r#"
        {
            "timeout": 100,
            "renew_timeout": 50,
            "first_opens": true,
            "last_closes": false,
            "max_size": 42,
            "patterns": [
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "PATTERN_NAME"
            ]
        }
        "#;

        let expected_patterns = vec![
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "PATTERN_NAME".to_string(),
        ];
        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok()
                                               .expect("Failed to deserialize a Conditions struct");
        assert_eq!(conditions.timeout, Duration::from_millis(100));
        assert_eq!(conditions.renew_timeout, Some(Duration::from_millis(50)));
        assert_eq!(conditions.first_opens, true);
        assert_eq!(conditions.last_closes, false);
        assert_eq!(conditions.max_size, Some(42));
        assert_eq!(conditions.patterns, expected_patterns);
    }

    #[test]
    fn test_given_condition_when_there_are_no_patterns_then_any_message_can_open_the_context() {
        let timeout = Duration::from_millis(100);
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let condition = ConditionsBuilder::new(timeout).build();
        let msg = MessageBuilder::new(&msg_id, "message").build();
        assert_true!(condition.is_opening(&msg));
    }

    #[test]
    fn test_given_condition_when_first_opens_is_set_then_the_right_message_can_open_the_context
        () {
        let timeout = Duration::from_millis(100);
        let patterns = vec![
                "p1".to_string(),
                "p2".to_string(),
                "p3".to_string(),
        ];
        let uuid = "e4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let msg_id = "p1".to_string();
        let condition = ConditionsBuilder::new(timeout)
                            .patterns(patterns)
                            .first_opens(true)
                            .build();
        let msg = MessageBuilder::new(&uuid, "message").name(Some(&msg_id)).build();
        assert_true!(condition.is_opening(&msg));
    }

    #[test]
    fn test_given_conditions_when_last_closes_is_set_and_the_message_has_a_name_then_we_check_that_name
        () {
        let timeout = Duration::from_millis(100);
        let patterns = vec!["p1".to_string(), "p2".to_string()];
        let p1_uuid = "e4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let p2_uuid = "f4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let p1 = "p1".to_string();
        let p2 = "p2".to_string();
        let mut state = State::new();
        let conditions = ConditionsBuilder::new(timeout)
                             .patterns(patterns)
                             .first_opens(true)
                             .last_closes(true)
                             .build();
        let p1_msg = MessageBuilder::new(&p1_uuid, "message").name(Some(&p1)).build();
        let p2_msg = MessageBuilder::new(&p2_uuid, "message").name(Some(&p2)).build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        assert_false!(state.is_open());
        state.on_message(Rc::new(p1_msg), &context);
        state.on_message(Rc::new(p2_msg), &context);
        assert_false!(state.is_open());
    }

    #[test]
    fn test_given_condition_when_first_opens_is_set_but_there_are_no_patterns_then_we_do_not_panic() {
        let msg = MessageBuilder::new("e4f3f8b2-3135-4916-a5ea-621a754dab0d", "message")
                                 .name(Some("p1"))
                                 .build();
        let conditions = ConditionsBuilder::new(Duration::from_millis(100))
                             .patterns(Vec::new())
                             .first_opens(true)
                             .build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        let mut state = State::new();
        state.on_message(Rc::new(msg), &context);
    }
}

mod deser {
    use super::{Conditions, FIRST_OPENS_DEFAULT, LAST_CLOSES_DEFAULT};
    use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Visitor};
    use std::time::Duration;
    use duration::SerializableDuration;

    impl Deserialize for Conditions {
        fn deserialize<D>(deserializer: &mut D) -> Result<Conditions, D::Error>
            where D: Deserializer
        {
            deserializer.visit_struct("Conditions", &[], ConditionsVisitor)
        }
    }

    enum Field {
        Timeout,
        RenewTimeout,
        FirstOpens,
        LastCloses,
        MaxSize,
        Patterns,
    }

    impl Deserialize for Field {
        fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
            where D: Deserializer
        {
            struct FieldVisitor;

            impl Visitor for FieldVisitor {
                type Value = Field;

                fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                    where E: Error
                {
                    match value {
                        "timeout" => Ok(Field::Timeout),
                        "renew_timeout" => Ok(Field::RenewTimeout),
                        "first_opens" => Ok(Field::FirstOpens),
                        "last_closes" => Ok(Field::LastCloses),
                        "max_size" => Ok(Field::MaxSize),
                        "patterns" => Ok(Field::Patterns),
                        name @ _ => Err(Error::syntax(&format!("Unexpected field: {}", name))),
                    }
                }
            }

            deserializer.visit(FieldVisitor)
        }
    }

    struct ConditionsVisitor;

    impl Visitor for ConditionsVisitor {
        type Value = Conditions;

        fn visit_map<V>(&mut self, mut visitor: V) -> Result<Conditions, V::Error>
            where V: MapVisitor
        {
            let mut timeout: Option<SerializableDuration> = None;
            let mut renew_timeout: Option<SerializableDuration> = None;
            let mut first_opens = FIRST_OPENS_DEFAULT;
            let mut last_closes = LAST_CLOSES_DEFAULT;
            let mut max_size = None;
            let mut patterns = None;

            while let Some(field) = try!(visitor.visit_key()) {
                match field {
                    Field::Timeout => timeout = Some(try!(visitor.visit_value())),
                    Field::RenewTimeout => renew_timeout = Some(try!(visitor.visit_value())),
                    Field::FirstOpens => first_opens = try!(visitor.visit_value()),
                    Field::LastCloses => last_closes = try!(visitor.visit_value()),
                    Field::MaxSize => max_size = Some(try!(visitor.visit_value())),
                    Field::Patterns => patterns = Some(try!(visitor.visit_value())),
                }
            }

            let timeout: Duration = match timeout {
                Some(timeout) => timeout.0,
                None => return visitor.missing_field("timeout"),
            };

            let renew_timeout = renew_timeout.map(|timeout| timeout.0);

            try!(visitor.end());

            Ok(Conditions {
                timeout: timeout,
                renew_timeout: renew_timeout,
                first_opens: first_opens,
                last_closes: last_closes,
                max_size: max_size,
                patterns: patterns.unwrap_or(Vec::new()),
            })
        }
    }
}
<|endoftext|>


<commit_before>//! Conversion between units

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

use ::si_units::*;

/// This macro implements *From* for the given units.
/// It either uses a factor or a closure to calculate the conversion
///
/// #Example:
///
/// ```
/// convert_unit!(Second, Minute, 60.0);
/// ```
#[macro_export] macro_rules! convert_unit {
    // Convert from $i1 to $i2 using closure $e1
    // Convert from $i2 to $i1 using closure $e2
    ($i1:ident, $i2:ident, $e1:expr, $e2:expr) => {
        impl From<$i1> for $i2 {
            fn from($i1(value): $i1) -> Self {
                $i2($e1(value))
            }
        }

        impl From<$i2> for $i1 {
            fn from($i2(value): $i2) -> Self {
                $i1($e2(value))
            }
        }
    };

    // Convert from $i1 to $i2 using factor $i3
    // $i2 = $i1 * $i3
    ($i1:ident, $i2:ident, $i3:ident) => {
        impl From<$i1> for $i2 {
            fn from($i1(value): $i1) -> Self {
                $i2(value * $i3)
            }
        }

        impl From<$i2> for $i1 {
            fn from($i2(value): $i2) -> Self {
                $i1(value / $i3)
            }
        }
    };

}

// TODO: move all constants to https://github.com/willi-kappler/natural_constants

const METER_TO_FOOT: f64 = 3.28084;
const METER_TO_YARD: f64 = 1.09361;
const METER_TO_MILE: f64 = 0.000621371;

const METER_TO_KILOMETER: f64 = 1.0e-3;
const METER_TO_MILIMETER: f64 = 1.0e+3;
const METER_TO_MICROMETER: f64 = 1.0e+6;
const METER_TO_NANOMETER: f64 = 1.0e+9;
const METER_TO_ASTRONOMICALUNIT: f64 = 1.0 / 149597870700.0;
const METER_TO_LIGHTYEAR: f64 =  1.0 / 9.4607e15;
const METER_TO_PARSEC: f64 = 1.0 / 3.08567758149137e16;

const SECOND_TO_MINUTE: f64 = 60.0;
const SECOND_TO_HOUR: f64 = 60.0 * 60.0;
const SECOND_TO_DAY: f64 = 60.0 * 60.0 * 24.0;
const SECOND_TO_WEEK: f64 = SECOND_TO_DAY * 7.0;
const SECOND_TO_MONTH: f64 = SECOND_TO_DAY * 30.0; // simple
const SECOND_TO_MONTH_AVG: f64 = SECOND_TO_DAY * 30.42; // average
const SECOND_TO_MONTH_AVG_LEAP: f64 = SECOND_TO_DAY * 30.50; // average leap year
const SECOND_TO_MONTH_SOLAR: f64 = SECOND_TO_DAY * 30.44; // solar calendar
const SECOND_TO_MONTH_LUNAR: f64 = SECOND_TO_DAY * 29.53; // lunar month

const SECOND_TO_YEAR: f64 = SECOND_TO_DAY * 365.25; // on average
const SECOND_TO_MIL_YEAR: f64 = SECOND_TO_YEAR * 1.0e6;

const DEGC_TO_KELVIN: f64 = 273.15;

init_unit!(Foot);
init_unit!(Yard);
init_unit!(Mile);

convert_unit!(Meter, Foot, METER_TO_FOOT);
convert_unit!(Meter, Yard, METER_TO_YARD);
convert_unit!(Meter, Mile, METER_TO_MILE);

init_unit!(Kilometer);
init_unit!(Milimeter);
init_unit!(Micrometer);
init_unit!(Nanometer);

convert_unit!(Meter, Kilometer, METER_TO_KILOMETER);
convert_unit!(Meter, Milimeter, METER_TO_MILIMETER);
convert_unit!(Meter, Micrometer, METER_TO_MICROMETER);
convert_unit!(Meter, Nanometer, METER_TO_NANOMETER);

init_unit!(AstronomicalUnit);
init_unit!(LightYear);
init_unit!(Parsec);

convert_unit!(Meter, AstronomicalUnit, METER_TO_ASTRONOMICALUNIT);
convert_unit!(Meter, LightYear, METER_TO_LIGHTYEAR);
convert_unit!(Meter, Parsec, METER_TO_PARSEC);

init_unit!(Minute);
init_unit!(Hour);
init_unit!(Day);
init_unit!(Week);
init_unit!(Month);
init_unit!(Year);
init_unit!(MilYear);

convert_unit!(Second, Minute, SECOND_TO_MINUTE);
convert_unit!(Second, Hour, SECOND_TO_HOUR);
convert_unit!(Second, Day, SECOND_TO_DAY);
convert_unit!(Second, Week, SECOND_TO_WEEK);
convert_unit!(Second, Month, SECOND_TO_MONTH);
convert_unit!(Second, Year, SECOND_TO_YEAR);
convert_unit!(Second, MilYear, SECOND_TO_MIL_YEAR);

init_unit!(Fahrenheit);

convert_unit!(DegC, Kelvin, |value| {value + DEGC_TO_KELVIN}, |value| {value - DEGC_TO_KELVIN});
convert_unit!(DegC, Fahrenheit, |value| {(value * 1.8) + 32.0}, |value| {(value - 32.0) / 1.8});
<commit_msg>fix doc test<commit_after>//! Conversion between units

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

use ::si_units::*;

/// This macro implements *From* for the given units.
/// It either uses a factor or a closure to calculate the conversion
///
/// # Example:
///
/// ```
/// # #[macro_use] extern crate simple_units;
/// # use std::ops::Add;
/// # use std::ops::Sub;
/// # use std::ops::Mul;
/// # use std::ops::Div;
/// # use std::cmp::PartialEq;
/// # fn main() {
/// const factor: f64 = 60.0;
/// init_unit!(Second);
/// init_unit!(Minute);
/// convert_unit!(Second, Minute, factor);
/// # }
/// ```
#[macro_export] macro_rules! convert_unit {
    // Convert from $i1 to $i2 using closure $e1
    // Convert from $i2 to $i1 using closure $e2
    ($i1:ident, $i2:ident, $e1:expr, $e2:expr) => {
        impl From<$i1> for $i2 {
            fn from($i1(value): $i1) -> Self {
                $i2($e1(value))
            }
        }

        impl From<$i2> for $i1 {
            fn from($i2(value): $i2) -> Self {
                $i1($e2(value))
            }
        }
    };

    // Convert from $i1 to $i2 using factor $i3
    // $i2 = $i1 * $i3
    ($i1:ident, $i2:ident, $i3:ident) => {
        impl From<$i1> for $i2 {
            fn from($i1(value): $i1) -> Self {
                $i2(value * $i3)
            }
        }

        impl From<$i2> for $i1 {
            fn from($i2(value): $i2) -> Self {
                $i1(value / $i3)
            }
        }
    };

}

// TODO: move all constants to https://github.com/willi-kappler/natural_constants

const METER_TO_FOOT: f64 = 3.28084;
const METER_TO_YARD: f64 = 1.09361;
const METER_TO_MILE: f64 = 0.000621371;

const METER_TO_KILOMETER: f64 = 1.0e-3;
const METER_TO_MILIMETER: f64 = 1.0e+3;
const METER_TO_MICROMETER: f64 = 1.0e+6;
const METER_TO_NANOMETER: f64 = 1.0e+9;
const METER_TO_ASTRONOMICALUNIT: f64 = 1.0 / 149597870700.0;
const METER_TO_LIGHTYEAR: f64 =  1.0 / 9.4607e15;
const METER_TO_PARSEC: f64 = 1.0 / 3.08567758149137e16;

const SECOND_TO_MINUTE: f64 = 60.0;
const SECOND_TO_HOUR: f64 = 60.0 * 60.0;
const SECOND_TO_DAY: f64 = 60.0 * 60.0 * 24.0;
const SECOND_TO_WEEK: f64 = SECOND_TO_DAY * 7.0;
const SECOND_TO_MONTH: f64 = SECOND_TO_DAY * 30.0; // simple
const SECOND_TO_MONTH_AVG: f64 = SECOND_TO_DAY * 30.42; // average
const SECOND_TO_MONTH_AVG_LEAP: f64 = SECOND_TO_DAY * 30.50; // average leap year
const SECOND_TO_MONTH_SOLAR: f64 = SECOND_TO_DAY * 30.44; // solar calendar
const SECOND_TO_MONTH_LUNAR: f64 = SECOND_TO_DAY * 29.53; // lunar month

const SECOND_TO_YEAR: f64 = SECOND_TO_DAY * 365.25; // on average
const SECOND_TO_MIL_YEAR: f64 = SECOND_TO_YEAR * 1.0e6;

const DEGC_TO_KELVIN: f64 = 273.15;

init_unit!(Foot);
init_unit!(Yard);
init_unit!(Mile);

convert_unit!(Meter, Foot, METER_TO_FOOT);
convert_unit!(Meter, Yard, METER_TO_YARD);
convert_unit!(Meter, Mile, METER_TO_MILE);

init_unit!(Kilometer);
init_unit!(Milimeter);
init_unit!(Micrometer);
init_unit!(Nanometer);

convert_unit!(Meter, Kilometer, METER_TO_KILOMETER);
convert_unit!(Meter, Milimeter, METER_TO_MILIMETER);
convert_unit!(Meter, Micrometer, METER_TO_MICROMETER);
convert_unit!(Meter, Nanometer, METER_TO_NANOMETER);

init_unit!(AstronomicalUnit);
init_unit!(LightYear);
init_unit!(Parsec);

convert_unit!(Meter, AstronomicalUnit, METER_TO_ASTRONOMICALUNIT);
convert_unit!(Meter, LightYear, METER_TO_LIGHTYEAR);
convert_unit!(Meter, Parsec, METER_TO_PARSEC);

init_unit!(Minute);
init_unit!(Hour);
init_unit!(Day);
init_unit!(Week);
init_unit!(Month);
init_unit!(Year);
init_unit!(MilYear);

convert_unit!(Second, Minute, SECOND_TO_MINUTE);
convert_unit!(Second, Hour, SECOND_TO_HOUR);
convert_unit!(Second, Day, SECOND_TO_DAY);
convert_unit!(Second, Week, SECOND_TO_WEEK);
convert_unit!(Second, Month, SECOND_TO_MONTH);
convert_unit!(Second, Year, SECOND_TO_YEAR);
convert_unit!(Second, MilYear, SECOND_TO_MIL_YEAR);

init_unit!(Fahrenheit);

convert_unit!(DegC, Kelvin, |value| {value + DEGC_TO_KELVIN}, |value| {value - DEGC_TO_KELVIN});
convert_unit!(DegC, Fahrenheit, |value| {(value * 1.8) + 32.0}, |value| {(value - 32.0) / 1.8});
<|endoftext|>


<commit_before>//! Amazon MWS Fulfillment Inbound Shipment API - Version 2010-10-01
//!
//! [Documentation](http://docs.developer.amazonservices.com/en_CA/fba_inbound/FBAInbound_Overview.html)

use chrono::{DateTime, UTC};
use client::{Client, Method, Response};
use xmlhelper::decode;
use super::types::ToIso8601;

mod types;
pub use self::types::*;

error_chain! {
  links {
    Client(super::client::Error, super::client::ErrorKind);
    Decode(decode::Error, decode::ErrorKind);
  }
}

static PATH: &'static str = "FulfillmentInboundShipment/2010-10-01";
static VERSION: &'static str = "2010-10-01";

/// Parameters for `ListInboundShipments`
#[derive(Debug, Default)]
pub struct ListInboundShipmentsParameters {
  pub shipment_status_list: Vec<ShipmentStatus>,
  pub shipment_id_list: Vec<String>,
  pub last_updated_after: Option<DateTime<UTC>>,
  pub last_updated_before: Option<DateTime<UTC>>,
}

impl Into<Vec<(String, String)>> for ListInboundShipmentsParameters {
  fn into(self) -> Vec<(String, String)> {
    let mut result = vec![];
    for (i, s) in self.shipment_status_list.into_iter().enumerate() {
      result.push((format!("ShipmentStatusList.member.{}", i + 1), s.to_string()));
    }

    for (i, id) in self.shipment_id_list.into_iter().enumerate() {
      result.push((format!("ShipmentIdList.member.{}", i + 1), id.to_string()));
    }

    if let Some(date) = self.last_updated_after {
      result.push(("LastUpdatedAfter".to_string(), date.to_iso8601()));
    }

    if let Some(date) = self.last_updated_before {
      result.push(("LastUpdatedBefore".to_string(), date.to_iso8601()));
    }

    result
  }
}

#[derive(Debug, Default, PartialEq)]
pub struct ListInboundShipmentsResponse {
  pub request_id: String,
  pub shipment_data: Vec<InboundShipmentInfo>,
  pub next_token: Option<String>,
}

impl<S: decode::XmlEventStream> decode::FromXMLStream<S> for ListInboundShipmentsResponse {
  fn from_xml(s: &mut S) -> decode::Result<ListInboundShipmentsResponse> {
    use self::decode::{start_document, element, fold_elements, characters};
    start_document(s)?;
    element(s, vec!["ListInboundShipmentsResponse", "ListInboundShipmentsByNextTokenResponse"], |s| {
      fold_elements(s, ListInboundShipmentsResponse::default(), |s, response| {
        match s.local_name() {
          "ListInboundShipmentsResult" | "ListInboundShipmentsByNextTokenResult" => {
            fold_elements(s, (), |s, _| {
              match s.local_name() {
                "ShipmentData" => {
                  response.shipment_data = fold_elements(s, vec![], |s, list| {
                    list.push(InboundShipmentInfo::from_xml(s)?);
                    Ok(())
                  })?;
                },
                "NextToken" => {
                  response.next_token = Some(characters(s)?);
                },
                _ => {},
              }
              Ok(())
            })
          },
          "ResponseMetadata" => {
            response.request_id = element(s, "RequestId", |s| {
              characters(s)
            })?;
            Ok(())
          },
          _ => { Ok(()) }
        }
      })
    })
  }
}

/// Returns a list of inbound shipments based on criteria that you specify.
///
/// [Documentation](http://docs.developer.amazonservices.com/en_CA/fba_inbound/FBAInbound_ListInboundShipments.html)
#[allow(non_snake_case)]
pub fn ListInboundShipments(client: &Client, parameters: ListInboundShipmentsParameters) -> Result<Response<ListInboundShipmentsResponse>> {
  client.request_xml(Method::Post, PATH, VERSION, "ListInboundShipments", parameters).map_err(|err| err.into())
}

/// Returns the next page of inbound shipments using the NextToken parameter.
///
/// [Documentation](http://docs.developer.amazonservices.com/en_CA/fba_inbound/FBAInbound_ListInboundShipmentsByNextToken.html)
#[allow(non_snake_case)]
pub fn ListInboundShipmentsByNextToken(client: &Client, next_token: String) -> Result<Response<ListInboundShipmentsResponse>> {
  let params = vec![
    ("NextToken".to_string(), next_token)
  ];
  client.request_xml(Method::Post, PATH, VERSION, "ListInboundShipmentsByNextToken", params).map_err(|err| err.into())
}

/// Parameters for `ListInboundShipments`
#[derive(Debug, Default)]
pub struct ListInboundShipmentItemsParameters {
  pub shipment_id: String,
  pub last_updated_after: Option<DateTime<UTC>>,
  pub last_updated_before: Option<DateTime<UTC>>,
}

impl Into<Vec<(String, String)>> for ListInboundShipmentItemsParameters {
  fn into(self) -> Vec<(String, String)> {
    let mut result = vec![
      ("ShipmentId".to_owned(), self.shipment_id)
    ];

    if let Some(date) = self.last_updated_after {
      result.push(("LastUpdatedAfter".to_string(), date.to_iso8601()));
    }

    if let Some(date) = self.last_updated_before {
      result.push(("LastUpdatedBefore".to_string(), date.to_iso8601()));
    }

    result
  }
}

#[derive(Debug, Default, PartialEq)]
pub struct ListInboundShipmentItemsResponse {
  pub request_id: String,
  pub item_data: Vec<InboundShipmentItem>,
  pub next_token: Option<String>,
}

impl<S: decode::XmlEventStream> decode::FromXMLStream<S> for ListInboundShipmentItemsResponse {
  fn from_xml(s: &mut S) -> decode::Result<ListInboundShipmentItemsResponse> {
    use self::decode::{start_document, element, fold_elements, characters};
    start_document(s)?;
    element(s, vec!["ListInboundShipmentItemsResponse", "ListInboundShipmentItemsByNextTokenResponse"], |s| {
      fold_elements(s, ListInboundShipmentItemsResponse::default(), |s, response| {
        match s.local_name() {
          "ListInboundShipmentItemsResult" | "ListInboundShipmentItemsByNextTokenResult" => {
            fold_elements(s, (), |s, _| {
              match s.local_name() {
                "ItemData" => {
                  response.item_data = fold_elements(s, vec![], |s, list| {
                    list.push(InboundShipmentItem::from_xml(s)?);
                    Ok(())
                  })?;
                },
                "NextToken" => {
                  response.next_token = Some(characters(s)?);
                },
                _ => {},
              }
              Ok(())
            })
          },
          "ResponseMetadata" => {
            response.request_id = element(s, "RequestId", |s| {
              characters(s)
            })?;
            Ok(())
          },
          _ => { Ok(()) }
        }
      })
    })
  }
}

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

  #[test]
  fn test_decode_list_inbound_shipments_response() {
    test_decode!(ListInboundShipmentsResponse, r#"
    <ListInboundShipmentsResponse xmlns="http://mws.amazonaws.com/FulfillmentInboundShipment/2010-10-01/">
      <ListInboundShipmentsResult>
        <ShipmentData>
          <member>
            <DestinationFulfillmentCenterId>MDW2</DestinationFulfillmentCenterId>
            <LabelPrepType>NO_LABEL</LabelPrepType>
            <ShipFromAddress>
              <City>Fort Worth</City>
              <CountryCode>US</CountryCode>
              <PostalCode>76104</PostalCode>
              <Name>RPD LTD</Name>
              <AddressLine1>428 Hemphill St</AddressLine1>
              <StateOrProvinceCode>TX</StateOrProvinceCode>
            </ShipFromAddress>
            <ShipmentId>FBA4FWJMVV</ShipmentId>
            <AreCasesRequired>true</AreCasesRequired>
            <ShipmentName>FBA (2/19/17 9:39 PM) - 1</ShipmentName>
            <BoxContentsSource>INTERACTIVE</BoxContentsSource>
            <ShipmentStatus>CLOSED</ShipmentStatus>
          </member>
        </ShipmentData>
      </ListInboundShipmentsResult>
      <ResponseMetadata>
        <RequestId>04c87e79-f747-4da9-984f-5bc1f0b875e6</RequestId>
      </ResponseMetadata>
    </ListInboundShipmentsResponse>
    "#, ListInboundShipmentsResponse {
      next_token: None,
      request_id: "04c87e79-f747-4da9-984f-5bc1f0b875e6".to_owned(),
      shipment_data: vec![
        InboundShipmentInfo {
          DestinationFulfillmentCenterId: "MDW2".to_owned(),
          LabelPrepType: Some(LabelPrepType::NO_LABEL),
          ShipFromAddress: Address {
            City: "Fort Worth".to_owned(),
            CountryCode: "US".to_owned(),
            PostalCode: "76104".to_owned(),
            Name: "RPD LTD".to_owned(),
            AddressLine1: "428 Hemphill St".to_owned(),
            AddressLine2: "".to_owned(),
            StateOrProvinceCode: "TX".to_owned(),
            DistrictOrCounty: "".to_owned(),
          },
          ShipmentId: "FBA4FWJMVV".to_owned(),
          AreCasesRequired: true,
          ShipmentName: "FBA (2/19/17 9:39 PM) - 1".to_owned(),
          BoxContentsSource: Some(BoxContentsSource::INTERACTIVE),
          ShipmentStatus: ShipmentStatus::CLOSED,
          ConfirmedNeedByDate: "".to_owned(),
          EstimatedBoxContentsFee: None,
        }
      ],
    });
  }

  #[test]
  fn test_decode_list_inbound_shipment_items_response() {
    test_decode!(ListInboundShipmentItemsResponse, r#"
    <ListInboundShipmentItemsResponse xmlns="http://mws.amazonaws.com/FulfillmentInboundShipment/2010-10-01/">
      <ListInboundShipmentItemsResult>
        <ItemData>
          <member>
            <QuantityShipped>60</QuantityShipped>
            <ShipmentId>FBA3T68MQL</ShipmentId>
            <PrepDetailsList>
              <PrepDetails/>
            </PrepDetailsList>
            <FulfillmentNetworkSKU>B016P9HJIA</FulfillmentNetworkSKU>
            <SellerSKU>edifier-r1280t-fba</SellerSKU>
            <QuantityReceived>50</QuantityReceived>
            <QuantityInCase>2</QuantityInCase>
          </member>
        </ItemData>
      </ListInboundShipmentItemsResult>
      <ResponseMetadata>
        <RequestId>70a60f01-d0df-4a29-b093-e1cb53bd8fc2</RequestId>
      </ResponseMetadata>
    </ListInboundShipmentItemsResponse>
    "#, ListInboundShipmentItemsResponse {
      next_token: None,
      request_id: "70a60f01-d0df-4a29-b093-e1cb53bd8fc2".to_owned(),
      item_data: vec![
        InboundShipmentItem {
          ShipmentId: "FBA3T68MQL".to_owned(),
          SellerSKU: "edifier-r1280t-fba".to_owned(),
          QuantityShipped: 60,
          QuantityInCase: Some(2),
          QuantityReceived: Some(50),
          FulfillmentNetworkSKU: "B016P9HJIA".to_owned(),
        }
      ],
    });
  }

}<commit_msg>Fix FulfillmentInboundShipment api path<commit_after>//! Amazon MWS Fulfillment Inbound Shipment API - Version 2010-10-01
//!
//! [Documentation](http://docs.developer.amazonservices.com/en_CA/fba_inbound/FBAInbound_Overview.html)

use chrono::{DateTime, UTC};
use client::{Client, Method, Response};
use xmlhelper::decode;
use super::types::ToIso8601;

mod types;
pub use self::types::*;

error_chain! {
  links {
    Client(super::client::Error, super::client::ErrorKind);
    Decode(decode::Error, decode::ErrorKind);
  }
}

static PATH: &'static str = "/FulfillmentInboundShipment/2010-10-01";
static VERSION: &'static str = "2010-10-01";

/// Parameters for `ListInboundShipments`
#[derive(Debug, Default)]
pub struct ListInboundShipmentsParameters {
  pub shipment_status_list: Vec<ShipmentStatus>,
  pub shipment_id_list: Vec<String>,
  pub last_updated_after: Option<DateTime<UTC>>,
  pub last_updated_before: Option<DateTime<UTC>>,
}

impl Into<Vec<(String, String)>> for ListInboundShipmentsParameters {
  fn into(self) -> Vec<(String, String)> {
    let mut result = vec![];
    for (i, s) in self.shipment_status_list.into_iter().enumerate() {
      result.push((format!("ShipmentStatusList.member.{}", i + 1), s.to_string()));
    }

    for (i, id) in self.shipment_id_list.into_iter().enumerate() {
      result.push((format!("ShipmentIdList.member.{}", i + 1), id.to_string()));
    }

    if let Some(date) = self.last_updated_after {
      result.push(("LastUpdatedAfter".to_string(), date.to_iso8601()));
    }

    if let Some(date) = self.last_updated_before {
      result.push(("LastUpdatedBefore".to_string(), date.to_iso8601()));
    }

    result
  }
}

#[derive(Debug, Default, PartialEq)]
pub struct ListInboundShipmentsResponse {
  pub request_id: String,
  pub shipment_data: Vec<InboundShipmentInfo>,
  pub next_token: Option<String>,
}

impl<S: decode::XmlEventStream> decode::FromXMLStream<S> for ListInboundShipmentsResponse {
  fn from_xml(s: &mut S) -> decode::Result<ListInboundShipmentsResponse> {
    use self::decode::{start_document, element, fold_elements, characters};
    start_document(s)?;
    element(s, vec!["ListInboundShipmentsResponse", "ListInboundShipmentsByNextTokenResponse"], |s| {
      fold_elements(s, ListInboundShipmentsResponse::default(), |s, response| {
        match s.local_name() {
          "ListInboundShipmentsResult" | "ListInboundShipmentsByNextTokenResult" => {
            fold_elements(s, (), |s, _| {
              match s.local_name() {
                "ShipmentData" => {
                  response.shipment_data = fold_elements(s, vec![], |s, list| {
                    list.push(InboundShipmentInfo::from_xml(s)?);
                    Ok(())
                  })?;
                },
                "NextToken" => {
                  response.next_token = Some(characters(s)?);
                },
                _ => {},
              }
              Ok(())
            })
          },
          "ResponseMetadata" => {
            response.request_id = element(s, "RequestId", |s| {
              characters(s)
            })?;
            Ok(())
          },
          _ => { Ok(()) }
        }
      })
    })
  }
}

/// Returns a list of inbound shipments based on criteria that you specify.
///
/// [Documentation](http://docs.developer.amazonservices.com/en_CA/fba_inbound/FBAInbound_ListInboundShipments.html)
#[allow(non_snake_case)]
pub fn ListInboundShipments(client: &Client, parameters: ListInboundShipmentsParameters) -> Result<Response<ListInboundShipmentsResponse>> {
  client.request_xml(Method::Post, PATH, VERSION, "ListInboundShipments", parameters).map_err(|err| err.into())
}

/// Returns the next page of inbound shipments using the NextToken parameter.
///
/// [Documentation](http://docs.developer.amazonservices.com/en_CA/fba_inbound/FBAInbound_ListInboundShipmentsByNextToken.html)
#[allow(non_snake_case)]
pub fn ListInboundShipmentsByNextToken(client: &Client, next_token: String) -> Result<Response<ListInboundShipmentsResponse>> {
  let params = vec![
    ("NextToken".to_string(), next_token)
  ];
  client.request_xml(Method::Post, PATH, VERSION, "ListInboundShipmentsByNextToken", params).map_err(|err| err.into())
}

/// Parameters for `ListInboundShipments`
#[derive(Debug, Default)]
pub struct ListInboundShipmentItemsParameters {
  pub shipment_id: String,
  pub last_updated_after: Option<DateTime<UTC>>,
  pub last_updated_before: Option<DateTime<UTC>>,
}

impl Into<Vec<(String, String)>> for ListInboundShipmentItemsParameters {
  fn into(self) -> Vec<(String, String)> {
    let mut result = vec![
      ("ShipmentId".to_owned(), self.shipment_id)
    ];

    if let Some(date) = self.last_updated_after {
      result.push(("LastUpdatedAfter".to_string(), date.to_iso8601()));
    }

    if let Some(date) = self.last_updated_before {
      result.push(("LastUpdatedBefore".to_string(), date.to_iso8601()));
    }

    result
  }
}

#[derive(Debug, Default, PartialEq)]
pub struct ListInboundShipmentItemsResponse {
  pub request_id: String,
  pub item_data: Vec<InboundShipmentItem>,
  pub next_token: Option<String>,
}

impl<S: decode::XmlEventStream> decode::FromXMLStream<S> for ListInboundShipmentItemsResponse {
  fn from_xml(s: &mut S) -> decode::Result<ListInboundShipmentItemsResponse> {
    use self::decode::{start_document, element, fold_elements, characters};
    start_document(s)?;
    element(s, vec!["ListInboundShipmentItemsResponse", "ListInboundShipmentItemsByNextTokenResponse"], |s| {
      fold_elements(s, ListInboundShipmentItemsResponse::default(), |s, response| {
        match s.local_name() {
          "ListInboundShipmentItemsResult" | "ListInboundShipmentItemsByNextTokenResult" => {
            fold_elements(s, (), |s, _| {
              match s.local_name() {
                "ItemData" => {
                  response.item_data = fold_elements(s, vec![], |s, list| {
                    list.push(InboundShipmentItem::from_xml(s)?);
                    Ok(())
                  })?;
                },
                "NextToken" => {
                  response.next_token = Some(characters(s)?);
                },
                _ => {},
              }
              Ok(())
            })
          },
          "ResponseMetadata" => {
            response.request_id = element(s, "RequestId", |s| {
              characters(s)
            })?;
            Ok(())
          },
          _ => { Ok(()) }
        }
      })
    })
  }
}

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

  #[test]
  fn test_decode_list_inbound_shipments_response() {
    test_decode!(ListInboundShipmentsResponse, r#"
    <ListInboundShipmentsResponse xmlns="http://mws.amazonaws.com/FulfillmentInboundShipment/2010-10-01/">
      <ListInboundShipmentsResult>
        <ShipmentData>
          <member>
            <DestinationFulfillmentCenterId>MDW2</DestinationFulfillmentCenterId>
            <LabelPrepType>NO_LABEL</LabelPrepType>
            <ShipFromAddress>
              <City>Fort Worth</City>
              <CountryCode>US</CountryCode>
              <PostalCode>76104</PostalCode>
              <Name>RPD LTD</Name>
              <AddressLine1>428 Hemphill St</AddressLine1>
              <StateOrProvinceCode>TX</StateOrProvinceCode>
            </ShipFromAddress>
            <ShipmentId>FBA4FWJMVV</ShipmentId>
            <AreCasesRequired>true</AreCasesRequired>
            <ShipmentName>FBA (2/19/17 9:39 PM) - 1</ShipmentName>
            <BoxContentsSource>INTERACTIVE</BoxContentsSource>
            <ShipmentStatus>CLOSED</ShipmentStatus>
          </member>
        </ShipmentData>
      </ListInboundShipmentsResult>
      <ResponseMetadata>
        <RequestId>04c87e79-f747-4da9-984f-5bc1f0b875e6</RequestId>
      </ResponseMetadata>
    </ListInboundShipmentsResponse>
    "#, ListInboundShipmentsResponse {
      next_token: None,
      request_id: "04c87e79-f747-4da9-984f-5bc1f0b875e6".to_owned(),
      shipment_data: vec![
        InboundShipmentInfo {
          DestinationFulfillmentCenterId: "MDW2".to_owned(),
          LabelPrepType: Some(LabelPrepType::NO_LABEL),
          ShipFromAddress: Address {
            City: "Fort Worth".to_owned(),
            CountryCode: "US".to_owned(),
            PostalCode: "76104".to_owned(),
            Name: "RPD LTD".to_owned(),
            AddressLine1: "428 Hemphill St".to_owned(),
            AddressLine2: "".to_owned(),
            StateOrProvinceCode: "TX".to_owned(),
            DistrictOrCounty: "".to_owned(),
          },
          ShipmentId: "FBA4FWJMVV".to_owned(),
          AreCasesRequired: true,
          ShipmentName: "FBA (2/19/17 9:39 PM) - 1".to_owned(),
          BoxContentsSource: Some(BoxContentsSource::INTERACTIVE),
          ShipmentStatus: ShipmentStatus::CLOSED,
          ConfirmedNeedByDate: "".to_owned(),
          EstimatedBoxContentsFee: None,
        }
      ],
    });
  }

  #[test]
  fn test_decode_list_inbound_shipment_items_response() {
    test_decode!(ListInboundShipmentItemsResponse, r#"
    <ListInboundShipmentItemsResponse xmlns="http://mws.amazonaws.com/FulfillmentInboundShipment/2010-10-01/">
      <ListInboundShipmentItemsResult>
        <ItemData>
          <member>
            <QuantityShipped>60</QuantityShipped>
            <ShipmentId>FBA3T68MQL</ShipmentId>
            <PrepDetailsList>
              <PrepDetails/>
            </PrepDetailsList>
            <FulfillmentNetworkSKU>B016P9HJIA</FulfillmentNetworkSKU>
            <SellerSKU>edifier-r1280t-fba</SellerSKU>
            <QuantityReceived>50</QuantityReceived>
            <QuantityInCase>2</QuantityInCase>
          </member>
        </ItemData>
      </ListInboundShipmentItemsResult>
      <ResponseMetadata>
        <RequestId>70a60f01-d0df-4a29-b093-e1cb53bd8fc2</RequestId>
      </ResponseMetadata>
    </ListInboundShipmentItemsResponse>
    "#, ListInboundShipmentItemsResponse {
      next_token: None,
      request_id: "70a60f01-d0df-4a29-b093-e1cb53bd8fc2".to_owned(),
      item_data: vec![
        InboundShipmentItem {
          ShipmentId: "FBA3T68MQL".to_owned(),
          SellerSKU: "edifier-r1280t-fba".to_owned(),
          QuantityShipped: 60,
          QuantityInCase: Some(2),
          QuantityReceived: Some(50),
          FulfillmentNetworkSKU: "B016P9HJIA".to_owned(),
        }
      ],
    });
  }

}<|endoftext|>


<commit_before>static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

pub struct Chip8 {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
        }
    }

    pub fn load_rom(&mut self, rom: &[u8]) {
        use std::slice::bytes::copy_memory;
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    pub fn get_display(&self) -> [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT] {
        self.display
    }

    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();
        self.pc += 2;

        match ins & 0xF000 {
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x6000 => self.set_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            _ => fail!("Unkown instruction: {:x}", ins)
        }
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, vx: uint, vy: uint, n: uint) {
        let offset = self.v[vx] as uint + (self.v[vy] as uint * DISPLAY_WIDTH);
        println!("n={}", n);

        for y in range(0u, n) {
            let b = self.ram[self.i as uint + y];
            for x in range(0u, 8) {
                self.display[offset + (y * DISPLAY_WIDTH) + x] ^= b & (0b10000000 >> x);
            }
        }
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] += byte;
    }

    fn set_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] = byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }
}
<commit_msg>Remove annoying print in display_sprite<commit_after>static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

pub struct Chip8 {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
        }
    }

    pub fn load_rom(&mut self, rom: &[u8]) {
        use std::slice::bytes::copy_memory;
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    pub fn get_display(&self) -> [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT] {
        self.display
    }

    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();
        self.pc += 2;

        match ins & 0xF000 {
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x6000 => self.set_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            _ => fail!("Unkown instruction: {:x}", ins)
        }
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, vx: uint, vy: uint, n: uint) {
        let offset = self.v[vx] as uint + (self.v[vy] as uint * DISPLAY_WIDTH);

        for y in range(0u, n) {
            let b = self.ram[self.i as uint + y];
            for x in range(0u, 8) {
                self.display[offset + (y * DISPLAY_WIDTH) + x] ^= b & (0b10000000 >> x);
            }
        }
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] += byte;
    }

    fn set_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] = byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(unused_attributes)]

extern crate regex;
extern crate time;
extern crate rustc_serialize;

mod util;

use util::command;
use util::fs;
use std::env;
use std::path::Path;

fn main() {
  let worlds = vec![
    "VR",
    "utes",
    "Sara",
    "SaraLite",
    "Sara_dbe1",
    "Chernarus",
    "Chernarus_Summer",
    "Porto",
    "Intro",
    "IsolaDiCapraia",
    "Mountains_ACR",
    "Takistan",
    "Zargabad",
    "Woodland_ACR",
    "Bootcamp_ACR",
    "Desert_E",
    "ProvingGrounds_PMC",
    "Shapur_BAF",
    "fata",
    "Stratis",
    "anim_helvantis_v2",
    "Altis",
    "pja310"
  ];

  let cwd: String = format!("{}\\", get_cwd());

  prepate_comfyDowntime(cwd.as_ref());

  // Mission Generation for all Maps
  for map in worlds {
    println!("Generating missions for Map: {}", map);
    compile_comfyDowntime(cwd.as_ref(), map);
    compile_comfyCompetition(cwd.as_ref(), map);
  }
}

fn prepate_comfyDowntime(path: &str) {
  let mission_downtime = "FP_ComfyDowntime";
  let dirpath: String = format!("{}{}.VR", path, mission_downtime);
  let mission_str: &str = "COMFY_USE_B = false; COMFY_USE_O = false; COMFY_USE_I = false;";

  // Create Folders for ComfyDowntime Faction Variations
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Blufor", path, mission_downtime).as_ref(), "/E"]);
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Opfor", path, mission_downtime).as_ref(), "/E"]);
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Indfor", path, mission_downtime).as_ref(), "/E"]);

  /***********************
  # Mission.sqm Editing
  ************************/
  let mission_path: String = format!("{}.VR\\mission.sqm", mission_downtime);
  let mission_path_slice: &str = mission_path.as_ref();
  let mission_path_struct = Path::new(mission_path_slice);
  let mission_file: String = fs::read(&mission_path_struct);

  let mut mission_blufor: String = mission_file.replace(mission_str, "COMFY_USE_B = true; COMFY_USE_O = false; COMFY_USE_I = false;");
  let mut mission_opfor: String = mission_file.replace(mission_str, "COMFY_USE_B = false; COMFY_USE_O = true; COMFY_USE_I = false;");
  let mut mission_indfor: String = mission_file.replace(mission_str, "COMFY_USE_B = false; COMFY_USE_O = false; COMFY_USE_I = true;");

  // Now replace the Units in the mission to fit the Faction. We don't require to replace blufor units, since blufor classes are already default
  mission_opfor = mission_opfor.replace("b_soldier_unarmed_f", "o_soldier_unarmed_f");
  mission_indfor = mission_indfor.replace("b_soldier_unarmed_f", "i_soldier_unarmed_f");

  // Adjust the Actual Side of the unit.
  mission_opfor = mission_opfor.replace("side=\"WEST\";", "side=\"EAST\";");
  mission_indfor = mission_indfor.replace("side=\"WEST\";", "side=\"GUER\";");

  mission_blufor = mission_blufor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (BLUFOR)");
  mission_opfor = mission_opfor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (OPFOR)");
  mission_indfor = mission_indfor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (INDFOR)");

  fs::write(format!("{}_Blufor.\\mission.sqm", mission_downtime).as_ref(), mission_blufor.as_ref());
  fs::write(format!("{}_Opfor.\\mission.sqm", mission_downtime).as_ref(), mission_opfor.as_ref());
  fs::write(format!("{}_Indfor.\\mission.sqm", mission_downtime).as_ref(), mission_indfor.as_ref());

  /***********************
  # Description.ext Editing
  ************************/
  let description_path: String = format!("{}.VR\\description.ext", mission_downtime);
  let description_path_slice: &str = description_path.as_ref();
  let description_path_struct = Path::new(description_path_slice);
  let description_file: String = fs::read(&description_path_struct);

  let description_blufor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (BLUFOR)");
  let description_opfor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (OPFOR)");
  let description_indfor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (INDFOR)");

  fs::write(format!("{}_Blufor.\\description.ext", mission_downtime).as_ref(), description_blufor.as_ref());
  fs::write(format!("{}_Opfor.\\description.ext", mission_downtime).as_ref(), description_opfor.as_ref());
  fs::write(format!("{}_Indfor.\\description.ext", mission_downtime).as_ref(), description_indfor.as_ref());
}

fn compile_comfyDowntime(path: &str, map: &str) {
  let dirpath_blufor: String = format!("{}FP_ComfyDowntime_Blufor", path);
  let newpath_blufor: String = format!("{}FP_ComfyDowntime_Blufor.{}.pbo", path, map);

  let dirpath_opfor: String = format!("{}FP_ComfyDowntime_Opfor", path);
  let newpath_opfor: String = format!("{}FP_ComfyDowntime_Opfor.{}.pbo", path, map);

  let dirpath_indfor: String = format!("{}FP_ComfyDowntime_Indfor", path);
  let newpath_indfor: String = format!("{}FP_ComfyDowntime_Indfor.{}.pbo", path, map);

  command::run("PBOConsole", &["-pack", dirpath_blufor.as_ref(), newpath_blufor.as_ref()]);
  command::run("PBOConsole", &["-pack", dirpath_opfor.as_ref(), newpath_opfor.as_ref()]);
  command::run("PBOConsole", &["-pack", dirpath_indfor.as_ref(), newpath_indfor.as_ref()]);
}

fn compile_comfyCompetition(path: &str, map: &str) {
  let dirpath: String = format!("{}FP_ComfyCompetition.VR", path);
  let newpath: String = format!("{}FP_ComfyCompetition.{}.pbo", path, map);
  command::run("PBOConsole", &["-pack", dirpath.as_ref(), newpath.as_ref()]);
}

//
fn get_cwd() -> String {
  let pathbuf = env::current_dir().unwrap();
  let path: &str = pathbuf.to_str().unwrap();
  path.to_string()
}<commit_msg>Updated Documentation of the Build system for the ComfyDowntime missions<commit_after>#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(unused_attributes)]

extern crate regex;
extern crate time;
extern crate rustc_serialize;

mod util;

use util::command;
use util::fs;
use std::env;
use std::path::Path;

fn main() {
  let worlds = vec![
    "VR",
    "utes",
    "Sara",
    "SaraLite",
    "Sara_dbe1",
    "Chernarus",
    "Chernarus_Summer",
    "Porto",
    "Intro",
    "IsolaDiCapraia",
    "Mountains_ACR",
    "Takistan",
    "Zargabad",
    "Woodland_ACR",
    "Bootcamp_ACR",
    "Desert_E",
    "ProvingGrounds_PMC",
    "Shapur_BAF",
    "fata",
    "Stratis",
    "anim_helvantis_v2",
    "Altis",
    "pja310"
  ];

  let cwd: String = format!("{}\\", get_cwd());

  prepare_comfyDowntime(cwd.as_ref());

  // Mission Generation for all Maps
  for map in worlds {
    println!("Generating missions for Map: {}", map);
    compile_comfyDowntime(cwd.as_ref(), map);
    compile_comfyCompetition(cwd.as_ref(), map);
  }
}

/*
  This function prepares the ComfyDowntime mission to be packed.
  It copies the main ComfyDowntime folder into 3 seperate ones. 1 for each major faction in the Armaverse.
  BLUFOR, OPFOR and INDFOR.

  Along with this, it edits the mission.sqm and description.ext files and Replaces the units, sides and mission name to fit the currently used faction.
*/
fn prepare_comfyDowntime(path: &str) {
  let mission_downtime = "FP_ComfyDowntime";
  let dirpath: String = format!("{}{}.VR", path, mission_downtime);
  let mission_str: &str = "COMFY_USE_B = false; COMFY_USE_O = false; COMFY_USE_I = false;";

  // Create Folders for ComfyDowntime Faction Variations
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Blufor", path, mission_downtime).as_ref(), "/E"]);
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Opfor", path, mission_downtime).as_ref(), "/E"]);
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Indfor", path, mission_downtime).as_ref(), "/E"]);

  /***********************
  # Mission.sqm Editing
  ************************/
  let mission_path: String = format!("{}.VR\\mission.sqm", mission_downtime);
  let mission_path_slice: &str = mission_path.as_ref();
  let mission_path_struct = Path::new(mission_path_slice);
  let mission_file: String = fs::read(&mission_path_struct);

  let mut mission_blufor: String = mission_file.replace(mission_str, "COMFY_USE_B = true; COMFY_USE_O = false; COMFY_USE_I = false;");
  let mut mission_opfor: String = mission_file.replace(mission_str, "COMFY_USE_B = false; COMFY_USE_O = true; COMFY_USE_I = false;");
  let mut mission_indfor: String = mission_file.replace(mission_str, "COMFY_USE_B = false; COMFY_USE_O = false; COMFY_USE_I = true;");

  // Now replace the Units in the mission to fit the Faction. We don't require to replace blufor units, since blufor classes are already default
  mission_opfor = mission_opfor.replace("b_soldier_unarmed_f", "o_soldier_unarmed_f");
  mission_indfor = mission_indfor.replace("b_soldier_unarmed_f", "i_soldier_unarmed_f");

  // Adjust the Actual Side of the unit.
  mission_opfor = mission_opfor.replace("side=\"WEST\";", "side=\"EAST\";");
  mission_indfor = mission_indfor.replace("side=\"WEST\";", "side=\"GUER\";");

  mission_blufor = mission_blufor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (BLUFOR)");
  mission_opfor = mission_opfor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (OPFOR)");
  mission_indfor = mission_indfor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (INDFOR)");

  fs::write(format!("{}_Blufor.\\mission.sqm", mission_downtime).as_ref(), mission_blufor.as_ref());
  fs::write(format!("{}_Opfor.\\mission.sqm", mission_downtime).as_ref(), mission_opfor.as_ref());
  fs::write(format!("{}_Indfor.\\mission.sqm", mission_downtime).as_ref(), mission_indfor.as_ref());

  /***********************
  # Description.ext Editing
  ************************/
  let description_path: String = format!("{}.VR\\description.ext", mission_downtime);
  let description_path_slice: &str = description_path.as_ref();
  let description_path_struct = Path::new(description_path_slice);
  let description_file: String = fs::read(&description_path_struct);

  let description_blufor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (BLUFOR)");
  let description_opfor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (OPFOR)");
  let description_indfor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (INDFOR)");

  fs::write(format!("{}_Blufor.\\description.ext", mission_downtime).as_ref(), description_blufor.as_ref());
  fs::write(format!("{}_Opfor.\\description.ext", mission_downtime).as_ref(), description_opfor.as_ref());
  fs::write(format!("{}_Indfor.\\description.ext", mission_downtime).as_ref(), description_indfor.as_ref());
}

/*
  This function Executes the PBOConsole Command and builds the Actual PBO Files for the
  ComfyDowntime Mission.

  It creates 3 PBO Files. One for Each Major Faction in Arma. BLUFOR; OPFOR and INFDOR/GUER
*/
fn compile_comfyDowntime(path: &str, map: &str) {
  let dirpath_blufor: String = format!("{}FP_ComfyDowntime_Blufor", path);
  let newpath_blufor: String = format!("{}FP_ComfyDowntime_Blufor.{}.pbo", path, map);

  let dirpath_opfor: String = format!("{}FP_ComfyDowntime_Opfor", path);
  let newpath_opfor: String = format!("{}FP_ComfyDowntime_Opfor.{}.pbo", path, map);

  let dirpath_indfor: String = format!("{}FP_ComfyDowntime_Indfor", path);
  let newpath_indfor: String = format!("{}FP_ComfyDowntime_Indfor.{}.pbo", path, map);

  command::run("PBOConsole", &["-pack", dirpath_blufor.as_ref(), newpath_blufor.as_ref()]);
  command::run("PBOConsole", &["-pack", dirpath_opfor.as_ref(), newpath_opfor.as_ref()]);
  command::run("PBOConsole", &["-pack", dirpath_indfor.as_ref(), newpath_indfor.as_ref()]);
}

/*
  This function Executes the PBOConsole Command and builds the Actual BPO Files for the ComfyCompetition Mission.
*/
fn compile_comfyCompetition(path: &str, map: &str) {
  let dirpath: String = format!("{}FP_ComfyCompetition.VR", path);
  let newpath: String = format!("{}FP_ComfyCompetition.{}.pbo", path, map);
  command::run("PBOConsole", &["-pack", dirpath.as_ref(), newpath.as_ref()]);
}

/*
  This function returns the Current working directory as a String.
  If combined with another path, an \\ or / might have to be added to
  the End of this String.

  for this, use the following format:
  format!("{}\\", get_cwd())
*/
fn get_cwd() -> String {
  let pathbuf = env::current_dir().unwrap();
  let path: &str = pathbuf.to_str().unwrap();
  path.to_string()
}<|endoftext|>


<commit_before>use nalgebra;
use num::Num;
use std::cmp;
use std::convert::From;
use std::marker::PhantomData;
use std::ops;

pub trait ClampedRange<T> {
    fn max_value() -> T;
    fn min_value() -> T;
}

pub struct Clamped<T, R>(T, PhantomData<R>)
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>;

impl<T, R> Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    pub fn new(value: T) -> Self {
        Clamped(nalgebra::clamp(value, R::min_value(), R::max_value()), PhantomData)
    }

    pub fn max_value() -> Self {
        Clamped(R::max_value(), PhantomData)
    }

    pub fn min_value() -> Self {
        Clamped(R::min_value(), PhantomData)
    }

    pub fn unclamped(&self) -> T {
        self.0
    }
}

impl<T, R> Clone for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn clone(&self) -> Self {
        Clamped(self.0, PhantomData)
    }
}

impl<T, R> Copy for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T> {}

impl<T, R> From<T> for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn from(value: T) -> Self {
        Self::new(value)
    }
}

impl<T, R> cmp::Eq for Clamped<T, R>
    where T: Copy + cmp::Eq + Num + cmp::PartialOrd,
          R: ClampedRange<T> {}

impl<T, R> cmp::Ord for Clamped<T, R>
    where T: Copy + Num + cmp::Ord + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T, R> cmp::PartialEq for Clamped<T, R>
    where T: Copy + Num + cmp::PartialEq + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn eq(&self, other: &Self) -> bool {
        self.0.eq(&other.0)
    }
}

impl<T, R> cmp::PartialOrd for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T, R> ops::Add for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: Self) -> Self::Output {
        Self::new(self.0.add(other.0))
    }
}

impl<T, R> ops::Add<T> for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: T) -> Self::Output {
        Self::new(self.0.add(other))
    }
}

impl<T, R> ops::Deref for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T, R> ops::Div for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: Self) -> Self::Output {
        Self::new(self.0.div(other.0))
    }
}

impl<T, R> ops::Div<T> for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: T) -> Self::Output {
        Self::new(self.0.div(other))
    }
}

impl<T, R> ops::Mul for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: Self) -> Self::Output {
        Self::new(self.0.mul(other.0))
    }
}

impl<T, R> ops::Mul<T> for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: T) -> Self::Output {
        Self::new(self.0.mul(other))
    }
}

impl<T, R> ops::Neg for Clamped<T, R>
    where T: Copy + ops::Neg<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self::new(self.0.neg())
    }
}

impl<T, R> ops::Sub for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: Self) -> Self::Output {
        Self::new(self.0.sub(other.0))
    }
}

impl<T, R> ops::Sub<T> for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: T) -> Self::Output {
        Self::new(self.0.sub(other))
    }
}
<commit_msg>Implement `Clamp` for `Clamped`.<commit_after>use nalgebra;
use num::Num;
use std::cmp;
use std::convert::From;
use std::marker::PhantomData;
use std::ops;

use math::Clamp;

pub trait ClampedRange<T> {
    fn max_value() -> T;
    fn min_value() -> T;
}

pub struct Clamped<T, R>(T, PhantomData<R>)
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>;

impl<T, R> Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    pub fn new(value: T) -> Self {
        Clamped(nalgebra::clamp(value, R::min_value(), R::max_value()), PhantomData)
    }

    pub fn max_value() -> Self {
        Clamped(R::max_value(), PhantomData)
    }

    pub fn min_value() -> Self {
        Clamped(R::min_value(), PhantomData)
    }

    pub fn unclamped(&self) -> T {
        self.0
    }
}

impl<T, R> Clamp<Clamped<T, R>> for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn clamp(&self, min: Self, max: Self) -> Self {
        nalgebra::clamp(*self, min, max)
    }
}

impl<T, R> Clone for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn clone(&self) -> Self {
        Clamped(self.0, PhantomData)
    }
}

impl<T, R> Copy for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T> {}

impl<T, R> From<T> for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn from(value: T) -> Self {
        Self::new(value)
    }
}

impl<T, R> cmp::Eq for Clamped<T, R>
    where T: Copy + cmp::Eq + Num + cmp::PartialOrd,
          R: ClampedRange<T> {}

impl<T, R> cmp::Ord for Clamped<T, R>
    where T: Copy + Num + cmp::Ord + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T, R> cmp::PartialEq for Clamped<T, R>
    where T: Copy + Num + cmp::PartialEq + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn eq(&self, other: &Self) -> bool {
        self.0.eq(&other.0)
    }
}

impl<T, R> cmp::PartialOrd for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T, R> ops::Add for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: Self) -> Self::Output {
        Self::new(self.0.add(other.0))
    }
}

impl<T, R> ops::Add<T> for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: T) -> Self::Output {
        Self::new(self.0.add(other))
    }
}

impl<T, R> ops::Deref for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T, R> ops::Div for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: Self) -> Self::Output {
        Self::new(self.0.div(other.0))
    }
}

impl<T, R> ops::Div<T> for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: T) -> Self::Output {
        Self::new(self.0.div(other))
    }
}

impl<T, R> ops::Mul for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: Self) -> Self::Output {
        Self::new(self.0.mul(other.0))
    }
}

impl<T, R> ops::Mul<T> for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: T) -> Self::Output {
        Self::new(self.0.mul(other))
    }
}

impl<T, R> ops::Neg for Clamped<T, R>
    where T: Copy + ops::Neg<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self::new(self.0.neg())
    }
}

impl<T, R> ops::Sub for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: Self) -> Self::Output {
        Self::new(self.0.sub(other.0))
    }
}

impl<T, R> ops::Sub<T> for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: T) -> Self::Output {
        Self::new(self.0.sub(other))
    }
}
<|endoftext|>