<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 {
            self.patterns.first().iter().any(|first|{ message.ids().any(|id| &id == first)})
        } 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 {
            state.messages().last().iter().any(|last_message| {
                self.patterns.last().iter().any(|last|{ last_message.ids().any(|id| &id == last)})
            })
        } 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);
    }

    #[test]
    fn test_given_condition_when_last_closes_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())
                             .last_closes(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()),
            })
        }
    }
}
<commit_msg>Conditions: fix MessageBuilder usage<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 {
            self.patterns.first().iter().any(|first|{ message.ids().any(|id| &id == first)})
        } 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 {
            state.messages().last().iter().any(|last_message| {
                self.patterns.last().iter().any(|last|{ last_message.ids().any(|id| &id == last)})
            })
        } 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);
    }

    #[test]
    fn test_given_condition_when_last_closes_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())
                             .last_closes(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>use std::net::{SocketAddr};
use std::time::{Duration, Instant};
use std::collections::VecDeque;
use std::sync::Arc;

use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_core::io::{Io, Framed};
use tokio_timer::{Timer};
use futures::Future;
use futures::Sink;
use futures::Stream;
use futures::sync::mpsc;

use mqtt3::{Message, QoS, TopicPath, PacketIdentifier, SubscribeTopic};

use error::*;
use packet::*;
use codec::MqttCodec;
use clientoptions::MqttOptions;

pub type MessageSendableFn = Box<Fn(Message) + Send + Sync>;
pub type PublishSendableFn = Box<Fn(Message) + Send + Sync>;

pub struct Connection {
    pub addr: SocketAddr,
    pub state: MqttState,
    pub opts: MqttOptions,
    pub initial_connect: bool,
    pub await_pingresp: bool,
    pub last_flush: Instant,

    pub no_of_reconnections: u32,

    /// On message callback
    pub message_callback: Option<Arc<MessageSendableFn>>,
    /// On publish callback
    pub publish_callback: Option<Arc<PublishSendableFn>>,

    // Queues. Note: 'record' is qos2 term for 'publish'
    /// For QoS 1. Stores outgoing publishes
    pub outgoing_pub: VecDeque<Box<Message>>,
    /// For QoS 2. Store for incoming publishes to record.
    pub incoming_rec: VecDeque<Box<Message>>, //
    /// For QoS 2. Store for outgoing publishes.
    pub outgoing_rec: VecDeque<PacketIdentifier>,
    /// For Qos2. Store for outgoing `pubrel` packets.
    pub outgoing_rel: VecDeque<PacketIdentifier>,
    /// For Qos2. Store for outgoing `pubcomp` packets.
    pub outgoing_comp: VecDeque<PacketIdentifier>,

    // clean_session=false will remember subscriptions only till lives.
    // If broker crashes, all its state will be lost (most brokers).
    // client wouldn't want to loose messages after it comes back up again
    pub subscriptions: VecDeque<Vec<SubscribeTopic>>,

    pub reactor: Core,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MqttState {
    Handshake,
    Connected,
    Disconnected,
}

#[derive(Debug)]
pub enum NetworkRequest {
    Subscribe(Vec<(TopicPath, QoS)>),
    Publish(Message),
    Retransmit,
    Shutdown,
    Disconnect,
    Ping,
}

#[derive(Debug)]
pub enum NetworkNotification {
    Disconnected,
    Connected,
}

// DESIGN: Initial connect status should be immediately known.
//        Intermediate disconnections should be automatically reconnected
fn _try_reconnect(addr: SocketAddr, reactor: &mut Core) -> Result<Framed<TcpStream, MqttCodec>, Error> {

    let connect = generate_connect_packet("".to_string(), true, None, None);

    let f_response = TcpStream::connect(&addr, &reactor.handle()).and_then(|connection| {
        let framed = connection.framed(MqttCodec);
        let f1 = framed.send(connect);

        f1.and_then(|framed| {
                framed.into_future()
                    .and_then(|(res, stream)| Ok((res, stream)))
                    .map_err(|(err, _stream)| err)
            })
            .boxed()
    });

    let response = reactor.run(f_response);
    let (packet, frame) = response?;
    println!("{:?}", packet);
    Ok(frame)
}

impl Connection {
    pub fn start(addr: SocketAddr,
                 opts: MqttOptions,
                 publish_callback: Option<Arc<PublishSendableFn>>,
                 message_callback: Option<Arc<MessageSendableFn>>) -> Result<(Self, Framed<TcpStream, MqttCodec>), Error> {
        let mut reactor = Core::new().unwrap();

        let framed = _try_reconnect(addr, &mut reactor)?;

        let connection = Connection {
            addr: addr,
            state: MqttState::Disconnected,
            opts: opts,
            initial_connect: true,
            await_pingresp: false,
            last_flush: Instant::now(),

            no_of_reconnections: 0,

            publish_callback: publish_callback,
            message_callback: message_callback,

            // Queues
            incoming_rec: VecDeque::new(),
            outgoing_pub: VecDeque::new(),
            outgoing_rec: VecDeque::new(),
            outgoing_rel: VecDeque::new(),
            outgoing_comp: VecDeque::new(),

            // Subscriptions
            subscriptions: VecDeque::new(),

            reactor: reactor,
        };

        Ok((connection, framed))
    }

    pub fn run(&mut self, framed: Framed<TcpStream, MqttCodec>) -> Result<(), Error> {
        let (mut sender, receiver) = framed.split();
        let rx_future = receiver.for_each(|msg| {
            print!("{:?}", msg);
            Ok(())
        }).map_err(|e| Error::Io(e));

        let (mut sender_tx, sender_rx) = mpsc::channel::<NetworkRequest>(1);

        // Ping timer
        let timer = Timer::default();

        let keep_alive = if self.opts.keep_alive.is_some() {
            self.opts.keep_alive.unwrap() as u64
        } else {
            1000
        };

        let interval = timer.interval(Duration::new(keep_alive, 0));
        let timer_future = interval.for_each(|_| {
                let ref mut sender_tx = sender_tx;
                sender_tx.send(NetworkRequest::Ping).wait().unwrap();
                Ok(())
            }).map_err(|e| Error::Timer(e));

        // Sender which does network writes
        let sender_future = sender_rx.for_each(move |r| {
            let packet = match r {
                NetworkRequest::Ping => {
                    println!("{:?}", r);
                    generate_pingreq_packet()
                }
                _ => panic!("Misc")
            };

            let _ = (&mut sender).send(packet).wait();
            Ok(())
        }).map_err(|_|Error::Sender);

        let mqtt_future =  timer_future.join3(rx_future, sender_future);

        let _ = self.reactor.run(mqtt_future)?;
        Ok(())
    }
}
<commit_msg>create ping timer in a separate method<commit_after>use std::net::{SocketAddr};
use std::time::{Duration, Instant};
use std::collections::VecDeque;
use std::sync::Arc;

use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_core::io::{Io, Framed};
use tokio_timer::{Timer, Interval};
use futures::Future;
use futures::Sink;
use futures::Stream;
use futures::sync::mpsc;

use mqtt3::{Message, QoS, TopicPath, PacketIdentifier, SubscribeTopic};

use error::*;
use packet::*;
use codec::MqttCodec;
use clientoptions::MqttOptions;

pub type MessageSendableFn = Box<Fn(Message) + Send + Sync>;
pub type PublishSendableFn = Box<Fn(Message) + Send + Sync>;

pub struct Connection {
    pub addr: SocketAddr,
    pub state: MqttState,
    pub opts: MqttOptions,
    pub initial_connect: bool,
    pub await_pingresp: bool,
    pub last_flush: Instant,

    pub no_of_reconnections: u32,

    /// On message callback
    pub message_callback: Option<Arc<MessageSendableFn>>,
    /// On publish callback
    pub publish_callback: Option<Arc<PublishSendableFn>>,

    // Queues. Note: 'record' is qos2 term for 'publish'
    /// For QoS 1. Stores outgoing publishes
    pub outgoing_pub: VecDeque<Box<Message>>,
    /// For QoS 2. Store for incoming publishes to record.
    pub incoming_rec: VecDeque<Box<Message>>, //
    /// For QoS 2. Store for outgoing publishes.
    pub outgoing_rec: VecDeque<PacketIdentifier>,
    /// For Qos2. Store for outgoing `pubrel` packets.
    pub outgoing_rel: VecDeque<PacketIdentifier>,
    /// For Qos2. Store for outgoing `pubcomp` packets.
    pub outgoing_comp: VecDeque<PacketIdentifier>,

    // clean_session=false will remember subscriptions only till lives.
    // If broker crashes, all its state will be lost (most brokers).
    // client wouldn't want to loose messages after it comes back up again
    pub subscriptions: VecDeque<Vec<SubscribeTopic>>,

    pub reactor: Core,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MqttState {
    Handshake,
    Connected,
    Disconnected,
}

#[derive(Debug)]
pub enum NetworkRequest {
    Subscribe(Vec<(TopicPath, QoS)>),
    Publish(Message),
    Retransmit,
    Shutdown,
    Disconnect,
    Ping,
}

#[derive(Debug)]
pub enum NetworkNotification {
    Disconnected,
    Connected,
}

// DESIGN: Initial connect status should be immediately known.
//        Intermediate disconnections should be automatically reconnected
fn _try_reconnect(addr: SocketAddr, reactor: &mut Core) -> Result<Framed<TcpStream, MqttCodec>, Error> {

    let connect = generate_connect_packet("".to_string(), true, None, None);

    let f_response = TcpStream::connect(&addr, &reactor.handle()).and_then(|connection| {
        let framed = connection.framed(MqttCodec);
        let f1 = framed.send(connect);

        f1.and_then(|framed| {
                framed.into_future()
                    .and_then(|(res, stream)| Ok((res, stream)))
                    .map_err(|(err, _stream)| err)
            })
            .boxed()
    });

    let response = reactor.run(f_response);
    let (packet, frame) = response?;
    println!("{:?}", packet);
    Ok(frame)
}

impl Connection {
    pub fn start(addr: SocketAddr,
                 opts: MqttOptions,
                 publish_callback: Option<Arc<PublishSendableFn>>,
                 message_callback: Option<Arc<MessageSendableFn>>) -> Result<(Self, Framed<TcpStream, MqttCodec>), Error> {
        let mut reactor = Core::new().unwrap();

        let framed = _try_reconnect(addr, &mut reactor)?;

        let connection = Connection {
            addr: addr,
            state: MqttState::Disconnected,
            opts: opts,
            initial_connect: true,
            await_pingresp: false,
            last_flush: Instant::now(),

            no_of_reconnections: 0,

            publish_callback: publish_callback,
            message_callback: message_callback,

            // Queues
            incoming_rec: VecDeque::new(),
            outgoing_pub: VecDeque::new(),
            outgoing_rec: VecDeque::new(),
            outgoing_rel: VecDeque::new(),
            outgoing_comp: VecDeque::new(),

            // Subscriptions
            subscriptions: VecDeque::new(),

            reactor: reactor,
        };

        Ok((connection, framed))
    }

    fn pingtimer(&mut self) -> Interval {
        let timer = Timer::default();

        let keep_alive = if self.opts.keep_alive.is_some() {
            self.opts.keep_alive.unwrap() as u64
        } else {
            1000
        };

        timer.interval(Duration::new(keep_alive, 0))
    }

    pub fn run(&mut self, framed: Framed<TcpStream, MqttCodec>) -> Result<(), Error> {
        let (mut sender, receiver) = framed.split();
        let rx_future = receiver.for_each(|msg| {
            print!("{:?}", msg);
            Ok(())
        }).map_err(|e| Error::Io(e));

        let (mut sender_tx, sender_rx) = mpsc::channel::<NetworkRequest>(1);

        let pingtimer = self.pingtimer();
        let timer_future = pingtimer.for_each(|_| {
                let ref mut sender_tx = sender_tx;
                sender_tx.send(NetworkRequest::Ping).wait().unwrap();
                Ok(())
            }).map_err(|e| Error::Timer(e));

        // Sender which does network writes
        let sender_future = sender_rx.for_each(move |r| {
            let packet = match r {
                NetworkRequest::Ping => {
                    println!("{:?}", r);
                    generate_pingreq_packet()
                }
                _ => panic!("Misc")
            };

            let _ = (&mut sender).send(packet).wait();
            Ok(())
        }).map_err(|_|Error::Sender);

        let mqtt_future =  timer_future.join3(rx_future, sender_future);

        let _ = self.reactor.run(mqtt_future)?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::thread;
use std::result::Result;

use super::{config, Command, Context, Dispatcher, Event, Message, Timer};

const TIMER_STEP: u32 = 100;

pub struct Correlator {
    tx: mpsc::Sender<Command>,
    dispatcher_thread_handle: thread::JoinHandle<()>
}

impl Correlator {
    pub fn new(contexts: Vec<config::Context>) -> Correlator {
        let (tx, rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, tx.clone());

        let handle = thread::spawn(move || {
            let mut dispatcher = Dispatcher::new(contexts);

            for i in rx.iter() {
                match i {
                    Command::Dispatch(event) => dispatcher.dispatch(event),
                    Command::Exit => break
                }
            }
        });

        Correlator {
            tx: tx,
            dispatcher_thread_handle: handle
        }
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Command>> {
        self.tx.send(Command::Dispatch(Event::Message(message)))
    }

    pub fn stop(self) -> thread::Result<()> {
        let _ = self.tx.send(Command::Exit);
        self.dispatcher_thread_handle.join()
    }
}
<commit_msg>Correlator: rename tx to dispatcher_input_channel<commit_after>use std::sync::mpsc;
use std::thread;
use std::result::Result;

use super::{config, Command, Context, Dispatcher, Event, Message, Timer};

const TIMER_STEP: u32 = 100;

pub struct Correlator {
    dispatcher_input_channel: mpsc::Sender<Command>,
    dispatcher_thread_handle: thread::JoinHandle<()>
}

impl Correlator {
    pub fn new(contexts: Vec<config::Context>) -> Correlator {
        let (dispatcher_input_channel, rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, dispatcher_input_channel.clone());

        let handle = thread::spawn(move || {
            let mut dispatcher = Dispatcher::new(contexts);

            for i in rx.iter() {
                match i {
                    Command::Dispatch(event) => dispatcher.dispatch(event),
                    Command::Exit => break
                }
            }
        });

        Correlator {
            dispatcher_input_channel: dispatcher_input_channel,
            dispatcher_thread_handle: handle
        }
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Command>> {
        self.dispatcher_input_channel.send(Command::Dispatch(Event::Message(message)))
    }

    pub fn stop(self) -> thread::Result<()> {
        let _ = self.dispatcher_input_channel.send(Command::Exit);
        self.dispatcher_thread_handle.join()
    }
}
<|endoftext|>


<commit_before>use semver;

use pg;
use Model;
use git;
use db::Connection;
use util::{CargoResult};

pub struct Dependency {
    pub id: i32,
    pub version_id: i32,
    pub crate_id: i32,
    pub req: semver::VersionReq,
    pub optional: bool,
    pub default_features: bool,
    pub features: Vec<String>,
    pub target: Option<String>,
    pub kind: Kind,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableDependency {
    pub id: i32,
    pub version_id: i32,
    pub crate_id: String,
    pub req: String,
    pub optional: bool,
    pub default_features: bool,
    pub features: String,
    pub target: Option<String>,
    pub kind: Kind,
}

#[derive(Copy, Clone)]
// NB: this order is important, it must be retained! The database stores an
// integer corresponding to each variant.
pub enum Kind {
    Normal,
    Build,
    Dev,

    // if you add a kind here, be sure to update `from_row` below.
}

impl Dependency {
    pub fn insert(conn: &Connection, version_id: i32, crate_id: i32,
                  req: &semver::VersionReq, kind: Kind,
                  optional: bool, default_features: bool,
                  features: &[String], target: &Option<String>)
                  -> CargoResult<Dependency> {
        let req = req.to_string();
        let features = features.connect(",");
        let stmt = try!(conn.prepare("INSERT INTO dependencies
                                      (version_id, crate_id, req, optional,
                                       default_features, features, target, kind)
                                      VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
                                      RETURNING *"));
        let rows = try!(stmt.query(&[&version_id, &crate_id, &req,
                                      &optional, &default_features,
                                      &features, target, &(kind as i32)]));
        Ok(Model::from_row(&rows.iter().next().unwrap()))
    }

    pub fn git_encode(&self, crate_name: &str) -> git::Dependency {
        let Dependency { id: _, version_id: _, crate_id: _, ref req,
                         optional, default_features, ref features,
                         ref target, kind } = *self;
        git::Dependency {
            name: crate_name.to_string(),
            req: req.to_string(),
            features: features.clone(),
            optional: optional,
            default_features: default_features,
            target: target.clone(),
            kind: Some(kind),
        }
    }

    pub fn encodable(self, crate_name: &str) -> EncodableDependency {
        let Dependency { id, version_id, crate_id: _, req, optional,
                         default_features, features, target, kind } = self;
        EncodableDependency {
            id: id,
            version_id: version_id,
            crate_id: crate_name.to_string(),
            req: req.to_string(),
            optional: optional,
            default_features: default_features,
            features: features.connect(","),
            target: target,
            kind: kind,
        }
    }
}

impl Model for Dependency {
    fn from_row(row: &pg::Row) -> Dependency {
        let features: String = row.get("features");
        let req: String = row.get("req");
        let kind: Option<i32> = row.get("kind");
        Dependency {
            id: row.get("id"),
            version_id: row.get("version_id"),
            crate_id: row.get("crate_id"),
            req: semver::VersionReq::parse(&req).unwrap(),
            optional: row.get("optional"),
            default_features: row.get("default_features"),
            features: features.split(',').map(|s| s.to_string())
                              .collect(),
            target: row.get("target"),
            kind: match kind.unwrap_or(0) {
                0 => Kind::Normal,
                1 => Kind::Build,
                2 => Kind::Dev,
                n => panic!("unknown kind: {}", n),
            }
        }
    }

    fn table_name(_: Option<Dependency>) -> &'static str { "dependencies" }
}
<commit_msg>Filter out empty strings in the dependency list<commit_after>use semver;

use pg;
use Model;
use git;
use db::Connection;
use util::{CargoResult};

pub struct Dependency {
    pub id: i32,
    pub version_id: i32,
    pub crate_id: i32,
    pub req: semver::VersionReq,
    pub optional: bool,
    pub default_features: bool,
    pub features: Vec<String>,
    pub target: Option<String>,
    pub kind: Kind,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableDependency {
    pub id: i32,
    pub version_id: i32,
    pub crate_id: String,
    pub req: String,
    pub optional: bool,
    pub default_features: bool,
    pub features: String,
    pub target: Option<String>,
    pub kind: Kind,
}

#[derive(Copy, Clone)]
// NB: this order is important, it must be retained! The database stores an
// integer corresponding to each variant.
pub enum Kind {
    Normal,
    Build,
    Dev,

    // if you add a kind here, be sure to update `from_row` below.
}

impl Dependency {
    pub fn insert(conn: &Connection, version_id: i32, crate_id: i32,
                  req: &semver::VersionReq, kind: Kind,
                  optional: bool, default_features: bool,
                  features: &[String], target: &Option<String>)
                  -> CargoResult<Dependency> {
        let req = req.to_string();
        let features = features.connect(",");
        let stmt = try!(conn.prepare("INSERT INTO dependencies
                                      (version_id, crate_id, req, optional,
                                       default_features, features, target, kind)
                                      VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
                                      RETURNING *"));
        let rows = try!(stmt.query(&[&version_id, &crate_id, &req,
                                      &optional, &default_features,
                                      &features, target, &(kind as i32)]));
        Ok(Model::from_row(&rows.iter().next().unwrap()))
    }

    pub fn git_encode(&self, crate_name: &str) -> git::Dependency {
        let Dependency { id: _, version_id: _, crate_id: _, ref req,
                         optional, default_features, ref features,
                         ref target, kind } = *self;
        git::Dependency {
            name: crate_name.to_string(),
            req: req.to_string(),
            features: features.clone(),
            optional: optional,
            default_features: default_features,
            target: target.clone(),
            kind: Some(kind),
        }
    }

    pub fn encodable(self, crate_name: &str) -> EncodableDependency {
        let Dependency { id, version_id, crate_id: _, req, optional,
                         default_features, features, target, kind } = self;
        EncodableDependency {
            id: id,
            version_id: version_id,
            crate_id: crate_name.to_string(),
            req: req.to_string(),
            optional: optional,
            default_features: default_features,
            features: features.connect(","),
            target: target,
            kind: kind,
        }
    }
}

impl Model for Dependency {
    fn from_row(row: &pg::Row) -> Dependency {
        let features: String = row.get("features");
        let req: String = row.get("req");
        let kind: Option<i32> = row.get("kind");
        Dependency {
            id: row.get("id"),
            version_id: row.get("version_id"),
            crate_id: row.get("crate_id"),
            req: semver::VersionReq::parse(&req).unwrap(),
            optional: row.get("optional"),
            default_features: row.get("default_features"),
            features: features.split(',').filter(|s| !s.is_empty())
                              .map(|s| s.to_string())
                              .collect(),
            target: row.get("target"),
            kind: match kind.unwrap_or(0) {
                0 => Kind::Normal,
                1 => Kind::Build,
                2 => Kind::Dev,
                n => panic!("unknown kind: {}", n),
            }
        }
    }

    fn table_name(_: Option<Dependency>) -> &'static str { "dependencies" }
}
<|endoftext|>


<commit_before>use dbus::{Connection, ConnPath, BusType};
use dbus::stdintf::OrgFreedesktopDBusProperties;

use general::{NM_DEVICE_INTERFACE, NM_SERVICE_INTERFACE, NM_SERVICE_PATH};
use dbus_helper::{variant_to_string_list, manager_path, property_as_string, property_as_i64,
                  property_as_bool};

#[derive(Debug)]
pub struct Device {
    interface: String,
    path: String,
    device_type: DeviceType,
    state: DeviceState,
    real: bool,
}

impl DeviceState {
    #[inline]
    fn from_i64(state: i64) -> Self {
        match state {
            0 => DeviceState::Unknown,
            10 => DeviceState::Unmanaged,
            20 => DeviceState::Unavailable,
            30 => DeviceState::Disconnected,
            100 => DeviceState::Activated,
            110 => DeviceState::Deactivating,
            120 => DeviceState::Failed,
            _ => DeviceState::Unknown,

        }
    }
}

#[derive(Debug)]
pub enum DeviceType {
    Unknown,
    Generic,
    Ethernet,
    WiFi,
    Bridge,
}

impl DeviceType {
    #[inline]
    fn from_i64(state: i64) -> Self {
        match state {
            0 => DeviceType::Unknown,
            14 => DeviceType::Generic,
            1 => DeviceType::Ethernet,
            2 => DeviceType::WiFi,
            13 => DeviceType::Bridge,
            _ => DeviceType::Unknown,

        }
    }
}

#[derive(Debug)]
pub enum DeviceState {
    Unknown,
    Unmanaged,
    Unavailable,
    Disconnected,
    Activated,
    Deactivating,
    Failed,
}

/// Get a list of Network Manager devices.
///
/// # Examples
///
/// ```
/// let devices = network_manager::device::list().unwrap();
/// println!("{:?}", devices);
/// ```
pub fn list() -> Result<Vec<Device>, String> {
    let connection = Connection::get_private(BusType::System).unwrap();

    let path = manager_path(&connection, NM_SERVICE_PATH);

    let devices = path.get(NM_SERVICE_INTERFACE, "Devices").unwrap();

    let device_paths = variant_to_string_list(devices).unwrap();

    let mut result = Vec::new();

    for device_path in device_paths {
        let path = manager_path(&connection, &device_path);

        let interface = device_string(&path, "Interface").unwrap();

        let device_type = DeviceType::from_i64(device_i64(&path, "DeviceType").unwrap());

        let state = DeviceState::from_i64(device_i64(&path, "State").unwrap());

        let real = device_bool(&path, "Real").unwrap();

        let device = Device {
            interface: interface,
            path: device_path.clone(),
            device_type: device_type,
            state: state,
            real: real,
        };

        result.push(device);
    }

    Ok(result)
}

#[test]
fn test_list_function() {
    let devices = list().unwrap();
    assert!(devices.len() > 0);
}

/// Enables a Network Manager device.
///
/// # Examples
///
/// ```
/// let devices = network_manager::device::list().unwrap();
/// let device = &devices[0];
/// let state = network_manager::device::enable(device, 10).unwrap();
/// println!("{:?}", state);
/// ```
pub fn enable(c: &Device, t: i32) -> Result<DeviceState, String> {
    // Enable device

    if t != 0 {
        // Wait until the device state is 'Activated' or
        // until the time has elapsed
    }

    Ok(DeviceState::Activated)
}

/// Disables a Network Manager device.
///
/// # Examples
///
/// ```
/// let devices = network_manager::device::list().unwrap();
/// let device = &devices[0];
/// let state = network_manager::device::disable(device, 10).unwrap();
/// println!("{:?}", state);
/// ```
pub fn disable(c: &Device, t: i32) -> Result<DeviceState, String> {
    // Disable device

    if t != 0 {
        // Wait until the device state is 'Unavailable' or
        // until the time has elapsed
    }

    Ok(DeviceState::Unavailable)
}

#[inline]
fn device_string(path: &ConnPath<&Connection>, property: &str) -> Option<String> {
    property_as_string(path, NM_DEVICE_INTERFACE, property)
}

#[inline]
fn device_i64(path: &ConnPath<&Connection>, property: &str) -> Option<i64> {
    property_as_i64(path, NM_DEVICE_INTERFACE, property)
}

#[inline]
fn device_bool(path: &ConnPath<&Connection>, property: &str) -> Option<bool> {
    property_as_bool(path, NM_DEVICE_INTERFACE, property)
}
<commit_msg>Using Rust From trait for converting from D-Bus enum numbers to DeviceState and DeviceType<commit_after>use dbus::{Connection, ConnPath, BusType};
use dbus::stdintf::OrgFreedesktopDBusProperties;

use general::{NM_DEVICE_INTERFACE, NM_SERVICE_INTERFACE, NM_SERVICE_PATH};
use dbus_helper::{variant_to_string_list, manager_path, property_as_string, property_as_i64,
                  property_as_bool};

#[derive(Debug)]
pub struct Device {
    interface: String,
    path: String,
    device_type: DeviceType,
    state: DeviceState,
    real: bool,
}

impl From<i64> for DeviceState {
    fn from(state: i64) -> Self {
        match state {
            0 => DeviceState::Unknown,
            10 => DeviceState::Unmanaged,
            20 => DeviceState::Unavailable,
            30 => DeviceState::Disconnected,
            100 => DeviceState::Activated,
            110 => DeviceState::Deactivating,
            120 => DeviceState::Failed,
            _ => DeviceState::Unknown,

        }
    }
}

#[derive(Debug)]
pub enum DeviceType {
    Unknown,
    Generic,
    Ethernet,
    WiFi,
    Bridge,
}

impl From<i64> for DeviceType {
    fn from(state: i64) -> Self {
        match state {
            0 => DeviceType::Unknown,
            14 => DeviceType::Generic,
            1 => DeviceType::Ethernet,
            2 => DeviceType::WiFi,
            13 => DeviceType::Bridge,
            _ => DeviceType::Unknown,

        }
    }
}

#[derive(Debug)]
pub enum DeviceState {
    Unknown,
    Unmanaged,
    Unavailable,
    Disconnected,
    Activated,
    Deactivating,
    Failed,
}

/// Get a list of Network Manager devices.
///
/// # Examples
///
/// ```
/// let devices = network_manager::device::list().unwrap();
/// println!("{:?}", devices);
/// ```
pub fn list() -> Result<Vec<Device>, String> {
    let connection = Connection::get_private(BusType::System).unwrap();

    let path = manager_path(&connection, NM_SERVICE_PATH);

    let devices = path.get(NM_SERVICE_INTERFACE, "Devices").unwrap();

    let device_paths = variant_to_string_list(devices).unwrap();

    let mut result = Vec::new();

    for device_path in device_paths {
        let path = manager_path(&connection, &device_path);

        let interface = device_string(&path, "Interface").unwrap();

        let device_type = DeviceType::from(device_i64(&path, "DeviceType").unwrap());

        let state = DeviceState::from(device_i64(&path, "State").unwrap());

        let real = device_bool(&path, "Real").unwrap();

        let device = Device {
            interface: interface,
            path: device_path.clone(),
            device_type: device_type,
            state: state,
            real: real,
        };

        result.push(device);
    }

    Ok(result)
}

#[test]
fn test_list_function() {
    let devices = list().unwrap();
    assert!(devices.len() > 0);
}

/// Enables a Network Manager device.
///
/// # Examples
///
/// ```
/// let devices = network_manager::device::list().unwrap();
/// let device = &devices[0];
/// let state = network_manager::device::enable(device, 10).unwrap();
/// println!("{:?}", state);
/// ```
pub fn enable(c: &Device, t: i32) -> Result<DeviceState, String> {
    // Enable device

    if t != 0 {
        // Wait until the device state is 'Activated' or
        // until the time has elapsed
    }

    Ok(DeviceState::Activated)
}

/// Disables a Network Manager device.
///
/// # Examples
///
/// ```
/// let devices = network_manager::device::list().unwrap();
/// let device = &devices[0];
/// let state = network_manager::device::disable(device, 10).unwrap();
/// println!("{:?}", state);
/// ```
pub fn disable(c: &Device, t: i32) -> Result<DeviceState, String> {
    // Disable device

    if t != 0 {
        // Wait until the device state is 'Unavailable' or
        // until the time has elapsed
    }

    Ok(DeviceState::Unavailable)
}

#[inline]
fn device_string(path: &ConnPath<&Connection>, property: &str) -> Option<String> {
    property_as_string(path, NM_DEVICE_INTERFACE, property)
}

#[inline]
fn device_i64(path: &ConnPath<&Connection>, property: &str) -> Option<i64> {
    property_as_i64(path, NM_DEVICE_INTERFACE, property)
}

#[inline]
fn device_bool(path: &ConnPath<&Connection>, property: &str) -> Option<bool> {
    property_as_bool(path, NM_DEVICE_INTERFACE, property)
}
<|endoftext|>


<commit_before>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

use ::engine::AppInfo;
use ::resource::ResourceManager;
use ::window::WindowManager;
use ::util::Logger;

use std::cell::RefCell;
use std::rc::Rc;
use std::boxed::Box;
use std::process;

/*===============================================================================================*/
/*------STATIC VARIABLES-------------------------------------------------------------------------*/
/*===============================================================================================*/

static mut APP_POINTER: Option <*mut App> = None;

/*===============================================================================================*/
/*------APP STRUCT-------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The app
///
/// This is the main control center of ionCore.
/// It is in charge of initialization, updating, and shutdown of all modules,
/// as well as the handing of any inter-module communication.
pub struct App {

    // Public
    /// The application info.
    pub app_info: AppInfo,
    /// The resource manager.
    pub resource_mgr: Rc<RefCell<ResourceManager>>,
    /// The window manager.
    pub window_mgr: Rc<RefCell<WindowManager>>,
}

/*===============================================================================================*/
/*------APP PUBLIC STATIC METHODS----------------------------------------------------------------*/
/*===============================================================================================*/

impl App {

    /// Initializes the app
    pub fn init (app_info: AppInfo) {

        // Check if not already initialized
        if !App::is_initialized () {

            Logger::init ("./ionCore.log", true).unwrap ();
            info! ("Initializing ionCore | Version: {}", env! ("CARGO_PKG_VERSION"));

            let ab = Box::new (App {

                app_info: app_info,
                resource_mgr: Rc::new (RefCell::new (ResourceManager::new ())),
                window_mgr: Rc::new (RefCell::new (WindowManager::new ())),
            });

            unsafe {APP_POINTER = Some (Box::into_raw (ab))};

            // Init the managers
            App::_init_managers ();
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Checks if the app has been initialized.
    ///
    /// # Return value
    /// A bool returning whether the app has been initialized.
    pub fn is_initialized () -> bool {

        unsafe {

            match APP_POINTER {

                Some (pointer) => !pointer.is_null (),
                None => false
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Gets a copy of the AppInfo instance.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::engine::{App, AppInfo};
    /// # App::init (AppInfo::new ());
    /// let app_info = App::get_app_info ().unwrap ();
    pub fn get_app_info () -> Result<AppInfo, ()> {

        // Check if app is initialized
        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()}.app_info.clone ());
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Sets the AppInfo instance.
    pub fn set_app_info (app_info: AppInfo) {

        // Check if app is inistalized
        if App::is_initialized () {
            unsafe {&mut *APP_POINTER.unwrap ()}.app_info = app_info;
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a pointer to the resource manager instance.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::engine::{App, AppInfo};
    /// # App::init (AppInfo::new ());
    /// let resource_mgr = App::get_resource_manager ().unwrap ();
    pub fn get_resource_manager () -> Result<Rc<RefCell<ResourceManager>>, ()> {

        // Check if app is initialized
        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()}.resource_mgr.clone ());
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a pointer to the window manager instance.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::engine::{App, AppInfo};
    /// # App::init (AppInfo::new ());
    /// let window_mgr = App::get_window_manager ().unwrap ();
    pub fn get_window_manager () -> Result<Rc<RefCell<WindowManager>>, ()> {

        // Check if the app is is_initialized
        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()}.window_mgr.clone ());
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Releases all resources, and exits the application.
    pub fn exit () {

        // Check if app is initialized
        if App::is_initialized () {

            info! ("Shutting down ion Core.");

            // Release the managers
            App::_release_managers ();

            unsafe {

                drop (Box::from_raw (APP_POINTER.unwrap ()));
                APP_POINTER = None;
            };

            // Release the logger, and shutdown the application
            info! ("Terminating the application.");
            Logger::release ();

            process::exit (0);
        }
    }

/*===============================================================================================*/
/*------APP PRIVATE STATIC METHODS---------------------------------------------------------------*/
/*===============================================================================================*/

    // Initializes the various managers.
    fn _init_managers () {

        // Get a reference to all managers.
        let resource_mgr = App::get_resource_manager ().unwrap ();
        let window_mgr   = App::get_window_manager   ().unwrap ();

        // Init the managers
        resource_mgr.borrow_mut ().init ();
        window_mgr.borrow_mut   ().init ();
    }

/*-----------------------------------------------------------------------------------------------*/

    // Releases the managers
    fn _release_managers () {

        // Get a reference to all managers.
        let window_mgr = App::get_window_manager ().unwrap ();

        // Release the managers
        window_mgr.borrow_mut ().release ();
    }
}
<commit_msg>Added main app loop<commit_after>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

use ::engine::AppInfo;
use ::resource::ResourceManager;
use ::window::WindowManager;
use ::util::Logger;

use std::cell::RefCell;
use std::rc::Rc;
use std::boxed::Box;
use std::process;

/*===============================================================================================*/
/*------STATIC VARIABLES-------------------------------------------------------------------------*/
/*===============================================================================================*/

static mut APP_POINTER: Option <*mut App> = None;

/*===============================================================================================*/
/*------APP STRUCT-------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The app
///
/// This is the main control center of ionCore.
/// It is in charge of initialization, updating, and shutdown of all modules,
/// as well as the handing of any inter-module communication.
pub struct App {

    // Public
    /// The application info.
    pub app_info: AppInfo,
    /// The resource manager.
    pub resource_mgr: Rc<RefCell<ResourceManager>>,
    /// The window manager.
    pub window_mgr: Rc<RefCell<WindowManager>>,

    // Private
    _is_in_main_loop: bool,
    _should_exit: bool,
}

/*===============================================================================================*/
/*------APP PUBLIC STATIC METHODS----------------------------------------------------------------*/
/*===============================================================================================*/

impl App {

    /// Initializes the app
    pub fn init (app_info: AppInfo) {

        // Check if not already initialized
        if !App::is_initialized () {

            Logger::init ("./ionCore.log", true).unwrap ();
            info! ("Initializing ionCore | Version: {}", env! ("CARGO_PKG_VERSION"));

            let ab = Box::new (App {

                app_info: app_info,
                resource_mgr: Rc::new (RefCell::new (ResourceManager::new ())),
                window_mgr: Rc::new (RefCell::new (WindowManager::new ())),
                _is_in_main_loop: false,
                _should_exit: false,
            });

            unsafe {APP_POINTER = Some (Box::into_raw (ab))};

            // Init the managers
            App::_init_managers ();
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Checks if the app has been initialized.
    ///
    /// # Return value
    /// A bool returning whether the app has been initialized.
    pub fn is_initialized () -> bool {

        unsafe {

            match APP_POINTER {

                Some (pointer) => !pointer.is_null (),
                None => false
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Gets a copy of the AppInfo instance.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::engine::{App, AppInfo};
    /// # App::init (AppInfo::new ());
    /// let app_info = App::get_app_info ().unwrap ();
    pub fn get_app_info () -> Result<AppInfo, ()> {

        // Check if app is initialized
        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()}.app_info.clone ());
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Sets the AppInfo instance.
    pub fn set_app_info (app_info: AppInfo) {

        // Check if app is inistalized
        if App::is_initialized () {
            unsafe {&mut *APP_POINTER.unwrap ()}.app_info = app_info;
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a pointer to the resource manager instance.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::engine::{App, AppInfo};
    /// # App::init (AppInfo::new ());
    /// let resource_mgr = App::get_resource_manager ().unwrap ();
    pub fn get_resource_manager () -> Result<Rc<RefCell<ResourceManager>>, ()> {

        // Check if app is initialized
        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()}.resource_mgr.clone ());
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a pointer to the window manager instance.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::engine::{App, AppInfo};
    /// # App::init (AppInfo::new ());
    /// let window_mgr = App::get_window_manager ().unwrap ();
    pub fn get_window_manager () -> Result<Rc<RefCell<WindowManager>>, ()> {

        // Check if the app is is_initialized
        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()}.window_mgr.clone ());
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// The main app loop.
    pub fn run () {

        if App::is_initialized () {

            unsafe {&mut *APP_POINTER.unwrap ()}._is_in_main_loop = true;

            loop {

                let should_exit = unsafe {&*APP_POINTER.unwrap ()}._should_exit;

                if !should_exit {

                    App::_on_pre_render ();
                    App::_on_render ();
                    App::_on_post_render ();
                }

                else {

                    unsafe {&mut *APP_POINTER.unwrap ()}._is_in_main_loop = false;
                    return;
                }
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Releases all resources, and exits the application.
    pub fn exit () {

        // Check if app is initialized
        if App::is_initialized () {

            // Check if in main loop
            if unsafe {&*APP_POINTER.unwrap ()}._is_in_main_loop {

                info! ("Exiting main loop.");
                unsafe {&mut *APP_POINTER.unwrap ()}._should_exit = true;
            }

            else {

                info! ("Shutting down ion Core.");

                // Release the managers
                App::_release_managers ();

                unsafe {

                    drop (Box::from_raw (APP_POINTER.unwrap ()));
                    APP_POINTER = None;
                };

                // Release the logger, and shutdown the application
                info! ("Terminating the application.");
                Logger::release ();

                process::exit (0);
            }
        }
    }

/*===============================================================================================*/
/*------APP PRIVATE STATIC METHODS---------------------------------------------------------------*/
/*===============================================================================================*/

    // Initializes the various managers.
    fn _init_managers () {

        // Get a reference to all managers.
        let resource_mgr = App::get_resource_manager ().unwrap ();
        let window_mgr   = App::get_window_manager   ().unwrap ();

        // Init the managers
        resource_mgr.borrow_mut ().init ();
        window_mgr.borrow_mut   ().init ();
    }

/*-----------------------------------------------------------------------------------------------*/

    // On pre render
    fn _on_pre_render () {

    }

/*-----------------------------------------------------------------------------------------------*/

    // On render
    fn _on_render () {

    }

/*-----------------------------------------------------------------------------------------------*/

    // On post render
    fn _on_post_render () {

    }

/*-----------------------------------------------------------------------------------------------*/

    // Releases the managers
    fn _release_managers () {

        // Get a reference to all managers.
        let window_mgr = App::get_window_manager ().unwrap ();

        // Release the managers
        window_mgr.borrow_mut ().release ();
    }
}
<|endoftext|>


<commit_before>//! The `EventLoop` struct and assorted supporting types, including `ControlFlow`.
//!
//! If you want to send custom events to the event loop, use [`EventLoop::create_proxy()`][create_proxy]
//! to acquire an [`EventLoopProxy`][event_loop_proxy] and call its [`send_event`][send_event] method.
//!
//! See the root-level documentation for information on how to create and use an event loop to
//! handle events.
//!
//! [create_proxy]: crate::event_loop::EventLoop::create_proxy
//! [event_loop_proxy]: crate::event_loop::EventLoopProxy
//! [send_event]: crate::event_loop::EventLoopProxy::send_event
use instant::Instant;
use std::ops::Deref;
use std::{error, fmt};

use crate::{event::Event, monitor::MonitorHandle, platform_impl};

/// Provides a way to retrieve events from the system and from the windows that were registered to
/// the events loop.
///
/// An `EventLoop` can be seen more or less as a "context". Calling `EventLoop::new()`
/// initializes everything that will be required to create windows. For example on Linux creating
/// an event loop opens a connection to the X or Wayland server.
///
/// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs.
///
/// Note that the `EventLoop` cannot be shared across threads (due to platform-dependant logic
/// forbidding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the
/// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the
/// `EventLoopProxy` allows you to wake up an `EventLoop` from another thread.
///
pub struct EventLoop<T: 'static> {
    pub(crate) event_loop: platform_impl::EventLoop<T>,
    pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
}

/// Target that associates windows with an `EventLoop`.
///
/// This type exists to allow you to create new windows while Winit executes
/// your callback. `EventLoop` will coerce into this type (`impl<T> Deref for
/// EventLoop<T>`), so functions that take this as a parameter can also take
/// `&EventLoop`.
pub struct EventLoopWindowTarget<T: 'static> {
    pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
    pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
}

impl<T> fmt::Debug for EventLoop<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("EventLoop { .. }")
    }
}

impl<T> fmt::Debug for EventLoopWindowTarget<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("EventLoopWindowTarget { .. }")
    }
}

/// Set by the user callback given to the `EventLoop::run` method.
///
/// Indicates the desired behavior of the event loop after [`Event::RedrawEventsCleared`][events_cleared]
/// is emitted. Defaults to `Poll`.
///
/// ## Persistency
/// Almost every change is persistent between multiple calls to the event loop closure within a
/// given run loop. The only exception to this is `Exit` which, once set, cannot be unset. Changes
/// are **not** persistent between multiple calls to `run_return` - issuing a new call will reset
/// the control flow to `Poll`.
///
/// [events_cleared]: crate::event::Event::RedrawEventsCleared
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ControlFlow {
    /// When the current loop iteration finishes, immediately begin a new iteration regardless of
    /// whether or not new events are available to process.
    ///
    /// For web, events are queued and usually sent when `requestAnimationFrame` fires but sometimes
    /// the events in the queue may be sent before the next `requestAnimationFrame` callback, for
    /// example when the scaling of the page has changed.
    Poll,
    /// When the current loop iteration finishes, suspend the thread until another event arrives.
    Wait,
    /// When the current loop iteration finishes, suspend the thread until either another event
    /// arrives or the given time is reached.
    WaitUntil(Instant),
    /// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
    /// `control_flow` cannot be changed from `Exit`, and any future attempts to do so will result
    /// in the `control_flow` parameter being reset to `Exit`.
    Exit,
}

impl Default for ControlFlow {
    #[inline(always)]
    fn default() -> ControlFlow {
        ControlFlow::Poll
    }
}

impl EventLoop<()> {
    /// Builds a new event loop with a `()` as the user event type.
    ///
    /// ***For cross-platform compatibility, the `EventLoop` must be created on the main thread.***
    /// Attempting to create the event loop on a different thread will panic. This restriction isn't
    /// strictly necessary on all platforms, but is imposed to eliminate any nasty surprises when
    /// porting to platforms that require it. `EventLoopExt::new_any_thread` functions are exposed
    /// in the relevant `platform` module if the target platform supports creating an event loop on
    /// any thread.
    ///
    /// Usage will result in display backend initialisation, this can be controlled on linux
    /// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`.
    /// If it is not set, winit will try to connect to a wayland connection, and if it fails will
    /// fallback on x11. If this variable is set with any other value, winit will panic.
    ///
    /// ## Platform-specific
    ///
    /// - **iOS:** Can only be called on the main thread.
    pub fn new() -> EventLoop<()> {
        EventLoop::<()>::with_user_event()
    }
}

impl<T> EventLoop<T> {
    /// Builds a new event loop.
    ///
    /// All caveats documented in [`EventLoop::new`] apply to this function.
    ///
    /// ## Platform-specific
    ///
    /// - **iOS:** Can only be called on the main thread.
    pub fn with_user_event() -> EventLoop<T> {
        EventLoop {
            event_loop: platform_impl::EventLoop::new(),
            _marker: ::std::marker::PhantomData,
        }
    }

    /// Hijacks the calling thread and initializes the winit event loop with the provided
    /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to
    /// access any data from the calling context.
    ///
    /// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the
    /// event loop's behavior.
    ///
    /// Any values not passed to this function will *not* be dropped.
    ///
    /// [`ControlFlow`]: crate::event_loop::ControlFlow
    #[inline]
    pub fn run<F>(self, event_handler: F) -> !
    where
        F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
    {
        self.event_loop.run(event_handler)
    }

    /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop.
    pub fn create_proxy(&self) -> EventLoopProxy<T> {
        EventLoopProxy {
            event_loop_proxy: self.event_loop.create_proxy(),
        }
    }
}

impl<T> Deref for EventLoop<T> {
    type Target = EventLoopWindowTarget<T>;
    fn deref(&self) -> &EventLoopWindowTarget<T> {
        self.event_loop.window_target()
    }
}

impl<T> EventLoopWindowTarget<T> {
    /// Returns the list of all the monitors available on the system.
    #[inline]
    pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
        self.p
            .available_monitors()
            .into_iter()
            .map(|inner| MonitorHandle { inner })
    }

    /// Returns the primary monitor of the system.
    ///
    /// Returns `None` if it can't identify any monitor as a primary one.
    ///
    /// ## Platform-specific
    ///
    /// **Wayland:** Always returns `None`.
    #[inline]
    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
        self.p.primary_monitor()
    }
}

/// Used to send custom events to `EventLoop`.
pub struct EventLoopProxy<T: 'static> {
    event_loop_proxy: platform_impl::EventLoopProxy<T>,
}

impl<T: 'static> Clone for EventLoopProxy<T> {
    fn clone(&self) -> Self {
        Self {
            event_loop_proxy: self.event_loop_proxy.clone(),
        }
    }
}

impl<T: 'static> EventLoopProxy<T> {
    /// Send an event to the `EventLoop` from which this proxy was created. This emits a
    /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
    /// function.
    ///
    /// Returns an `Err` if the associated `EventLoop` no longer exists.
    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
        self.event_loop_proxy.send_event(event)
    }
}

impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("EventLoopProxy { .. }")
    }
}

/// The error that is returned when an `EventLoopProxy` attempts to wake up an `EventLoop` that
/// no longer exists. Contains the original event given to `send_event`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct EventLoopClosed<T>(pub T);

impl<T> fmt::Display for EventLoopClosed<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("Tried to wake up a closed `EventLoop`")
    }
}

impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {}
<commit_msg>Clarify ControlFlow::Poll doc for web (#1725)<commit_after>//! The `EventLoop` struct and assorted supporting types, including `ControlFlow`.
//!
//! If you want to send custom events to the event loop, use [`EventLoop::create_proxy()`][create_proxy]
//! to acquire an [`EventLoopProxy`][event_loop_proxy] and call its [`send_event`][send_event] method.
//!
//! See the root-level documentation for information on how to create and use an event loop to
//! handle events.
//!
//! [create_proxy]: crate::event_loop::EventLoop::create_proxy
//! [event_loop_proxy]: crate::event_loop::EventLoopProxy
//! [send_event]: crate::event_loop::EventLoopProxy::send_event
use instant::Instant;
use std::ops::Deref;
use std::{error, fmt};

use crate::{event::Event, monitor::MonitorHandle, platform_impl};

/// Provides a way to retrieve events from the system and from the windows that were registered to
/// the events loop.
///
/// An `EventLoop` can be seen more or less as a "context". Calling `EventLoop::new()`
/// initializes everything that will be required to create windows. For example on Linux creating
/// an event loop opens a connection to the X or Wayland server.
///
/// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs.
///
/// Note that the `EventLoop` cannot be shared across threads (due to platform-dependant logic
/// forbidding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the
/// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the
/// `EventLoopProxy` allows you to wake up an `EventLoop` from another thread.
///
pub struct EventLoop<T: 'static> {
    pub(crate) event_loop: platform_impl::EventLoop<T>,
    pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
}

/// Target that associates windows with an `EventLoop`.
///
/// This type exists to allow you to create new windows while Winit executes
/// your callback. `EventLoop` will coerce into this type (`impl<T> Deref for
/// EventLoop<T>`), so functions that take this as a parameter can also take
/// `&EventLoop`.
pub struct EventLoopWindowTarget<T: 'static> {
    pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
    pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
}

impl<T> fmt::Debug for EventLoop<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("EventLoop { .. }")
    }
}

impl<T> fmt::Debug for EventLoopWindowTarget<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("EventLoopWindowTarget { .. }")
    }
}

/// Set by the user callback given to the `EventLoop::run` method.
///
/// Indicates the desired behavior of the event loop after [`Event::RedrawEventsCleared`][events_cleared]
/// is emitted. Defaults to `Poll`.
///
/// ## Persistency
/// Almost every change is persistent between multiple calls to the event loop closure within a
/// given run loop. The only exception to this is `Exit` which, once set, cannot be unset. Changes
/// are **not** persistent between multiple calls to `run_return` - issuing a new call will reset
/// the control flow to `Poll`.
///
/// [events_cleared]: crate::event::Event::RedrawEventsCleared
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ControlFlow {
    /// When the current loop iteration finishes, immediately begin a new iteration regardless of
    /// whether or not new events are available to process.
    ///
    /// ## Platform-specific
    /// - **Web:** Events are queued and usually sent when `requestAnimationFrame` fires but sometimes
    ///   the events in the queue may be sent before the next `requestAnimationFrame` callback, for
    ///   example when the scaling of the page has changed. This should be treated as an implementation
    ///   detail which should not be relied on.
    Poll,
    /// When the current loop iteration finishes, suspend the thread until another event arrives.
    Wait,
    /// When the current loop iteration finishes, suspend the thread until either another event
    /// arrives or the given time is reached.
    WaitUntil(Instant),
    /// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
    /// `control_flow` cannot be changed from `Exit`, and any future attempts to do so will result
    /// in the `control_flow` parameter being reset to `Exit`.
    Exit,
}

impl Default for ControlFlow {
    #[inline(always)]
    fn default() -> ControlFlow {
        ControlFlow::Poll
    }
}

impl EventLoop<()> {
    /// Builds a new event loop with a `()` as the user event type.
    ///
    /// ***For cross-platform compatibility, the `EventLoop` must be created on the main thread.***
    /// Attempting to create the event loop on a different thread will panic. This restriction isn't
    /// strictly necessary on all platforms, but is imposed to eliminate any nasty surprises when
    /// porting to platforms that require it. `EventLoopExt::new_any_thread` functions are exposed
    /// in the relevant `platform` module if the target platform supports creating an event loop on
    /// any thread.
    ///
    /// Usage will result in display backend initialisation, this can be controlled on linux
    /// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`.
    /// If it is not set, winit will try to connect to a wayland connection, and if it fails will
    /// fallback on x11. If this variable is set with any other value, winit will panic.
    ///
    /// ## Platform-specific
    ///
    /// - **iOS:** Can only be called on the main thread.
    pub fn new() -> EventLoop<()> {
        EventLoop::<()>::with_user_event()
    }
}

impl<T> EventLoop<T> {
    /// Builds a new event loop.
    ///
    /// All caveats documented in [`EventLoop::new`] apply to this function.
    ///
    /// ## Platform-specific
    ///
    /// - **iOS:** Can only be called on the main thread.
    pub fn with_user_event() -> EventLoop<T> {
        EventLoop {
            event_loop: platform_impl::EventLoop::new(),
            _marker: ::std::marker::PhantomData,
        }
    }

    /// Hijacks the calling thread and initializes the winit event loop with the provided
    /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to
    /// access any data from the calling context.
    ///
    /// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the
    /// event loop's behavior.
    ///
    /// Any values not passed to this function will *not* be dropped.
    ///
    /// [`ControlFlow`]: crate::event_loop::ControlFlow
    #[inline]
    pub fn run<F>(self, event_handler: F) -> !
    where
        F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
    {
        self.event_loop.run(event_handler)
    }

    /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop.
    pub fn create_proxy(&self) -> EventLoopProxy<T> {
        EventLoopProxy {
            event_loop_proxy: self.event_loop.create_proxy(),
        }
    }
}

impl<T> Deref for EventLoop<T> {
    type Target = EventLoopWindowTarget<T>;
    fn deref(&self) -> &EventLoopWindowTarget<T> {
        self.event_loop.window_target()
    }
}

impl<T> EventLoopWindowTarget<T> {
    /// Returns the list of all the monitors available on the system.
    #[inline]
    pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
        self.p
            .available_monitors()
            .into_iter()
            .map(|inner| MonitorHandle { inner })
    }

    /// Returns the primary monitor of the system.
    ///
    /// Returns `None` if it can't identify any monitor as a primary one.
    ///
    /// ## Platform-specific
    ///
    /// **Wayland:** Always returns `None`.
    #[inline]
    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
        self.p.primary_monitor()
    }
}

/// Used to send custom events to `EventLoop`.
pub struct EventLoopProxy<T: 'static> {
    event_loop_proxy: platform_impl::EventLoopProxy<T>,
}

impl<T: 'static> Clone for EventLoopProxy<T> {
    fn clone(&self) -> Self {
        Self {
            event_loop_proxy: self.event_loop_proxy.clone(),
        }
    }
}

impl<T: 'static> EventLoopProxy<T> {
    /// Send an event to the `EventLoop` from which this proxy was created. This emits a
    /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
    /// function.
    ///
    /// Returns an `Err` if the associated `EventLoop` no longer exists.
    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
        self.event_loop_proxy.send_event(event)
    }
}

impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("EventLoopProxy { .. }")
    }
}

/// The error that is returned when an `EventLoopProxy` attempts to wake up an `EventLoop` that
/// no longer exists. Contains the original event given to `send_event`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct EventLoopClosed<T>(pub T);

impl<T> fmt::Display for EventLoopClosed<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("Tried to wake up a closed `EventLoop`")
    }
}

impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {}
<|endoftext|>