<commit_before>use message::{Message};
use MiliSec;
use state::State;

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

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

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

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens.unwrap_or(FIRST_OPENS_DEFAULT) {
            self.is_message_the_first_among_patterns(message)
        } else {
            true
        }
    }

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

    fn is_message_the_first_among_patterns(&self, message: &Message) -> bool {
        if let Some(id) = message.name() {
            self.patterns.first().unwrap() == message.uuid() || self.patterns.first().unwrap() == id
        } else {
            self.patterns.first().unwrap() == message.uuid()
        }
    }

    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.unwrap_or(LAST_CLOSES_DEFAULT) {
            self.patterns.last().unwrap() == state.messages().last().unwrap().uuid()
        } 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: MiliSec) -> ConditionsBuilder {
        ConditionsBuilder {
            conditions: Conditions::new(timeout)
        }
    }

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

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

    pub fn last_closes(&mut self, last_closes: bool) -> &mut ConditionsBuilder {
        self.conditions.last_closes = Some(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;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = 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).build();
        let msg_which_should_be_ignored = MessageBuilder::new(&msg_id2).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 = 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 condition = ConditionsBuilder::new(timeout).patterns(patterns).last_closes(true).build();
        let msg_1 = MessageBuilder::new(&msg_id1).build();
        let msg_closing = Rc::new(MessageBuilder::new(&msg_id2).build());
        assert_true!(condition.is_opening(&msg_1));
        state.open();
        state.add_message(msg_closing);
        assert_true!(condition.is_closing(&mut state));
    }

    #[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, 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, 100);
        assert_eq!(conditions.renew_timeout, Some(50));
        assert_eq!(conditions.first_opens, Some(true));
        assert_eq!(conditions.last_closes, Some(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 = 100;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let condition = ConditionsBuilder::new(timeout).build();
        let msg = MessageBuilder::new(&msg_id).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 = 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).name(Some(&msg_id)).build();
        assert_true!(condition.is_opening(&msg));
    }
}

mod deser {
    use MiliSec;
    use super::Conditions;
    use serde::de::{
        Deserialize,
        Deserializer,
        Error,
        MapVisitor,
        Visitor
    };

    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<MiliSec> = None;
            let mut renew_timeout = None;
            let mut first_opens = None;
            let mut last_closes = None;
            let mut max_size = None;
            let mut patterns = None;

            loop {
                match try!(visitor.visit_key()) {
                    Some(Field::Timeout) => { timeout = Some(try!(visitor.visit_value())); }
                    Some(Field::RenewTimeout) => { renew_timeout = Some(try!(visitor.visit_value())); }
                    Some(Field::FirstOpens) => { first_opens = Some(try!(visitor.visit_value())); }
                    Some(Field::LastCloses) => { last_closes = Some(try!(visitor.visit_value())); }
                    Some(Field::MaxSize) => { max_size = Some(try!(visitor.visit_value())); }
                    Some(Field::Patterns) => { patterns = Some(try!(visitor.visit_value())); }
                    None => { break; }
                }
            }

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

            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: check the message's name when close condition is being checked<commit_after>use message::{Message};
use MiliSec;
use state::State;

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

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

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

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens.unwrap_or(FIRST_OPENS_DEFAULT) {
            self.is_message_the_first_among_patterns(message)
        } else {
            true
        }
    }

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

    fn is_message_the_first_among_patterns(&self, message: &Message) -> bool {
        if let Some(id) = message.name() {
            self.patterns.first().unwrap() == message.uuid() || self.patterns.first().unwrap() == id
        } else {
            self.patterns.first().unwrap() == message.uuid()
        }
    }

    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.unwrap_or(LAST_CLOSES_DEFAULT) {
            self.is_message_the_last_among_patterns(state)
        } else {
            false
        }
    }

    fn is_message_the_last_among_patterns(&self, state: &State) -> bool {
        let last_message = state.messages().last().unwrap();
        if let Some(id) = last_message.name() {
            self.patterns.last().unwrap() == last_message.uuid() || self.patterns.last().unwrap() == id
        } else {
            self.patterns.last().unwrap() == last_message.uuid()
        }
    }

    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: MiliSec) -> ConditionsBuilder {
        ConditionsBuilder {
            conditions: Conditions::new(timeout)
        }
    }

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

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

    pub fn last_closes(&mut self, last_closes: bool) -> &mut ConditionsBuilder {
        self.conditions.last_closes = Some(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;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = 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).build();
        let msg_which_should_be_ignored = MessageBuilder::new(&msg_id2).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 = 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 condition = ConditionsBuilder::new(timeout).patterns(patterns).last_closes(true).build();
        let msg_1 = MessageBuilder::new(&msg_id1).build();
        let msg_closing = Rc::new(MessageBuilder::new(&msg_id2).build());
        assert_true!(condition.is_opening(&msg_1));
        state.open();
        state.add_message(msg_closing);
        assert_true!(condition.is_closing(&mut state));
    }

    #[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, 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, 100);
        assert_eq!(conditions.renew_timeout, Some(50));
        assert_eq!(conditions.first_opens, Some(true));
        assert_eq!(conditions.last_closes, Some(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 = 100;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let condition = ConditionsBuilder::new(timeout).build();
        let msg = MessageBuilder::new(&msg_id).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 = 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).name(Some(&msg_id)).build();
        assert_true!(condition.is_opening(&msg));
    }
}

mod deser {
    use MiliSec;
    use super::Conditions;
    use serde::de::{
        Deserialize,
        Deserializer,
        Error,
        MapVisitor,
        Visitor
    };

    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<MiliSec> = None;
            let mut renew_timeout = None;
            let mut first_opens = None;
            let mut last_closes = None;
            let mut max_size = None;
            let mut patterns = None;

            loop {
                match try!(visitor.visit_key()) {
                    Some(Field::Timeout) => { timeout = Some(try!(visitor.visit_value())); }
                    Some(Field::RenewTimeout) => { renew_timeout = Some(try!(visitor.visit_value())); }
                    Some(Field::FirstOpens) => { first_opens = Some(try!(visitor.visit_value())); }
                    Some(Field::LastCloses) => { last_closes = Some(try!(visitor.visit_value())); }
                    Some(Field::MaxSize) => { max_size = Some(try!(visitor.visit_value())); }
                    Some(Field::Patterns) => { patterns = Some(try!(visitor.visit_value())); }
                    None => { break; }
                }
            }

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

            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 message::{Message, PatternId};
use MiliSec;
use state::State;

const FIRST_OPENS_DEFAULT: bool = false;

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

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

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens.unwrap_or(FIRST_OPENS_DEFAULT) {
            self.patterns.first().unwrap() == message.uuid()
        } else {
            true
        }
    }

    pub fn is_closing(&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 {
        self.last_closes.map_or(false, |last_message_closes_the_context| {
            if last_message_closes_the_context {
                self.patterns.last().unwrap() == state.messages().last().unwrap().uuid()
            } 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 Builder {
    conditions: Conditions
}

impl Builder {
    pub fn new(timeout: MiliSec) -> Builder {
        Builder{
            conditions: Conditions::new(timeout)
        }
    }

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

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

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

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

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

#[cfg(test)]
mod test {
    use std::rc::Rc;

    use message;
    use message::{PatternId};
    use state::State;
    use super::Builder;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = 100;
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            PatternId::Uuid(msg_id1.clone()),
        ];
        let condition = Builder::new(timeout).patterns(patterns).first_opens(true).build();
        let msg_which_should_not_be_ignored = message::Builder::new(&msg_id1).build();
        let msg_which_should_be_ignored = message::Builder::new(&msg_id2).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 = 100;
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            PatternId::Uuid(msg_id1.clone()),
            PatternId::Uuid(msg_id2.clone()),
        ];
        let mut state = State::new();
        let condition = Builder::new(timeout).patterns(patterns).last_closes(true).build();
        let msg_1 = message::Builder::new(&msg_id1).build();
        let msg_closing = Rc::new(message::Builder::new(&msg_id2).build());
        assert_true!(condition.is_opening(&msg_1));
        state.open();
        state.add_message(msg_closing);
        assert_true!(condition.is_closing(&mut state));
    }
}
<commit_msg>Conditions: refactor is_closing_message()<commit_after>use message::{Message, PatternId};
use MiliSec;
use state::State;

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

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

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

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens.unwrap_or(FIRST_OPENS_DEFAULT) {
            self.patterns.first().unwrap() == message.uuid()
        } else {
            true
        }
    }

    pub fn is_closing(&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.unwrap_or(LAST_CLOSES_DEFAULT) {
            self.patterns.last().unwrap() == state.messages().last().unwrap().uuid()
        } 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 Builder {
    conditions: Conditions
}

impl Builder {
    pub fn new(timeout: MiliSec) -> Builder {
        Builder{
            conditions: Conditions::new(timeout)
        }
    }

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

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

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

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

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

#[cfg(test)]
mod test {
    use std::rc::Rc;

    use message;
    use message::{PatternId};
    use state::State;
    use super::Builder;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = 100;
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            PatternId::Uuid(msg_id1.clone()),
        ];
        let condition = Builder::new(timeout).patterns(patterns).first_opens(true).build();
        let msg_which_should_not_be_ignored = message::Builder::new(&msg_id1).build();
        let msg_which_should_be_ignored = message::Builder::new(&msg_id2).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 = 100;
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            PatternId::Uuid(msg_id1.clone()),
            PatternId::Uuid(msg_id2.clone()),
        ];
        let mut state = State::new();
        let condition = Builder::new(timeout).patterns(patterns).last_closes(true).build();
        let msg_1 = message::Builder::new(&msg_id1).build();
        let msg_closing = Rc::new(message::Builder::new(&msg_id2).build());
        assert_true!(condition.is_opening(&msg_1));
        state.open();
        state.add_message(msg_closing);
        assert_true!(condition.is_closing(&mut state));
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

use std;
use std::net::SocketAddr;
use std::sync::Arc;

use tokio_core::reactor::Core;
use tokio_core::net::TcpListener;
use tokio_core::io::Io;
use futures::{future, Future, Stream, Sink};
use futures::sync::mpsc;
use tokio_service::Service as TokioService;

use jsonrpc::{MetaIoHandler, Metadata};
use service::Service;
use line_codec::LineCodec;
use meta::{MetaExtractor, RequestContext, NoopExtractor};
use dispatch::{Dispatcher, SenderChannels, PeerMessageQueue};

pub struct Server<M: Metadata = ()> {
    listen_addr: SocketAddr,
    handler: Arc<MetaIoHandler<M>>,
    meta_extractor: Arc<MetaExtractor<M>>,
    channels: Arc<SenderChannels>,
}

impl<M: Metadata> Server<M> {
    pub fn new(addr: SocketAddr, handler: Arc<MetaIoHandler<M>>) -> Self {
        Server {
            listen_addr: addr,
            handler: handler,
            meta_extractor: Arc::new(NoopExtractor),
            channels: Default::default(),
        }
    }

    pub fn extractor(mut self, meta_extractor: Arc<MetaExtractor<M>>) -> Self {
        self.meta_extractor = meta_extractor;
        self
    }

    pub fn run(&self) -> std::io::Result<()> {
        let mut core = Core::new()?;
        let handle = core.handle();
        let meta_extractor = self.meta_extractor.clone();

        let listener = TcpListener::bind(&self.listen_addr, &handle)?;

        let connections = listener.incoming();
        let server = connections.for_each(move |(socket, peer_addr)| {
            trace!(target: "tcp", "Accepted incoming connection from {}", &peer_addr);

            let context = RequestContext { peer_addr: peer_addr };
            let meta = meta_extractor.extract(&context);

            let (writer, reader) = socket.framed(LineCodec).split();
            let service = self.spawn_service(peer_addr, meta);

            let responses = reader.and_then(
                move |req| service.call(req).then(|response|
                    match response {
                        Err(e) => {
                            warn!(target: "tcp", "Error while processing request: {:?}", e);
                            future::ok(String::new())
                        },
                        Ok(None) => {
                            trace!(target: "tcp", "JSON RPC request produced no response");
                            future::ok(String::new())
                        },
                        Ok(Some(response_data)) => {
                            trace!(target: "tcp", "Sent response: {}", &response_data);
                            future::ok(response_data)
                        }
                    }));

            let (sender, receiver) = mpsc::channel(65536);
            let mut channels = self.channels.lock().unwrap();
            channels.insert(peer_addr, sender.clone());

            let peer_message_queue = PeerMessageQueue::new(
                responses,
                receiver,
                peer_addr.clone(),
            );

            let server = writer.send_all(peer_message_queue).then(
                move |_| {
                    trace!(target: "tcp", "Peer {}: service finished", peer_addr);
                    Ok(())
                }
            );
            handle.spawn(server);

            Ok(())
        });
        core.run(server)
    }

    pub fn dispatcher(&self) -> Dispatcher {
        Dispatcher::new(self.channels.clone())
    }

    fn spawn_service(&self, peer_addr: SocketAddr, meta: M) -> Service<M> {
        Service::new(peer_addr.clone(), self.handler.clone(), meta)
    }
}
<commit_msg>remove channel from list once peer is disconnected<commit_after>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

use std;
use std::net::SocketAddr;
use std::sync::Arc;

use tokio_core::reactor::Core;
use tokio_core::net::TcpListener;
use tokio_core::io::Io;
use futures::{future, Future, Stream, Sink};
use futures::sync::mpsc;
use tokio_service::Service as TokioService;

use jsonrpc::{MetaIoHandler, Metadata};
use service::Service;
use line_codec::LineCodec;
use meta::{MetaExtractor, RequestContext, NoopExtractor};
use dispatch::{Dispatcher, SenderChannels, PeerMessageQueue};

pub struct Server<M: Metadata = ()> {
    listen_addr: SocketAddr,
    handler: Arc<MetaIoHandler<M>>,
    meta_extractor: Arc<MetaExtractor<M>>,
    channels: Arc<SenderChannels>,
}

impl<M: Metadata> Server<M> {
    pub fn new(addr: SocketAddr, handler: Arc<MetaIoHandler<M>>) -> Self {
        Server {
            listen_addr: addr,
            handler: handler,
            meta_extractor: Arc::new(NoopExtractor),
            channels: Default::default(),
        }
    }

    pub fn extractor(mut self, meta_extractor: Arc<MetaExtractor<M>>) -> Self {
        self.meta_extractor = meta_extractor;
        self
    }

    pub fn run(&self) -> std::io::Result<()> {
        let mut core = Core::new()?;
        let handle = core.handle();
        let meta_extractor = self.meta_extractor.clone();

        let listener = TcpListener::bind(&self.listen_addr, &handle)?;

        let connections = listener.incoming();
        let server = connections.for_each(move |(socket, peer_addr)| {
            trace!(target: "tcp", "Accepted incoming connection from {}", &peer_addr);

            let context = RequestContext { peer_addr: peer_addr };
            let meta = meta_extractor.extract(&context);

            let (writer, reader) = socket.framed(LineCodec).split();
            let service = self.spawn_service(peer_addr, meta);

            let responses = reader.and_then(
                move |req| service.call(req).then(|response|
                    match response {
                        Err(e) => {
                            warn!(target: "tcp", "Error while processing request: {:?}", e);
                            future::ok(String::new())
                        },
                        Ok(None) => {
                            trace!(target: "tcp", "JSON RPC request produced no response");
                            future::ok(String::new())
                        },
                        Ok(Some(response_data)) => {
                            trace!(target: "tcp", "Sent response: {}", &response_data);
                            future::ok(response_data)
                        }
                    }));

            let peer_message_queue = {
                let (sender, receiver) = mpsc::channel(65536);
                let mut channels = self.channels.lock().unwrap();
                channels.insert(peer_addr.clone(), sender.clone());

                PeerMessageQueue::new(
                    responses,
                    receiver,
                    peer_addr.clone(),
                )
            };

            let shared_channels = self.channels.clone();
            let server = writer.send_all(peer_message_queue).then(
                move |_| {
                    trace!(target: "tcp", "Peer {}: service finished", peer_addr);
                    let mut channels = shared_channels.lock().unwrap();
                    channels.remove(&peer_addr);
                    Ok(())
                }
            );
            handle.spawn(server);

            Ok(())
        });
        core.run(server)
    }

    pub fn dispatcher(&self) -> Dispatcher {
        Dispatcher::new(self.channels.clone())
    }

    fn spawn_service(&self, peer_addr: SocketAddr, meta: M) -> Service<M> {
        Service::new(peer_addr.clone(), self.handler.clone(), meta)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std;
use ffi;
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, ToPythonPointer};
use objects::PyObject;
use err::PyResult;

/// Conversion trait that allows various objects to be converted into Python objects.
pub trait ToPyObject<'p> {
    type ObjectType : PythonObject<'p> = PyObject<'p>;

    /// Converts self into a Python object.
    fn to_py_object(&self, py: Python<'p>) -> Self::ObjectType;

    /// Converts self into a Python object.
    ///
    /// May be more efficient than `to_py_object` in some cases because
    /// it can move out of the input object.
    #[inline]
    fn into_py_object(self, py: Python<'p>) -> Self::ObjectType
      where Self: Sized {
        self.to_py_object(py)
    }

    /// Converts self into a Python object and calls the specified closure
    /// on the native FFI pointer underlying the Python object.
    ///
    /// May be more efficient than `to_py_object` because it does not need
    /// to touch any reference counts when the input object already is a Python object.
    #[inline]
    fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
      where F: FnOnce(*mut ffi::PyObject) -> R {
        let obj = self.to_py_object(py).into_object();
        f(obj.as_ptr())
    }

    // FFI functions that accept a borrowed reference will use:
    //   input.with_borrowed_ptr(|obj| ffi::Call(obj)
    // 1) input is &PyObject
    //   -> with_borrowed_ptr() just forwards to the closure
    // 2) input is PyObject
    //   -> with_borrowed_ptr() just forwards to the closure
    // 3) input is &str, int, ...
    //   -> to_py_object() allocates new Python object; FFI call happens; PyObject::drop() calls Py_DECREF()

    // FFI functions that steal a reference will use:
    //   let input = try!(input.into_py_object()); ffi::Call(input.steal_ptr())
    // 1) input is &PyObject
    //   -> into_py_object() calls Py_INCREF
    // 2) input is PyObject
    //   -> into_py_object() is no-op
    // 3) input is &str, int, ...
    //   -> into_py_object() allocates new Python object
}

/// FromPyObject is implemented by various types that can be extracted from a Python object.
pub trait FromPyObject<'p> {
    fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, Self>;
}

// PyObject, PyModule etc.
// We support FromPyObject and ToPyObject for owned python references.
// This allows using existing Python objects in code that generically expects a value
// convertible to a Python object.

/// Identity conversion: allows using existing `PyObject` instances where
/// `ToPyObject` is expected.
impl <'p, 's> ToPyObject<'p> for PyObject<'s> {
    type ObjectType = PyObject<'p>;

    #[inline]
    fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> {
        self.clone().into_py_object(py)
    }

    #[inline]
    fn into_py_object(self, _py: Python<'p>) -> PyObject<'p> {
        // Transmute the lifetime.
        // This is safe, because both lifetime variables represent the same lifetime:
        // that of the python GIL acquisition.
        unsafe { std::mem::transmute(self) }
    }

    #[inline]
    fn with_borrowed_ptr<F, R>(&self, _py: Python<'p>, f: F) -> R
      where F: FnOnce(*mut ffi::PyObject) -> R {
        f(self.as_ptr())
    }
}

impl <'p, T> FromPyObject<'p> for T where T: PythonObjectWithCheckedDowncast<'p> {
    #[inline]
    fn from_py_object(s : &PyObject<'p>) -> PyResult<'p, T> {
        Ok(try!(s.clone().cast_into()))
    }
}

// &PyObject, &PyModule etc.
// We support FromPyObject and ToPyObject for borrowed python references.
// This allows using existing Python objects in code that generically expects a value
// convertible to a Python object.
impl <'p, 's, T: ?Sized> ToPyObject<'p> for &'s T where T: ToPyObject<'p> {
    type ObjectType = T::ObjectType;

    #[inline]
    fn to_py_object(&self, py: Python<'p>) -> T::ObjectType {
        <T as ToPyObject>::to_py_object(*self, py)
    }

    #[inline]
    fn into_py_object(self, py: Python<'p>) -> T::ObjectType {
        <T as ToPyObject>::to_py_object(self, py)
    }

    #[inline]
    fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
      where F: FnOnce(*mut ffi::PyObject) -> R {
        <T as ToPyObject>::with_borrowed_ptr(*self, py, f)
    }
}

<commit_msg>Adjust to breaking change rust-lang/rust#26728<commit_after>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std;
use ffi;
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, ToPythonPointer};
use objects::PyObject;
use err::PyResult;

/// Conversion trait that allows various objects to be converted into Python objects.
pub trait ToPyObject<'p> {
    type ObjectType : PythonObject<'p>;

    /// Converts self into a Python object.
    fn to_py_object(&self, py: Python<'p>) -> Self::ObjectType;

    /// Converts self into a Python object.
    ///
    /// May be more efficient than `to_py_object` in some cases because
    /// it can move out of the input object.
    #[inline]
    fn into_py_object(self, py: Python<'p>) -> Self::ObjectType
      where Self: Sized {
        self.to_py_object(py)
    }

    /// Converts self into a Python object and calls the specified closure
    /// on the native FFI pointer underlying the Python object.
    ///
    /// May be more efficient than `to_py_object` because it does not need
    /// to touch any reference counts when the input object already is a Python object.
    #[inline]
    fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
      where F: FnOnce(*mut ffi::PyObject) -> R {
        let obj = self.to_py_object(py).into_object();
        f(obj.as_ptr())
    }

    // FFI functions that accept a borrowed reference will use:
    //   input.with_borrowed_ptr(|obj| ffi::Call(obj)
    // 1) input is &PyObject
    //   -> with_borrowed_ptr() just forwards to the closure
    // 2) input is PyObject
    //   -> with_borrowed_ptr() just forwards to the closure
    // 3) input is &str, int, ...
    //   -> to_py_object() allocates new Python object; FFI call happens; PyObject::drop() calls Py_DECREF()

    // FFI functions that steal a reference will use:
    //   let input = try!(input.into_py_object()); ffi::Call(input.steal_ptr())
    // 1) input is &PyObject
    //   -> into_py_object() calls Py_INCREF
    // 2) input is PyObject
    //   -> into_py_object() is no-op
    // 3) input is &str, int, ...
    //   -> into_py_object() allocates new Python object
}

/// FromPyObject is implemented by various types that can be extracted from a Python object.
pub trait FromPyObject<'p> {
    fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, Self>;
}

// PyObject, PyModule etc.
// We support FromPyObject and ToPyObject for owned python references.
// This allows using existing Python objects in code that generically expects a value
// convertible to a Python object.

/// Identity conversion: allows using existing `PyObject` instances where
/// `ToPyObject` is expected.
impl <'p, 's> ToPyObject<'p> for PyObject<'s> {
    type ObjectType = PyObject<'p>;

    #[inline]
    fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> {
        self.clone().into_py_object(py)
    }

    #[inline]
    fn into_py_object(self, _py: Python<'p>) -> PyObject<'p> {
        // Transmute the lifetime.
        // This is safe, because both lifetime variables represent the same lifetime:
        // that of the python GIL acquisition.
        unsafe { std::mem::transmute(self) }
    }

    #[inline]
    fn with_borrowed_ptr<F, R>(&self, _py: Python<'p>, f: F) -> R
      where F: FnOnce(*mut ffi::PyObject) -> R {
        f(self.as_ptr())
    }
}

impl <'p, T> FromPyObject<'p> for T where T: PythonObjectWithCheckedDowncast<'p> {
    #[inline]
    fn from_py_object(s : &PyObject<'p>) -> PyResult<'p, T> {
        Ok(try!(s.clone().cast_into()))
    }
}

// &PyObject, &PyModule etc.
// We support FromPyObject and ToPyObject for borrowed python references.
// This allows using existing Python objects in code that generically expects a value
// convertible to a Python object.
impl <'p, 's, T: ?Sized> ToPyObject<'p> for &'s T where T: ToPyObject<'p> {
    type ObjectType = T::ObjectType;

    #[inline]
    fn to_py_object(&self, py: Python<'p>) -> T::ObjectType {
        <T as ToPyObject>::to_py_object(*self, py)
    }

    #[inline]
    fn into_py_object(self, py: Python<'p>) -> T::ObjectType {
        <T as ToPyObject>::to_py_object(self, py)
    }

    #[inline]
    fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
      where F: FnOnce(*mut ffi::PyObject) -> R {
        <T as ToPyObject>::with_borrowed_ptr(*self, py, f)
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;

use lazy_static::lazy_static;
use maplit::hashmap;
use specs::{Entities, ReadExpect, ReadStorage, System, WriteStorage};

use crate::animation::ImageType;
use crate::combat::components::collision::{CollisionBox, Points};
use crate::combat::components::intent::{AttackType, DefendType};
use crate::combat::components::state::HitType;
use crate::combat::components::{
    Action, Body, Collided, Draw, Facing, Health, Position, State, Velocity, Weapon,
};
use crate::files::collide::CollisionBoxes;
use crate::objects::TextureAtlas;
use crate::rect::{Interval, Point, Rect};
use crate::scenes::encounter::EncounterTextures;

pub struct EntityEntityCollision;

impl<'a> System<'a> for EntityEntityCollision {
    type SystemData = (
        ReadStorage<'a, Body>,
        ReadStorage<'a, Position>,
        WriteStorage<'a, Velocity>,
        Entities<'a>,
    );

    fn run(
        &mut self,
        (body_storage, position_storage, mut velocity_storage, entities): Self::SystemData,
    ) {
        use specs::Join;
        for (body, position_1, velocity, entity_1) in (
            &body_storage,
            &position_storage,
            &mut velocity_storage,
            &*entities,
        )
            .join()
        {
            for (other, position_2, _entity_2) in (&body_storage, &position_storage, &*entities)
                .join()
                .filter(|(.., entity_2)| entity_2.id() != entity_1.id())
            {
                if let (Some(body_rect), Some(other_rect)) = (body.rect, other.rect) {
                    let y_delta: i32 = position_1.y as i32 - position_2.y as i32;
                    let new_rect = body_rect + (velocity.x, velocity.y);
                    if y_delta.abs() <= 20 {
                        if new_rect.intersects(&other_rect) {
                            let other_x = Interval {
                                a: other_rect.x,
                                b: other_rect.x + other_rect.w as i32,
                            };
                            if velocity.x < 0 && other_x.contains_point(new_rect.x) {
                                velocity.x = 0;
                            } else if velocity.x > 0
                                && other_x.contains_point(new_rect.x + new_rect.w as i32)
                            {
                                velocity.x = 0;
                            }

                            let other_y = Interval {
                                a: other_rect.y,
                                b: other_rect.y + new_rect.h as i32,
                            };
                            if velocity.y < 0 && other_y.contains_point(new_rect.y) {
                                velocity.y = 0;
                            } else if velocity.y > 0
                                && other_y.contains_point(new_rect.y + new_rect.h as i32)
                            {
                                velocity.y = 0;
                            }
                        }
                    }

                    // let y_delta: i32 = position_1.y as i32 - position_2.y as i32;
                    // if y_delta.abs() <= 10 && new_y.intersects(&other_y) {
                    //     println!("{:?}", new_y);
                    //     velocity.y = 0;
                    // }
                }
            }
        }
    }
}

pub struct UpdateBoundingBoxes;

impl<'a> System<'a> for UpdateBoundingBoxes {
    type SystemData = (
        ReadExpect<'a, CollisionBoxes>,
        ReadExpect<'a, EncounterTextures>,
        ReadStorage<'a, Draw>,
        ReadStorage<'a, Position>,
        WriteStorage<'a, Body>,
        WriteStorage<'a, Weapon>,
    );

    fn run(
        &mut self,
        (
            collision_boxes,
            encounter_textures,
            draw,
            position,
            mut body,
            mut weapon,
        ): Self::SystemData,
    ) {
        use specs::Join;
        let collision_data = &collision_boxes.data;
        let textures = &encounter_textures.data;
        for (draw, position, body, weapon) in (&draw, &position, &mut body, &mut weapon).join() {
            let mut weapon_boxes: Vec<Points> = vec![];
            let mut body_boxes: Vec<CollisionBox> = vec![];
            for image in draw.frame.images.iter() {
                match image.image_type {
                    ImageType::Collider => {
                        if let Some(Some(points)) = &collision_data
                            .get(&image.sheet)
                            .and_then(|v| v.points.get(image.image))
                        {
                            let direction = draw.direction as i32;
                            let image_global_x: i32 = position.x as i32 + image.x * direction;
                            let image_global_y: i32 = position.y as i32 + image.y;
                            let rect_x = match draw.direction {
                                Facing::Left => image_global_x - points.max_x as i32,
                                Facing::Right => image_global_x,
                            };
                            weapon_boxes.push(Points {
                                bounding: Rect {
                                    x: rect_x,
                                    y: image_global_y,
                                    w: points.max_x,
                                    h: points.max_y,
                                },
                                points: points
                                    .data
                                    .iter()
                                    .map(|p| Point {
                                        x: image_global_x + p.x * direction,
                                        y: image_global_y + p.y,
                                    })
                                    .collect(),
                            })
                        }
                    }
                    ImageType::Collidee => {
                        if let Some(texture) = textures.get(&image.sheet) {
                            let rect = &texture.rects[image.image];
                            let mut image_global_x: i32 =
                                position.x as i32 + image.x * draw.direction as i32;
                            image_global_x = match draw.direction {
                                Facing::Left => image_global_x - rect.w as i32,
                                Facing::Right => image_global_x,
                            };
                            body_boxes.push(CollisionBox {
                                rect: Rect {
                                    x: image_global_x,
                                    y: position.y as i32 + image.y,
                                    w: rect.w,
                                    h: rect.h,
                                },
                                sheet: image.sheet.clone(),
                                image_num: image.image as u32,
                            })
                        }
                    }
                    _ => (),
                }
            }

            if weapon_boxes.is_empty() {
                weapon.collision_points = None;
            } else {
                weapon.collision_points = Some(weapon_boxes);
            }

            if body_boxes.is_empty() {
                body.collision_boxes = None;
            } else {
                let mut contains_all: Option<Rect> = None;
                for body_box in &body_boxes {
                    match contains_all {
                        Some(ref mut rect) => {
                            if body_box.rect.w > rect.w {
                                rect.w = body_box.rect.w
                            }
                            if body_box.rect.h > rect.h {
                                rect.h = body_box.rect.h
                            }
                            if body_box.rect.x < rect.x {
                                rect.x = body_box.rect.x
                            }
                            if body_box.rect.y < rect.x {
                                rect.y = body_box.rect.y
                            }
                        }
                        None => contains_all = Some(body_box.rect.clone()),
                    }
                }
                body.collision_boxes = Some(body_boxes);
                body.rect = contains_all;
            }
        }
    }
}

pub struct CheckCollisions;

impl<'a> System<'a> for CheckCollisions {
    type SystemData = (
        ReadExpect<'a, EncounterTextures>,
        ReadStorage<'a, State>,
        ReadStorage<'a, Position>,
        ReadStorage<'a, Body>,
        ReadStorage<'a, Weapon>,
        WriteStorage<'a, Collided>,
        Entities<'a>,
    );

    fn run(
        &mut self,
        (encounter_textures, state, position, bodies, weapons, mut collided, entities): Self::SystemData,
    ) {
        use specs::Join;
        let textures = &encounter_textures.data;
        for (_state, att_pos, weapon, attacker) in (&state, &position, &weapons, &*entities)
            .join()
            .filter(|(state, ..)| state.action.is_attack())
        {
            for (defender, body, _defender_position) in (&*entities, &bodies, &position)
                .join()
                // ignore self for collision checking.
                .filter(|(defender, ..)| attacker.id() != defender.id())
                // ignore entities outside a 10 pixel y range.
                .filter(|(_, _, d_pos)| (att_pos.y as i32 - d_pos.y as i32).abs() < 10)
            {
                let hit = CheckCollisions::check_collision(&textures, weapon, body);
                if hit {
                    let _result = collided.insert(attacker, Collided { target: defender });
                }
            }
        }
    }
}

impl CheckCollisions {
    fn check_collision(
        textures: &HashMap<String, TextureAtlas>,
        weapon: &Weapon,
        body: &Body,
    ) -> bool {
        for weapon_part in weapon.collision_points.iter().flat_map(|v| v) {
            // each attacking image in the attacker
            for body_part in body
                .collision_boxes
                .iter() // Option.iter()
                .flat_map(|v| v)
                .filter(|b| weapon_part.bounding.intersects(&b.rect))
            {
                // check that against each defending image in the defender
                for point in weapon_part
                    .points
                    .iter()
                    .filter(|p| body_part.rect.contains_point(p))
                {
                    // check the points collide and the pixel in the image is a part of the target
                    let hit_x = point.x - body_part.rect.x;
                    let hit_y = point.y - body_part.rect.y;
                    let texture = textures
                        .get(&body_part.sheet)
                        .expect("Encounter hasn't loaded correct textures to as world resource");
                    let collision_lookup = hit_x as usize * texture.image.width + hit_y as usize;
                    let pixel = texture.image.pixels[collision_lookup];
                    if pixel > 0 {
                        return true;
                    }
                }
            }
        }
        false
    }
}

lazy_static! {
    static ref blocks_attack: HashMap<Action, Action> = hashmap! {
        Action::Attack(AttackType::Swing) => Action::Defend(DefendType::Block),
        Action::Attack(AttackType::BackSwing) => Action::Defend(DefendType::Block),
        Action::Attack(AttackType::Thrust) => Action::Defend(DefendType::Dodge),
        Action::Attack(AttackType::Chop) => Action::Defend(DefendType::Dodge),
        Action::Attack(AttackType::UpThrust) => Action::Defend(DefendType::Dodge),
        Action::Attack(AttackType::ThrowDagger) => Action::Defend(DefendType::Dodge),
    };
}

pub struct ResolveCollisions;

impl<'a> System<'a> for ResolveCollisions {
    type SystemData = (
        WriteStorage<'a, Collided>,
        WriteStorage<'a, Health>,
        WriteStorage<'a, State>,
        Entities<'a>,
    );

    fn run(
        &mut self,
        (mut collided_storage, mut health_storage, mut state_storage, entities): Self::SystemData,
    ) {
        use specs::Join;
        for (collided, entity) in (collided_storage.drain(), &*entities).join() {
            let mut has_defended = false;
            let mut target_used_block = false;

            let target = &collided.target;
            {
                let state: Option<&State> = state_storage.get(entity);
                let target_state: Option<&State> = state_storage.get(*target);
                if let (Some(state), Some(target_state)) = (state, target_state) {
                    has_defended = blocks_attack
                        .get(&state.action)
                        .and_then(|a| Some(a == &target_state.action))
                        .expect(&format!(
                            "attack {:?} not in blocks_attack lookup",
                            &state.action
                        ));
                    target_used_block = target_state.action == Action::Defend(DefendType::Block);
                    if target_used_block && target_state.direction == state.direction {
                        has_defended = false;
                    }
                }
            }

            {
                if !has_defended {
                    // set defender animation
                    let target = &collided.target;
                    let target_health: Option<&mut Health> = health_storage.get_mut(*target);
                    let target_state: Option<&mut State> = state_storage.get_mut(*target);
                    if let (Some(target_health), Some(target_state)) = (target_health, target_state)
                    {
                        target_health.points -= 3; // TODO: change hard coded weapon damage
                        target_state.action = Action::Hit(HitType::Sliced);
                        target_state.ticks = 0;
                    }
                }
            }
            {
                // set attacker state
                let state: Option<&mut State> = state_storage.get_mut(entity);
                if let Some(state) = state {
                    if !has_defended || target_used_block {
                        match state.action {
                            Action::Attack(AttackType::UpThrust) => (),
                            _ => {
                                state.action = Action::AttackRecovery;
                                state.ticks = 0;
                            }
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>seperate out weapon and body box updating.<commit_after>use std::collections::HashMap;

use lazy_static::lazy_static;
use maplit::hashmap;
use specs::{Entities, ReadExpect, ReadStorage, System, WriteStorage};

use crate::animation::ImageType;
use crate::combat::components::collision::{CollisionBox, Points};
use crate::combat::components::intent::{AttackType, DefendType};
use crate::combat::components::state::HitType;
use crate::combat::components::{
    Action, Body, Collided, Draw, Facing, Health, Position, State, Velocity, Weapon,
};
use crate::files::collide::CollisionBoxes;
use crate::objects::TextureAtlas;
use crate::rect::{Interval, Point, Rect};
use crate::scenes::encounter::EncounterTextures;

pub struct EntityEntityCollision;

impl<'a> System<'a> for EntityEntityCollision {
    type SystemData = (
        ReadStorage<'a, Body>,
        ReadStorage<'a, Position>,
        WriteStorage<'a, Velocity>,
        Entities<'a>,
    );

    fn run(
        &mut self,
        (body_storage, position_storage, mut velocity_storage, entities): Self::SystemData,
    ) {
        use specs::Join;
        for (body, position_1, velocity, entity_1) in (
            &body_storage,
            &position_storage,
            &mut velocity_storage,
            &*entities,
        )
            .join()
        {
            for (other, position_2, _entity_2) in (&body_storage, &position_storage, &*entities)
                .join()
                .filter(|(.., entity_2)| entity_2.id() != entity_1.id())
            {
                if let (Some(body_rect), Some(other_rect)) = (body.rect, other.rect) {
                    let y_delta: i32 = position_1.y as i32 - position_2.y as i32;
                    let new_rect = body_rect + (velocity.x, velocity.y);
                    if y_delta.abs() <= 20 {
                        if new_rect.intersects(&other_rect) {
                            let other_x = Interval {
                                a: other_rect.x,
                                b: other_rect.x + other_rect.w as i32,
                            };
                            if velocity.x < 0 && other_x.contains_point(new_rect.x) {
                                velocity.x = 0;
                            } else if velocity.x > 0
                                && other_x.contains_point(new_rect.x + new_rect.w as i32)
                            {
                                velocity.x = 0;
                            }

                            let other_y = Interval {
                                a: other_rect.y,
                                b: other_rect.y + new_rect.h as i32,
                            };
                            if velocity.y < 0 && other_y.contains_point(new_rect.y) {
                                velocity.y = 0;
                            } else if velocity.y > 0
                                && other_y.contains_point(new_rect.y + new_rect.h as i32)
                            {
                                velocity.y = 0;
                            }
                        }
                    }

                    // let y_delta: i32 = position_1.y as i32 - position_2.y as i32;
                    // if y_delta.abs() <= 10 && new_y.intersects(&other_y) {
                    //     println!("{:?}", new_y);
                    //     velocity.y = 0;
                    // }
                }
            }
        }
    }
}

pub struct UpdateBoundingBoxes;

impl<'a> System<'a> for UpdateBoundingBoxes {
    type SystemData = (
        ReadExpect<'a, CollisionBoxes>,
        ReadExpect<'a, EncounterTextures>,
        ReadStorage<'a, Draw>,
        ReadStorage<'a, Position>,
        WriteStorage<'a, Body>,
        WriteStorage<'a, Weapon>,
    );

    fn run(
        &mut self,
        (
            collision_boxes,
            encounter_textures,
            draw,
            position,
            mut body,
            mut weapon,
        ): Self::SystemData,
    ) {
        use specs::Join;
        let collision_data = &collision_boxes.data;
        let textures = &encounter_textures.data;

        for (draw, position, body) in (&draw, &position, &mut body).join() {
            let mut body_boxes: Vec<CollisionBox> = vec![];
            for image in draw.frame.images.iter() {
                match image.image_type {
                    ImageType::Collidee => {
                        if let Some(texture) = textures.get(&image.sheet) {
                            let rect = &texture.rects[image.image];
                            let mut image_global_x: i32 =
                                position.x as i32 + image.x * draw.direction as i32;
                            image_global_x = match draw.direction {
                                Facing::Left => image_global_x - rect.w as i32,
                                Facing::Right => image_global_x,
                            };
                            body_boxes.push(CollisionBox {
                                rect: Rect {
                                    x: image_global_x,
                                    y: position.y as i32 + image.y,
                                    w: rect.w,
                                    h: rect.h,
                                },
                                sheet: image.sheet.clone(),
                                image_num: image.image as u32,
                            })
                        }
                    }
                    _ => (),
                }
            }

            if body_boxes.is_empty() {
                body.collision_boxes = None;
            } else {
                let mut contains_all: Option<Rect> = None;
                for body_box in &body_boxes {
                    match contains_all {
                        Some(ref mut rect) => {
                            if body_box.rect.w > rect.w {
                                rect.w = body_box.rect.w
                            }
                            if body_box.rect.h > rect.h {
                                rect.h = body_box.rect.h
                            }
                            if body_box.rect.x < rect.x {
                                rect.x = body_box.rect.x
                            }
                            if body_box.rect.y < rect.x {
                                rect.y = body_box.rect.y
                            }
                        }
                        None => contains_all = Some(body_box.rect.clone()),
                    }
                }
                body.collision_boxes = Some(body_boxes);
                body.rect = contains_all;
            }
        }

        for (draw, position, weapon) in (&draw, &position, &mut weapon).join() {
            let mut weapon_boxes: Vec<Points> = vec![];
            for image in draw.frame.images.iter() {
                match image.image_type {
                    ImageType::Collider => {
                        if let Some(Some(points)) = &collision_data
                            .get(&image.sheet)
                            .and_then(|v| v.points.get(image.image))
                        {
                            let direction = draw.direction as i32;
                            let image_global_x: i32 = position.x as i32 + image.x * direction;
                            let image_global_y: i32 = position.y as i32 + image.y;
                            let rect_x = match draw.direction {
                                Facing::Left => image_global_x - points.max_x as i32,
                                Facing::Right => image_global_x,
                            };
                            weapon_boxes.push(Points {
                                bounding: Rect {
                                    x: rect_x,
                                    y: image_global_y,
                                    w: points.max_x,
                                    h: points.max_y,
                                },
                                points: points
                                    .data
                                    .iter()
                                    .map(|p| Point {
                                        x: image_global_x + p.x * direction,
                                        y: image_global_y + p.y,
                                    })
                                    .collect(),
                            })
                        }
                    }
                    _ => (),
                }
            }

            if weapon_boxes.is_empty() {
                weapon.collision_points = None;
            } else {
                weapon.collision_points = Some(weapon_boxes);
            }
        }
    }
}

pub struct CheckCollisions;

impl<'a> System<'a> for CheckCollisions {
    type SystemData = (
        ReadExpect<'a, EncounterTextures>,
        ReadStorage<'a, State>,
        ReadStorage<'a, Position>,
        ReadStorage<'a, Body>,
        ReadStorage<'a, Weapon>,
        WriteStorage<'a, Collided>,
        Entities<'a>,
    );

    fn run(
        &mut self,
        (encounter_textures, state, position, bodies, weapons, mut collided, entities): Self::SystemData,
    ) {
        use specs::Join;
        let textures = &encounter_textures.data;
        for (_state, att_pos, weapon, attacker) in (&state, &position, &weapons, &*entities)
            .join()
            .filter(|(state, ..)| state.action.is_attack())
        {
            for (defender, body, _defender_position) in (&*entities, &bodies, &position)
                .join()
                // ignore self for collision checking.
                .filter(|(defender, ..)| attacker.id() != defender.id())
                // ignore entities outside a 10 pixel y range.
                .filter(|(_, _, d_pos)| (att_pos.y as i32 - d_pos.y as i32).abs() < 10)
            {
                let hit = CheckCollisions::check_collision(&textures, weapon, body);
                if hit {
                    let _result = collided.insert(attacker, Collided { target: defender });
                }
            }
        }
    }
}

impl CheckCollisions {
    fn check_collision(
        textures: &HashMap<String, TextureAtlas>,
        weapon: &Weapon,
        body: &Body,
    ) -> bool {
        for weapon_part in weapon.collision_points.iter().flat_map(|v| v) {
            // each attacking image in the attacker
            for body_part in body
                .collision_boxes
                .iter() // Option.iter()
                .flat_map(|v| v)
                .filter(|b| weapon_part.bounding.intersects(&b.rect))
            {
                // check that against each defending image in the defender
                for point in weapon_part
                    .points
                    .iter()
                    .filter(|p| body_part.rect.contains_point(p))
                {
                    // check the points collide and the pixel in the image is a part of the target
                    let hit_x = point.x - body_part.rect.x;
                    let hit_y = point.y - body_part.rect.y;
                    let texture = textures
                        .get(&body_part.sheet)
                        .expect("Encounter hasn't loaded correct textures to as world resource");
                    let collision_lookup = hit_x as usize * texture.image.width + hit_y as usize;
                    let pixel = texture.image.pixels[collision_lookup];
                    if pixel > 0 {
                        return true;
                    }
                }
            }
        }
        false
    }
}

lazy_static! {
    static ref blocks_attack: HashMap<Action, Action> = hashmap! {
        Action::Attack(AttackType::Swing) => Action::Defend(DefendType::Block),
        Action::Attack(AttackType::BackSwing) => Action::Defend(DefendType::Block),
        Action::Attack(AttackType::Thrust) => Action::Defend(DefendType::Dodge),
        Action::Attack(AttackType::Chop) => Action::Defend(DefendType::Dodge),
        Action::Attack(AttackType::UpThrust) => Action::Defend(DefendType::Dodge),
        Action::Attack(AttackType::ThrowDagger) => Action::Defend(DefendType::Dodge),
    };
}

pub struct ResolveCollisions;

impl<'a> System<'a> for ResolveCollisions {
    type SystemData = (
        WriteStorage<'a, Collided>,
        WriteStorage<'a, Health>,
        WriteStorage<'a, State>,
        Entities<'a>,
    );

    fn run(
        &mut self,
        (mut collided_storage, mut health_storage, mut state_storage, entities): Self::SystemData,
    ) {
        use specs::Join;
        for (collided, entity) in (collided_storage.drain(), &*entities).join() {
            let mut has_defended = false;
            let mut target_used_block = false;

            let target = &collided.target;
            {
                let state: Option<&State> = state_storage.get(entity);
                let target_state: Option<&State> = state_storage.get(*target);
                if let (Some(state), Some(target_state)) = (state, target_state) {
                    has_defended = blocks_attack
                        .get(&state.action)
                        .and_then(|a| Some(a == &target_state.action))
                        .expect(&format!(
                            "attack {:?} not in blocks_attack lookup",
                            &state.action
                        ));
                    target_used_block = target_state.action == Action::Defend(DefendType::Block);
                    if target_used_block && target_state.direction == state.direction {
                        has_defended = false;
                    }
                }
            }

            {
                if !has_defended {
                    // set defender animation
                    let target = &collided.target;
                    let target_health: Option<&mut Health> = health_storage.get_mut(*target);
                    let target_state: Option<&mut State> = state_storage.get_mut(*target);
                    if let (Some(target_health), Some(target_state)) = (target_health, target_state)
                    {
                        target_health.points -= 3; // TODO: change hard coded weapon damage
                        target_state.action = Action::Hit(HitType::Sliced);
                        target_state.ticks = 0;
                    }
                }
            }
            {
                // set attacker state
                let state: Option<&mut State> = state_storage.get_mut(entity);
                if let Some(state) = state {
                    if !has_defended || target_used_block {
                        match state.action {
                            Action::Attack(AttackType::UpThrust) => (),
                            _ => {
                                state.action = Action::AttackRecovery;
                                state.ticks = 0;
                            }
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use core::*;

pub type NodeId = usize;

#[derive(Clone)]
pub struct Node<T>(pub NodeId, pub T);

impl fmt::Debug for Node<Epiq> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({} {:?})", self.0, self.1)
    }
}

pub struct SymbolTable {
    table: Vec<Vec<(String, Option<NodeId>)>>,
    current_index: usize,
}

impl SymbolTable {
    pub fn new(_initial_table: Vec<(String, Option<NodeId>)>) -> SymbolTable {
        SymbolTable {
            table: vec![vec![]],
            current_index: Default::default(),
        }
    }

    pub fn define(&mut self, name: &str, value: NodeId) {
        // println!("symbol_table: {:?}", "define");
        if {
            if let Some(&(_, ref _r)) = self.table[self.current_index].iter().find(|&&(ref n, _)| n == name) {
                // すでに含まれていたら上書きしたいが、方法がわからないので何もせずにおく
                // *r = Some(value);
                false
            } else {
                true
            }
        } {
            self.table[self.current_index].push( (name.to_string(), Some(value)) );
            // println!("symbol_table: {:?}", self.table);
        }
    }

    pub fn resolve(&self, name: &str) -> Option<Option<NodeId>> {
        self.resolve_internal(name, self.current_index)
        /*
        if let Some(&( _, Some(r) )) = self.table[self.current_index].iter().find(|&&(ref n, _)| n == name) {
            Some(Some(r))
        } else {
            // なかったら一つ上のframeを探す
            resolve()
            None
        }
        */
    }

    fn resolve_internal(&self, name: &str, frame: usize) -> Option<Option<NodeId>> {
        if let Some(&( _, Some(r) )) = self.table[frame].iter().find(|&&(ref n, _)| n == name) {
            // println!("resolve 見つかりました {:?} {:?}", name, self.table);
            Some(Some(r))
        } else {
            if frame == 0 {
                // グローバル環境まで来たら終了
                // println!("resolve 見つかりませんでした {:?} {:?}", name, self.table);
                None
            } else {
                // なかったら一つ上のframeを探す
                // println!("resolve 見つからないので親を探します {:?}", name);
                self.resolve_internal(name, frame - 1)
            }
        }
    }

    pub fn extend(&mut self) {
        let new_frame = vec![];
        self.table.push(new_frame);
        self.current_index = self.table.len() - 1;

    }

    pub fn pop(&mut self) {
        let _ = self.table.pop();
        self.current_index = self.table.len() - 1;
    }
}

pub struct NodeArena<T> (Vec<Node<T>>, Option<usize>, SymbolTable);

impl<T> NodeArena<T> {
    pub fn new() -> NodeArena<T> {
        NodeArena::<T>(Default::default(), Default::default(), SymbolTable::new(vec![]))
    }

    pub fn alloc(&mut self, value: T) -> NodeId {
        let id = self.0.len();
        let node = Node(id, value);
        self.0.push(node);
        self.1 = Some(id);
        id
    }

    pub fn get(&self, id: NodeId) -> &Node<T> {
        &self.0[id]
    }

    pub fn get_mut(&mut self, id: NodeId) -> &mut Node<T> {
        &mut self.0[id]
    }

    pub fn entry(&self) -> Option<NodeId> {
        self.1
    }

    pub fn set_entry(&mut self, id: NodeId) {
        self.1 = Some(id);
    }

    pub fn max_id(&self) -> Option<NodeId> {
        let id = self.0.len();
        if id == 0 { None } else { Some(id - 1) }
    }

    pub fn define(&mut self, name: &str, value: NodeId) {
        self.2.define(name, value)
    }

    pub fn resolve(&self, name: &str) -> Option<Option<&Node<T>>> {
        match self.2.resolve(name) {
            Some(Some(n)) => {
                Some(Some(&self.0[n]))
            },
            _ => {
                // どちらかがNoneだが今は考えない
                // とりあえずNone
                None
            }
        }

    }

    pub fn extend(&mut self) {
        self.2.extend()
    }

    pub fn pop(&mut self) {
        self.2.pop()
    }
}

#[test]
fn make() { let _arena = NodeArena::<u8>::new(); }

#[test]
fn alloc() {
    let mut arena = NodeArena::<u8>::new();
    assert_eq!(arena.alloc(46), 0);
}

#[test]
fn get() {
    let mut arena = NodeArena::<u8>::new();
    let _node_id = arena.alloc(46);

}

#[test]
fn get_mut() {
    let mut arena = NodeArena::<u8>::new();
    let node_id = arena.alloc(46);
    {
        let mut node = arena.get_mut(node_id);
        node.1 = 87;
    }
    assert_eq!(arena.get(node_id).1, 87);
}
<commit_msg>delete old code3<commit_after>use core::*;

pub type NodeId = usize;

#[derive(Clone)]
pub struct Node<T>(pub NodeId, pub T);

impl fmt::Debug for Node<Epiq> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({} {:?})", self.0, self.1)
    }
}

pub struct SymbolTable {
    table: Vec<Vec<(String, Option<NodeId>)>>,
    current_index: usize,
}

impl SymbolTable {
    pub fn new(_initial_table: Vec<(String, Option<NodeId>)>) -> SymbolTable {
        SymbolTable {
            table: vec![vec![]],
            current_index: Default::default(),
        }
    }

    pub fn define(&mut self, name: &str, value: NodeId) {
        // println!("symbol_table: {:?}", "define");
        if {
            if let Some(&(_, ref _r)) = self.table[self.current_index].iter().find(|&&(ref n, _)| n == name) {
                // すでに含まれていたら上書きしたいが、方法がわからないので何もせずにおく
                // *r = Some(value);
                false
            } else {
                true
            }
        } {
            self.table[self.current_index].push( (name.to_string(), Some(value)) );
            // println!("symbol_table: {:?}", self.table);
        }
    }

    pub fn resolve(&self, name: &str) -> Option<Option<NodeId>> {
        self.resolve_internal(name, self.current_index)
    }

    fn resolve_internal(&self, name: &str, frame: usize) -> Option<Option<NodeId>> {
        if let Some(&( _, Some(r) )) = self.table[frame].iter().find(|&&(ref n, _)| n == name) {
            // println!("resolve 見つかりました {:?} {:?}", name, self.table);
            Some(Some(r))
        } else {
            if frame == 0 {
                // グローバル環境まで来たら終了
                // println!("resolve 見つかりませんでした {:?} {:?}", name, self.table);
                None
            } else {
                // なかったら一つ上のframeを探す
                // println!("resolve 見つからないので親を探します {:?}", name);
                self.resolve_internal(name, frame - 1)
            }
        }
    }

    pub fn extend(&mut self) {
        let new_frame = vec![];
        self.table.push(new_frame);
        self.current_index = self.table.len() - 1;

    }

    pub fn pop(&mut self) {
        let _ = self.table.pop();
        self.current_index = self.table.len() - 1;
    }
}

pub struct NodeArena<T> (Vec<Node<T>>, Option<usize>, SymbolTable);

impl<T> NodeArena<T> {
    pub fn new() -> NodeArena<T> {
        NodeArena::<T>(Default::default(), Default::default(), SymbolTable::new(vec![]))
    }

    pub fn alloc(&mut self, value: T) -> NodeId {
        let id = self.0.len();
        let node = Node(id, value);
        self.0.push(node);
        self.1 = Some(id);
        id
    }

    pub fn get(&self, id: NodeId) -> &Node<T> {
        &self.0[id]
    }

    pub fn get_mut(&mut self, id: NodeId) -> &mut Node<T> {
        &mut self.0[id]
    }

    pub fn entry(&self) -> Option<NodeId> {
        self.1
    }

    pub fn set_entry(&mut self, id: NodeId) {
        self.1 = Some(id);
    }

    pub fn max_id(&self) -> Option<NodeId> {
        let id = self.0.len();
        if id == 0 { None } else { Some(id - 1) }
    }

    pub fn define(&mut self, name: &str, value: NodeId) {
        self.2.define(name, value)
    }

    pub fn resolve(&self, name: &str) -> Option<Option<&Node<T>>> {
        match self.2.resolve(name) {
            Some(Some(n)) => {
                Some(Some(&self.0[n]))
            },
            _ => {
                // どちらかがNoneだが今は考えない
                // とりあえずNone
                None
            }
        }

    }

    pub fn extend(&mut self) {
        self.2.extend()
    }

    pub fn pop(&mut self) {
        self.2.pop()
    }
}

#[test]
fn make() { let _arena = NodeArena::<u8>::new(); }

#[test]
fn alloc() {
    let mut arena = NodeArena::<u8>::new();
    assert_eq!(arena.alloc(46), 0);
}

#[test]
fn get() {
    let mut arena = NodeArena::<u8>::new();
    let _node_id = arena.alloc(46);

}

#[test]
fn get_mut() {
    let mut arena = NodeArena::<u8>::new();
    let node_id = arena.alloc(46);
    {
        let mut node = arena.get_mut(node_id);
        node.1 = 87;
    }
    assert_eq!(arena.get(node_id).1, 87);
}
<|endoftext|>


<commit_before>extern crate csv;

use std;
use std::io;
use std::path::Path;
use std::num;
use std::collections::HashMap;
use cpu::common_defs::OpcodeExecInfo;
use cpu::common_defs::OpcodeDebugInfo;
use cpu::common_defs::opcode_class;
use cpu::common_defs::address_mode;

#[derive(Debug)]
pub enum OpcodeLoadError {
  Io(io::Error),
  CSV(csv::Error),
  ParseInt(num::ParseIntError),
  ParseOpcodeClass(opcode_class::ParseError),
  ParseAddressMode(address_mode::ParseError)
}

impl From<csv::Error> for OpcodeLoadError {
    fn from(err:csv::Error) -> OpcodeLoadError {
        OpcodeLoadError::CSV(err)
    }
}
impl From<num::ParseIntError> for OpcodeLoadError {
    fn from(err:num::ParseIntError) -> OpcodeLoadError {
        OpcodeLoadError::ParseInt(err)
    }
}
impl From<opcode_class::ParseError> for OpcodeLoadError {
    fn from(err:opcode_class::ParseError) -> OpcodeLoadError {
        OpcodeLoadError::ParseOpcodeClass(err)
    }
}
impl From<address_mode::ParseError> for OpcodeLoadError {
    fn from(err:address_mode::ParseError) -> OpcodeLoadError {
        OpcodeLoadError::ParseAddressMode(err)
    }
}

pub fn load_from_file<P:AsRef<Path>>(file_path: P) -> Result<(Vec<OpcodeExecInfo>,Vec<OpcodeDebugInfo>),OpcodeLoadError> {
    let mut rdr = try!(csv::Reader::from_file(file_path));
    rdr = rdr.has_headers(true);
    rdr = rdr.flexible(false); // all records are the same length

    let mut exec_info_hash = Vec::<OpcodeExecInfo>::new();
    let mut debug_info_hash = Vec::<OpcodeDebugInfo>::new();

    for rec in rdr.decode() {
        let (opcode_string,name,address_mode_name,len,cycles,page_cycles,notes) : (String,String,String,u8,u8,u8,String) = rec.unwrap();
        let opcode = try!(u8::from_str_radix(&opcode_string[2..],16)); // from_str_radix won't parse 0x

        let mut debug_info = OpcodeDebugInfo { opcode : opcode, name : name.clone(), address_mode_name : address_mode_name.trim().to_string(), notes : notes, };

        let address_mode = try!(debug_info.address_mode_name.parse::<address_mode::AddressMode>());
        let opcode_class = try!(name.trim().to_string().parse::<opcode_class::OpcodeClass>());

        let mut exec_info = OpcodeExecInfo { opcode: opcode, len: len, cycles: cycles, page_cycles: page_cycles, address_mode: address_mode,opcode_class:opcode_class };

        debug_info_hash.push(debug_info);
        exec_info_hash.push(exec_info);
    }
    Ok((exec_info_hash,debug_info_hash))
}

<commit_msg>fixed 'unnecessary mutable' warning<commit_after>extern crate csv;

use std;
use std::io;
use std::path::Path;
use std::num;
use std::collections::HashMap;
use cpu::common_defs::OpcodeExecInfo;
use cpu::common_defs::OpcodeDebugInfo;
use cpu::common_defs::opcode_class;
use cpu::common_defs::address_mode;

#[derive(Debug)]
pub enum OpcodeLoadError {
  Io(io::Error),
  CSV(csv::Error),
  ParseInt(num::ParseIntError),
  ParseOpcodeClass(opcode_class::ParseError),
  ParseAddressMode(address_mode::ParseError)
}

impl From<csv::Error> for OpcodeLoadError {
    fn from(err:csv::Error) -> OpcodeLoadError {
        OpcodeLoadError::CSV(err)
    }
}
impl From<num::ParseIntError> for OpcodeLoadError {
    fn from(err:num::ParseIntError) -> OpcodeLoadError {
        OpcodeLoadError::ParseInt(err)
    }
}
impl From<opcode_class::ParseError> for OpcodeLoadError {
    fn from(err:opcode_class::ParseError) -> OpcodeLoadError {
        OpcodeLoadError::ParseOpcodeClass(err)
    }
}
impl From<address_mode::ParseError> for OpcodeLoadError {
    fn from(err:address_mode::ParseError) -> OpcodeLoadError {
        OpcodeLoadError::ParseAddressMode(err)
    }
}

pub fn load_from_file<P:AsRef<Path>>(file_path: P) -> Result<(Vec<OpcodeExecInfo>,Vec<OpcodeDebugInfo>),OpcodeLoadError> {
    let mut rdr = try!(csv::Reader::from_file(file_path));
    rdr = rdr.has_headers(true);
    rdr = rdr.flexible(false); // all records are the same length

    let mut exec_info_hash = Vec::<OpcodeExecInfo>::new();
    let mut debug_info_hash = Vec::<OpcodeDebugInfo>::new();

    for rec in rdr.decode() {
        let (opcode_string,name,address_mode_name,len,cycles,page_cycles,notes) : (String,String,String,u8,u8,u8,String) = rec.unwrap();
        let opcode = try!(u8::from_str_radix(&opcode_string[2..],16)); // from_str_radix won't parse 0x

        let debug_info = OpcodeDebugInfo { opcode : opcode, name : name.clone(), address_mode_name : address_mode_name.trim().to_string(), notes : notes, };

        let address_mode = try!(debug_info.address_mode_name.parse::<address_mode::AddressMode>());
        let opcode_class = try!(name.trim().to_string().parse::<opcode_class::OpcodeClass>());

        let exec_info = OpcodeExecInfo { opcode: opcode, len: len, cycles: cycles, page_cycles: page_cycles, address_mode: address_mode,opcode_class:opcode_class };

        debug_info_hash.push(debug_info);
        exec_info_hash.push(exec_info);
    }
    Ok((exec_info_hash,debug_info_hash))
}

<|endoftext|>


<commit_before>pub mod block;
pub mod stream;
pub mod asymmetric;
<commit_msg>docs(crypto): Add module documentation<commit_after>//! Cryptosystems primitives
//!
//! Cryptosystem is a suite of algorithms that describe particular security service, in most cases
//! used for achieving confidentiality. Typically this is set of three algorithms: key generation,
//! encryption function and decryption function.
//!
//! Mathematically it can be described as tuple `(P, C, K, E, D)`, where:
//!
//! - `P` is a set called "plaintext space"
//! - `C` is a set called "ciphertext space"
//! - `K` is a set called "key space"
//! - `E` is a set of functions `e :: k -> p -> c` called "encryption functions"
//! - `D` is a set of functions `d :: k -> c -> p` called "decryption functions"
//!
//! For each `ke ∈ K` there is `kd ∈ K` such that `d(kd, e(ke, p)) = p`. If `kd = ke` then we call
//! that "symmetric cipher" otherwise we call it "asymmetric cipher".
//!
//! In practise we use "asymmetric ciphers" for which computing `kd` from `ke` is computationally
//! hard or impossible.
//!
//! # Kerckhoff's Principle
//!
//! > A cryptosystem should be secure even if everything about the system, except the key, is
//! > public knowledge.
//!
//! This is basic law for moder cryptography. Unfortunately many of people understand this as
//! "keeping cryptosystem hidden is bad". That is big misunderstanding of what that principle
//! states. It is nothing bad to keep cryptosystem in secret, it is yet another obstacle to
//! overcome by eavesdropper, just don't rely on secrecy.

pub mod block;
pub mod stream;
pub mod asymmetric;
<|endoftext|>