<commit_before>use std::rc::Rc;

use state::State;
use super::{Action, config, Conditions, Message, TimerEvent};

use action::ExecResult;
use self::linear::LinearContext;
use self::map::MapContext;

#[derive(Debug)]
pub struct BaseContext {
    conditions: Conditions,
    actions: Vec<Action>
}

impl BaseContext {
    pub fn new(conditions: Conditions) -> BaseContext {
        BaseContext {
            conditions: conditions,
            actions: Vec::new()
        }
    }

    pub fn actions(&self) -> &[Action] {
        &self.actions
    }

    pub fn on_timer(&self, event: &TimerEvent, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.on_timer(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        }
        None
    }

    pub fn on_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if self.conditions.ignore_message(&event) {
            None
        } else {
            self.on_relevant_message(event, state)
        }
    }

    pub fn on_relevant_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.add_message(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        } else if self.conditions.is_opening(&event) {
            state.add_message(event);
            state.open();
        }
        None
    }

    fn close_state(&self, state: &mut State) -> Option<Vec<ExecResult>> {
        state.close();
        if self.actions.is_empty() {
            None
        } else {
            let commands = self.actions().iter().map(|action| action.execute(state, self)).collect();
            Some(commands)
        }
    }
}

impl From<config::Context> for BaseContext {
    fn from(config: config::Context) -> BaseContext {
        let config::Context{conditions, actions} = config;
        BaseContext {
            conditions: conditions,
            actions: actions
        }
    }
}

#[derive(Debug)]
pub enum Context {
    Linear(LinearContext),
    Map(MapContext)
}

impl Context {
    pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
        match *self {
            Context::Linear(ref mut context) => context.on_timer(event),
            Context::Map(ref mut context) => context.on_timer(event),
        }
    }

    pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
        match *self {
            Context::Linear(ref mut context) => context.on_message(event),
            Context::Map(ref mut context) => context.on_message(event),
        }
    }

    pub fn is_open(&mut self) -> bool {
        match *self {
            Context::Linear(ref context) => context.is_open(),
            Context::Map(ref mut context) => context.is_open(),
        }
    }

    pub fn new_linear(conditions: Conditions) -> Context {
        Context::Linear(
            LinearContext::new(conditions)
        )
    }

    pub fn new_map(conditions: Conditions) -> Context {
        Context::Map(
            MapContext::new(conditions)
        )
    }
}

impl From<config::Context> for Context {
    fn from(config: config::Context) -> Context {
        Context::Linear(LinearContext::from(config))
    }
}

mod linear {
    use std::rc::Rc;

    use action::ExecResult;
    use config;
    use Conditions;
    use Message;
    use state::State;
    use TimerEvent;
    use super::BaseContext;

    #[derive(Debug)]
    pub struct LinearContext {
        base: BaseContext,
        state: State
    }

    impl LinearContext {
        pub fn new(conditions: Conditions) -> LinearContext {
            LinearContext {
                base: BaseContext::new(conditions),
                state: State::new()
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
            self.base.on_timer(event, &mut self.state)
        }

        pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            self.base.on_message(event, &mut self.state)
        }

        pub fn is_open(&self) -> bool {
            self.state.is_open()
        }
    }

    impl From<config::Context> for LinearContext {
        fn from(config: config::Context) -> LinearContext {
            LinearContext {
                base: BaseContext::from(config),
                state: State::new()
            }
        }
    }
}

mod map {
    use std::collections::BTreeMap;
    use std::fmt::Write;
    use std::rc::Rc;

    use action::ExecResult;
    use Conditions;
    use Message;
    use state::State;
    use TimerEvent;
    use super::BaseContext;

    #[derive(Debug)]
    pub struct MapContext {
        base: BaseContext,
        map: BTreeMap<String, State>,
        format_buffer: String
    }

    impl MapContext {
        pub fn new(conditions: Conditions) -> MapContext {
            MapContext {
                base: BaseContext::new(conditions),
                map: BTreeMap::new(),
                format_buffer: String::new()
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
            let mut result: Vec<ExecResult> = Vec::new();

            for (_, mut state) in self.map.iter_mut() {
                if let Some(commands) = self.base.on_timer(event, &mut state) {
                    for i in commands.into_iter() {
                        result.push(i);
                    }
                }
            }

            self.remove_closed_states();
            Some(result)
        }

        fn get_closed_state_ids(&self) -> Vec<String> {
            self.map.iter().filter_map(|(id, state)| {
                if !state.is_open() {
                    Some(id.clone())
                } else {
                    None
                }
            }).collect::<Vec<String>>()
        }

        fn remove_closed_states(&mut self) {
            for id in self.get_closed_state_ids() {
                let _ = self.map.remove(&id);
            }
        }

        pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            self.format_context_id(&event);
            let result = self.update_state(event);
            self.format_buffer.clear();
            self.remove_closed_states();
            result
        }

        fn update_state(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            let id = self.format_buffer.clone();
            let state = self.map.entry(id).or_insert(State::new());
            self.base.on_message(event, state)
        }

        pub fn is_open(&mut self) -> bool {
            !self.map.is_empty()
        }

        fn format_context_id(&mut self, message: &Message) {
            let empty = String::new();
            let _ = self.format_buffer.write_str(message.get("HOST").unwrap_or(&empty));
            let _ = self.format_buffer.write_str(":");
            let _ = self.format_buffer.write_str(message.get("PROGRAM").unwrap_or(&empty));
            let _ = self.format_buffer.write_str(":");
            let _ = self.format_buffer.write_str(message.get("PID").unwrap_or(&empty));
        }
    }

    #[cfg(test)]
    mod test {
        use conditions::Builder;
        use Context;
        use TimerEvent;
        use message;

        use std::rc::Rc;

        #[test]
        fn test_given_map_context_when_messages_have_the_same_kvpairs_then_they_go_to_the_same_context() {
            let delta = 10;
            let timeout = 30;
            let event = TimerEvent(delta);
            let patterns: Vec<String> = vec!["1".to_string(), "2".to_string(), "3".to_string()];
            let mut context = Context::new_map(Builder::new(timeout).patterns(patterns).build());
            let msg1 = message::Builder::new("1".to_string())
                                        .pair("HOST".to_string(), "host".to_string())
                                        .pair("PROGRAM".to_string(), "program".to_string())
                                        .pair("PID".to_string(), "pid".to_string())
                                        .build();
            let msg2 = message::Builder::new("2".to_string())
                                        .pair("HOST".to_string(), "host2".to_string())
                                        .pair("PROGRAM".to_string(), "program2".to_string())
                                        .pair("PID".to_string(), "pid2".to_string())
                                        .build();
            let msg3 = message::Builder::new("3".to_string())
                                        .pair("HOST".to_string(), "host".to_string())
                                        .pair("PROGRAM".to_string(), "program".to_string())
                                        .pair("PID".to_string(), "pid".to_string())
                                        .build();

            assert_false!(context.is_open());
            context.on_message(Rc::new(msg1));
            assert_true!(context.is_open());
            context.on_timer(&event);
            context.on_message(Rc::new(msg2));
            context.on_message(Rc::new(msg3));
            context.on_timer(&event);
            context.on_timer(&event);
            assert_true!(context.is_open());
            context.on_timer(&event);
            assert_false!(context.is_open());
        }
    }
}

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

    use message;
    use TimerEvent;
    use super::Context;
    use conditions::Builder;

    #[test]
    fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
        let timeout = 100;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        println!("{:?}", &context);
        assert_false!(context.is_open());
        context.on_message(event);
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(50));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(49));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
        let timeout = 100;
        let max_size = 3;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).max_size(max_size).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        println!("{:?}", &context);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        println!("{:?}", &context);
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).renew_timeout(renew_timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).renew_timeout(renew_timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
    }
}
<commit_msg>Context: close State only when it is processed<commit_after>use std::rc::Rc;

use state::State;
use super::{Action, config, Conditions, Message, TimerEvent};

use action::ExecResult;
use self::linear::LinearContext;
use self::map::MapContext;

#[derive(Debug)]
pub struct BaseContext {
    conditions: Conditions,
    actions: Vec<Action>
}

impl BaseContext {
    pub fn new(conditions: Conditions) -> BaseContext {
        BaseContext {
            conditions: conditions,
            actions: Vec::new()
        }
    }

    pub fn actions(&self) -> &[Action] {
        &self.actions
    }

    pub fn on_timer(&self, event: &TimerEvent, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.on_timer(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        }
        None
    }

    pub fn on_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if self.conditions.ignore_message(&event) {
            None
        } else {
            self.on_relevant_message(event, state)
        }
    }

    pub fn on_relevant_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.add_message(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        } else if self.conditions.is_opening(&event) {
            state.add_message(event);
            state.open();
        }
        None
    }

    fn close_state(&self, state: &mut State) -> Option<Vec<ExecResult>> {
        if self.actions.is_empty() {
            state.close();
            None
        } else {
            let commands = self.actions().iter().map(|action| action.execute(state, self)).collect();
            state.close();
            Some(commands)
        }
    }
}

impl From<config::Context> for BaseContext {
    fn from(config: config::Context) -> BaseContext {
        let config::Context{conditions, actions} = config;
        BaseContext {
            conditions: conditions,
            actions: actions
        }
    }
}

#[derive(Debug)]
pub enum Context {
    Linear(LinearContext),
    Map(MapContext)
}

impl Context {
    pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
        match *self {
            Context::Linear(ref mut context) => context.on_timer(event),
            Context::Map(ref mut context) => context.on_timer(event),
        }
    }

    pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
        match *self {
            Context::Linear(ref mut context) => context.on_message(event),
            Context::Map(ref mut context) => context.on_message(event),
        }
    }

    pub fn is_open(&mut self) -> bool {
        match *self {
            Context::Linear(ref context) => context.is_open(),
            Context::Map(ref mut context) => context.is_open(),
        }
    }

    pub fn new_linear(conditions: Conditions) -> Context {
        Context::Linear(
            LinearContext::new(conditions)
        )
    }

    pub fn new_map(conditions: Conditions) -> Context {
        Context::Map(
            MapContext::new(conditions)
        )
    }
}

impl From<config::Context> for Context {
    fn from(config: config::Context) -> Context {
        Context::Linear(LinearContext::from(config))
    }
}

mod linear {
    use std::rc::Rc;

    use action::ExecResult;
    use config;
    use Conditions;
    use Message;
    use state::State;
    use TimerEvent;
    use super::BaseContext;

    #[derive(Debug)]
    pub struct LinearContext {
        base: BaseContext,
        state: State
    }

    impl LinearContext {
        pub fn new(conditions: Conditions) -> LinearContext {
            LinearContext {
                base: BaseContext::new(conditions),
                state: State::new()
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
            self.base.on_timer(event, &mut self.state)
        }

        pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            self.base.on_message(event, &mut self.state)
        }

        pub fn is_open(&self) -> bool {
            self.state.is_open()
        }
    }

    impl From<config::Context> for LinearContext {
        fn from(config: config::Context) -> LinearContext {
            LinearContext {
                base: BaseContext::from(config),
                state: State::new()
            }
        }
    }
}

mod map {
    use std::collections::BTreeMap;
    use std::fmt::Write;
    use std::rc::Rc;

    use action::ExecResult;
    use Conditions;
    use Message;
    use state::State;
    use TimerEvent;
    use super::BaseContext;

    #[derive(Debug)]
    pub struct MapContext {
        base: BaseContext,
        map: BTreeMap<String, State>,
        format_buffer: String
    }

    impl MapContext {
        pub fn new(conditions: Conditions) -> MapContext {
            MapContext {
                base: BaseContext::new(conditions),
                map: BTreeMap::new(),
                format_buffer: String::new()
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
            let mut result: Vec<ExecResult> = Vec::new();

            for (_, mut state) in self.map.iter_mut() {
                if let Some(commands) = self.base.on_timer(event, &mut state) {
                    for i in commands.into_iter() {
                        result.push(i);
                    }
                }
            }

            self.remove_closed_states();
            Some(result)
        }

        fn get_closed_state_ids(&self) -> Vec<String> {
            self.map.iter().filter_map(|(id, state)| {
                if !state.is_open() {
                    Some(id.clone())
                } else {
                    None
                }
            }).collect::<Vec<String>>()
        }

        fn remove_closed_states(&mut self) {
            for id in self.get_closed_state_ids() {
                let _ = self.map.remove(&id);
            }
        }

        pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            self.format_context_id(&event);
            let result = self.update_state(event);
            self.format_buffer.clear();
            self.remove_closed_states();
            result
        }

        fn update_state(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            let id = self.format_buffer.clone();
            let state = self.map.entry(id).or_insert(State::new());
            self.base.on_message(event, state)
        }

        pub fn is_open(&mut self) -> bool {
            !self.map.is_empty()
        }

        fn format_context_id(&mut self, message: &Message) {
            let empty = String::new();
            let _ = self.format_buffer.write_str(message.get("HOST").unwrap_or(&empty));
            let _ = self.format_buffer.write_str(":");
            let _ = self.format_buffer.write_str(message.get("PROGRAM").unwrap_or(&empty));
            let _ = self.format_buffer.write_str(":");
            let _ = self.format_buffer.write_str(message.get("PID").unwrap_or(&empty));
        }
    }

    #[cfg(test)]
    mod test {
        use conditions::Builder;
        use Context;
        use TimerEvent;
        use message;

        use std::rc::Rc;

        #[test]
        fn test_given_map_context_when_messages_have_the_same_kvpairs_then_they_go_to_the_same_context() {
            let delta = 10;
            let timeout = 30;
            let event = TimerEvent(delta);
            let patterns: Vec<String> = vec!["1".to_string(), "2".to_string(), "3".to_string()];
            let mut context = Context::new_map(Builder::new(timeout).patterns(patterns).build());
            let msg1 = message::Builder::new("1".to_string())
                                        .pair("HOST".to_string(), "host".to_string())
                                        .pair("PROGRAM".to_string(), "program".to_string())
                                        .pair("PID".to_string(), "pid".to_string())
                                        .build();
            let msg2 = message::Builder::new("2".to_string())
                                        .pair("HOST".to_string(), "host2".to_string())
                                        .pair("PROGRAM".to_string(), "program2".to_string())
                                        .pair("PID".to_string(), "pid2".to_string())
                                        .build();
            let msg3 = message::Builder::new("3".to_string())
                                        .pair("HOST".to_string(), "host".to_string())
                                        .pair("PROGRAM".to_string(), "program".to_string())
                                        .pair("PID".to_string(), "pid".to_string())
                                        .build();

            assert_false!(context.is_open());
            context.on_message(Rc::new(msg1));
            assert_true!(context.is_open());
            context.on_timer(&event);
            context.on_message(Rc::new(msg2));
            context.on_message(Rc::new(msg3));
            context.on_timer(&event);
            context.on_timer(&event);
            assert_true!(context.is_open());
            context.on_timer(&event);
            assert_false!(context.is_open());
        }
    }
}

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

    use message;
    use TimerEvent;
    use super::Context;
    use conditions::Builder;

    #[test]
    fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
        let timeout = 100;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        println!("{:?}", &context);
        assert_false!(context.is_open());
        context.on_message(event);
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(50));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(49));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
        let timeout = 100;
        let max_size = 3;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).max_size(max_size).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        println!("{:?}", &context);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        println!("{:?}", &context);
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).renew_timeout(renew_timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).renew_timeout(renew_timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use super::{Message, TimerEvent};

#[derive(Clone)]
struct ConditionFields {
    timeout: u32,
    renew_timeout: Option<u32>,
    uuid: Option<String>,
    max_size: Option<usize>
}

impl ConditionFields {
    fn new(timeout: u32) -> ConditionFields {
        ConditionFields {
            timeout: timeout,
            renew_timeout: None,
            uuid: None,
            max_size: None
        }
    }
}

pub struct Context {
    conditions: ConditionFields,
    elapsed_time: u32,
    elapsed_time_since_last_message: u32,
    messages: Vec<Rc<Message>>
}

impl Context {
    pub fn on_timer(&mut self, event: &TimerEvent) -> bool {
        println!("timer event: {}", event.0);
        self.update_timers(event.0);
        self.is_any_timer_expired()
    }

    pub fn on_message(&mut self, event: Rc<Message>) -> bool {
        println!("message event");
        self.elapsed_time_since_last_message = 0;
        self.messages.push(event);
        self.is_last_message()
    }

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

    fn is_closing_message(&self) -> bool {
        if let Some(event) = self.messages.last() {
            self.conditions.uuid.as_ref().map_or(false, |uuid| {
                uuid == event.get("uuid").unwrap()
            })
        } else {
            false
        }
    }

    fn is_last_message(&self) -> bool {
       self.is_max_size_reached() || self.is_closing_message()
    }

    fn is_timeout_expired(&self) -> bool {
        self.elapsed_time >= self.conditions.timeout
    }

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

    fn is_any_timer_expired(&self) -> bool {
        self.is_timeout_expired() || self.is_renew_timeout_expired()
    }

    fn update_timers(&mut self, elapsed_time: u32) {
        self.elapsed_time += elapsed_time;
        self.elapsed_time_since_last_message += elapsed_time;
    }
}

pub struct Builder {
    conditions: ConditionFields
}

impl Builder {
    pub fn new(timeout: u32) -> Builder {
        Builder{
            conditions: ConditionFields::new(timeout)
        }
    }

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

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

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

    pub fn build(&mut self) -> Context {
        Context {
            messages: Vec::new(),
            conditions: self.conditions.clone(),
            elapsed_time: 0,
            elapsed_time_since_last_message: 0
        }
    }
}

#[test]
fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
    let timeout = 100;
    let mut context = Builder::new(timeout).build();
    assert_false!(context.on_timer(&mut TimerEvent(50)));
    assert_false!(context.on_timer(&mut TimerEvent(49)));
    assert_true!(context.on_timer(&mut TimerEvent(1)));
}

#[test]
fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
    let timeout = 100;
    let max_size = 3;
    let mut context = Builder::new(timeout).max_size(max_size).build();
    let msg1 = btreemap!{
        "uuid".to_string() => "1".to_string(),
    };
    let event = Rc::new(msg1);
    assert_false!(context.on_message(event.clone()));
    assert_false!(context.on_message(event.clone()));
    assert_true!(context.on_message(event.clone()));
}

#[test]
fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
    let timeout = 100;
    let renew_timeout = 10;
    let mut context = Builder::new(timeout).renew_timeout(renew_timeout).build();
    let msg1 = btreemap!{
        "uuid".to_string() => "1".to_string(),
    };
    let event = Rc::new(msg1);
    assert_false!(context.on_message(event.clone()));
    assert_false!(context.on_timer(&mut TimerEvent(8)));
    assert_false!(context.on_timer(&mut TimerEvent(1)));
    assert_true!(context.on_timer(&mut TimerEvent(1)));
}

#[test]
fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
    let timeout = 100;
    let renew_timeout = 10;
    let mut context = Builder::new(timeout).renew_timeout(renew_timeout).build();
    let msg1 = btreemap!{
        "uuid".to_string() => "1".to_string(),
    };
    let event = Rc::new(msg1);
    assert_false!(context.on_message(event.clone()));
    assert_false!(context.on_timer(&mut TimerEvent(8)));
    assert_false!(context.on_timer(&mut TimerEvent(1)));
    assert_false!(context.on_message(event.clone()));
    assert_false!(context.on_timer(&mut TimerEvent(1)));
}
<commit_msg>Context: simplify is_closing_message()<commit_after>use std::rc::Rc;

use super::{Message, TimerEvent};

#[derive(Clone)]
struct ConditionFields {
    timeout: u32,
    renew_timeout: Option<u32>,
    uuid: Option<String>,
    max_size: Option<usize>
}

impl ConditionFields {
    fn new(timeout: u32) -> ConditionFields {
        ConditionFields {
            timeout: timeout,
            renew_timeout: None,
            uuid: None,
            max_size: None
        }
    }
}

pub struct Context {
    conditions: ConditionFields,
    elapsed_time: u32,
    elapsed_time_since_last_message: u32,
    messages: Vec<Rc<Message>>
}

impl Context {
    pub fn on_timer(&mut self, event: &TimerEvent) -> bool {
        println!("timer event: {}", event.0);
        self.update_timers(event.0);
        self.is_any_timer_expired()
    }

    pub fn on_message(&mut self, event: Rc<Message>) -> bool {
        println!("message event");
        self.elapsed_time_since_last_message = 0;
        self.messages.push(event);
        self.is_last_message()
    }

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

    fn is_closing_message(&self) -> bool {
        self.messages.last().map_or(false, |event| {
            self.conditions.uuid.as_ref().map_or(false, |uuid| {
                uuid == event.get("uuid").unwrap()
            })
        })
    }

    fn is_last_message(&self) -> bool {
       self.is_max_size_reached() || self.is_closing_message()
    }

    fn is_timeout_expired(&self) -> bool {
        self.elapsed_time >= self.conditions.timeout
    }

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

    fn is_any_timer_expired(&self) -> bool {
        self.is_timeout_expired() || self.is_renew_timeout_expired()
    }

    fn update_timers(&mut self, elapsed_time: u32) {
        self.elapsed_time += elapsed_time;
        self.elapsed_time_since_last_message += elapsed_time;
    }
}

pub struct Builder {
    conditions: ConditionFields
}

impl Builder {
    pub fn new(timeout: u32) -> Builder {
        Builder{
            conditions: ConditionFields::new(timeout)
        }
    }

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

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

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

    pub fn build(&mut self) -> Context {
        Context {
            messages: Vec::new(),
            conditions: self.conditions.clone(),
            elapsed_time: 0,
            elapsed_time_since_last_message: 0
        }
    }
}

#[test]
fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
    let timeout = 100;
    let mut context = Builder::new(timeout).build();
    assert_false!(context.on_timer(&mut TimerEvent(50)));
    assert_false!(context.on_timer(&mut TimerEvent(49)));
    assert_true!(context.on_timer(&mut TimerEvent(1)));
}

#[test]
fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
    let timeout = 100;
    let max_size = 3;
    let mut context = Builder::new(timeout).max_size(max_size).build();
    let msg1 = btreemap!{
        "uuid".to_string() => "1".to_string(),
    };
    let event = Rc::new(msg1);
    assert_false!(context.on_message(event.clone()));
    assert_false!(context.on_message(event.clone()));
    assert_true!(context.on_message(event.clone()));
}

#[test]
fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
    let timeout = 100;
    let renew_timeout = 10;
    let mut context = Builder::new(timeout).renew_timeout(renew_timeout).build();
    let msg1 = btreemap!{
        "uuid".to_string() => "1".to_string(),
    };
    let event = Rc::new(msg1);
    assert_false!(context.on_message(event.clone()));
    assert_false!(context.on_timer(&mut TimerEvent(8)));
    assert_false!(context.on_timer(&mut TimerEvent(1)));
    assert_true!(context.on_timer(&mut TimerEvent(1)));
}

#[test]
fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
    let timeout = 100;
    let renew_timeout = 10;
    let mut context = Builder::new(timeout).renew_timeout(renew_timeout).build();
    let msg1 = btreemap!{
        "uuid".to_string() => "1".to_string(),
    };
    let event = Rc::new(msg1);
    assert_false!(context.on_message(event.clone()));
    assert_false!(context.on_timer(&mut TimerEvent(8)));
    assert_false!(context.on_timer(&mut TimerEvent(1)));
    assert_false!(context.on_message(event.clone()));
    assert_false!(context.on_timer(&mut TimerEvent(1)));
}
<|endoftext|>


<commit_before>//! A zero cost wrapper around [`std::fs`] that satisfies [`rsfs::FS`].
//!
//! # Example
//!
//! ```
//! use rsfs::*;
//! use rsfs::unix_ext::*;
//!
//! use rsfs::disk::fs;
//!
//! let fs = fs::FS;
//!
//! let meta = fs.metadata("/").unwrap();
//! assert!(meta.is_dir());
//! assert!(meta.permissions().mode() == 0o755);
//! ```
//!
//! [`rsfs::FS`]: ../trait.FS.html
//! [`std::fs`]: https://doc.rust-lang.org/std/fs/

use fs;
use std::ffi::OsString;
use std::fs as rs_fs;
use std::io::{Read, Result, Seek, SeekFrom, Write};
use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt};
use std::path::{Path, PathBuf};

#[cfg(unix)]
use unix_ext;

/// A single element tuple containing a [`std::fs::Permissions`].
///
/// [`std::fs::Permissions`]: https://doc.rust-lang.org/std/fs/struct.Permissions.html
#[derive(Debug)]
pub struct Permissions(rs_fs::Permissions);

impl fs::Permissions for Permissions {
    fn readonly(&self) -> bool {
        self.0.readonly()
    }
    fn set_readonly(&mut self, readonly: bool) {
        self.0.set_readonly(readonly)
    }
}

#[cfg(unix)]
impl unix_ext::PermissionsExt for Permissions {
    fn mode(&self) -> u32 {
        self.0.mode()
    }
    fn set_mode(&mut self, mode: u32) {
        self.0.set_mode(mode)
    }
    fn from_mode(mode: u32) -> Self {
        Permissions(rs_fs::Permissions::from_mode(mode))
    }
}

/// A single element tuple containing a [`std::fs::FileType`].
///
/// [`std::fs::FileType`]: https://doc.rust-lang.org/std/fs/struct.FileType.html
#[derive(Debug)]
pub struct FileType(rs_fs::FileType);

impl fs::FileType for FileType {
    fn is_dir(&self) -> bool {
        self.0.is_dir()
    }
    fn is_file(&self) -> bool {
        self.0.is_file()
    }
}

/// A single element tuple containing a [`std::fs::Metadata`].
///
/// [`std::fs::Metadata`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html
#[derive(Debug)]
pub struct Metadata(rs_fs::Metadata);

impl fs::Metadata for Metadata {
    type Permissions = Permissions;
    type FileType = FileType;

    fn file_type(&self) -> Self::FileType {
        FileType(self.0.file_type())
    }
    fn is_dir(&self) -> bool {
        self.0.is_dir()
    }
    fn is_file(&self) -> bool {
        self.0.is_file()
    }
    fn len(&self) -> u64 {
        self.0.len()
    }
    fn permissions(&self) -> Self::Permissions {
        Permissions(self.0.permissions())
    }
}

/// A single element tuple containing a [`std::fs::File`].
///
/// [`std::fs::File`]: https://doc.rust-lang.org/std/fs/struct.File.html
#[derive(Debug)]
pub struct File(rs_fs::File);

impl fs::File for File {
    type Metadata = Metadata;

    fn metadata(&self) -> Result<Self::Metadata> {
        self.0.metadata().map(Metadata)
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.0.read(buf)
    }
}

impl Write for File {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.0.write(buf)
    }
    fn flush(&mut self) -> Result<()> {
        Ok(())
    }
}

impl Seek for File {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        self.0.seek(pos)
    }
}

/// A single element tuple containing a [`std::fs::OpenOptions`].
///
/// [`std::fs::OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
#[derive(Debug)]
pub struct OpenOptions(rs_fs::OpenOptions);

impl fs::OpenOptions for OpenOptions {
    type File = File;

    fn read(&mut self, read: bool) -> &mut Self {
        self.0.read(read);
        self
    }
    fn write(&mut self, write: bool) -> &mut Self {
        self.0.write(write);
        self
    }
    fn append(&mut self, append: bool) -> &mut Self {
        self.0.append(append);
        self
    }
    fn truncate(&mut self, truncate: bool) -> &mut Self {
        self.0.truncate(truncate);
        self
    }
    fn create(&mut self, create: bool) -> &mut Self {
        self.0.create(create);
        self
    }
    fn create_new(&mut self, create_new: bool) -> &mut Self {
        self.0.create_new(create_new);
        self
    }
    fn open<P: AsRef<Path>>(&self, path: P) -> Result<Self::File> {
        self.0.open(path).map(File)
    }
}

#[cfg(unix)]
impl unix_ext::OpenOptionsExt for OpenOptions {
    fn mode(&mut self, mode: u32) -> &mut Self {
        self.0.mode(mode);
        self
    }
}

/// A single element tuple containing a [`std::fs::DirBuilder`].
///
/// [`std::fs::DirBuilder`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html
#[derive(Debug)]
pub struct DirBuilder(rs_fs::DirBuilder);

impl fs::DirBuilder for DirBuilder {
    fn recursive(&mut self, recursive: bool) -> &mut Self {
        self.0.recursive(recursive);
        self
    }
    fn create<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        self.0.create(path)
    }
}

#[cfg(unix)]
impl unix_ext::DirBuilderExt for DirBuilder {
    fn mode(&mut self, mode: u32) -> &mut Self {
        self.0.mode(mode);
        self
    }
}

/// A single element tuple containing a [`std::fs::DirEntry`].
///
/// [`std::fs::DirEntry`]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html
#[derive(Debug)]
pub struct DirEntry(rs_fs::DirEntry);

impl fs::DirEntry for DirEntry {
    type Metadata = Metadata;
    type FileType = FileType;

    fn path(&self) -> PathBuf {
        self.0.path()
    }
    fn metadata(&self) -> Result<Self::Metadata> {
        self.0.metadata().map(Metadata)
    }
    fn file_type(&self) -> Result<Self::FileType> {
        self.0.file_type().map(FileType)
    }
    fn file_name(&self) -> OsString {
        self.0.file_name()
    }
}

/// A single element tuple containing a [`std::fs::ReadDir`].
///
/// [`std::fs::ReadDir`]: https://doc.rust-lang.org/std/fs/struct.ReadDir.html
#[derive(Debug)]
pub struct ReadDir(rs_fs::ReadDir);

impl Iterator for ReadDir {
    type Item = Result<DirEntry>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|res_dirent| res_dirent.map(DirEntry))
    }
}

/// An empty struct that satisfies [`rsfs::FS`] by calling [`std::fs`] functions.
///
/// [`rsfs::FS`]: ../trait.FS.html
/// [`std::fs`]: https://doc.rust-lang.org/std/fs/
#[derive(Copy, Clone, Debug)]
pub struct FS;

impl fs::GenFS for FS {
    type DirBuilder = DirBuilder;
    type DirEntry = DirEntry;
    type Metadata = Metadata;
    type OpenOptions = OpenOptions;
    type Permissions = Permissions;
    type ReadDir = ReadDir;

    fn metadata<P: AsRef<Path>>(&self, path: P) -> Result<Self::Metadata> {
        rs_fs::metadata(path).map(Metadata)
    }
    fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<Self::ReadDir> {
        rs_fs::read_dir(path).map(ReadDir)
    }
    fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        rs_fs::remove_dir(path)
    }
    fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        rs_fs::remove_dir_all(path)
    }
    fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        rs_fs::remove_file(path)
    }
    fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to: Q) -> Result<()> {
        rs_fs::rename(from, to)
    }
    fn set_permissions<P: AsRef<Path>>(path: P, perm: Self::Permissions) -> Result<()> {
        rs_fs::set_permissions(path, perm.0)
    }
    fn new_openopts(&self) -> Self::OpenOptions {
        OpenOptions(rs_fs::OpenOptions::new())
    }
    fn new_dirbuilder(&self) -> Self::DirBuilder {
        DirBuilder(rs_fs::DirBuilder::new())
    }
}
<commit_msg>disk: formatting changes to be in line with std::fs ordering<commit_after>//! A zero cost wrapper around [`std::fs`] that satisfies [`rsfs::FS`].
//!
//! # Example
//!
//! ```
//! use rsfs::*;
//! use rsfs::unix_ext::*;
//!
//! use rsfs::disk::fs;
//!
//! let fs = fs::FS;
//!
//! let meta = fs.metadata("/").unwrap();
//! assert!(meta.is_dir());
//! assert!(meta.permissions().mode() == 0o755);
//! ```
//!
//! [`rsfs::FS`]: ../trait.FS.html
//! [`std::fs`]: https://doc.rust-lang.org/std/fs/

use std::ffi::OsString;
use std::fs as rs_fs;
use std::io::{Read, Result, Seek, SeekFrom, Write};
use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt};
use std::path::{Path, PathBuf};

use fs;

#[cfg(unix)]
use unix_ext;

/// A single element tuple containing a [`std::fs::DirBuilder`].
///
/// [`std::fs::DirBuilder`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html
#[derive(Debug)]
pub struct DirBuilder(rs_fs::DirBuilder);

impl fs::DirBuilder for DirBuilder {
    fn recursive(&mut self, recursive: bool) -> &mut Self {
        self.0.recursive(recursive);
        self
    }
    fn create<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        self.0.create(path)
    }
}

#[cfg(unix)]
impl unix_ext::DirBuilderExt for DirBuilder {
    fn mode(&mut self, mode: u32) -> &mut Self {
        self.0.mode(mode);
        self
    }
}

/// A single element tuple containing a [`std::fs::DirEntry`].
///
/// [`std::fs::DirEntry`]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html
#[derive(Debug)]
pub struct DirEntry(rs_fs::DirEntry);

impl fs::DirEntry for DirEntry {
    type Metadata = Metadata;
    type FileType = FileType;

    fn path(&self) -> PathBuf {
        self.0.path()
    }
    fn metadata(&self) -> Result<Self::Metadata> {
        self.0.metadata().map(Metadata)
    }
    fn file_type(&self) -> Result<Self::FileType> {
        self.0.file_type().map(FileType)
    }
    fn file_name(&self) -> OsString {
        self.0.file_name()
    }
}

/// A single element tuple containing a [`std::fs::FileType`].
///
/// [`std::fs::FileType`]: https://doc.rust-lang.org/std/fs/struct.FileType.html
#[derive(Debug)]
pub struct FileType(rs_fs::FileType);

impl fs::FileType for FileType {
    fn is_dir(&self) -> bool {
        self.0.is_dir()
    }
    fn is_file(&self) -> bool {
        self.0.is_file()
    }
}

/// A single element tuple containing a [`std::fs::File`].
///
/// [`std::fs::File`]: https://doc.rust-lang.org/std/fs/struct.File.html
#[derive(Debug)]
pub struct File(rs_fs::File);

impl fs::File for File {
    type Metadata = Metadata;

    fn metadata(&self) -> Result<Self::Metadata> {
        self.0.metadata().map(Metadata)
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.0.read(buf)
    }
}

impl Write for File {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.0.write(buf)
    }
    fn flush(&mut self) -> Result<()> {
        Ok(())
    }
}

impl Seek for File {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        self.0.seek(pos)
    }
}

/// A single element tuple containing a [`std::fs::Metadata`].
///
/// [`std::fs::Metadata`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html
#[derive(Debug)]
pub struct Metadata(rs_fs::Metadata);

impl fs::Metadata for Metadata {
    type Permissions = Permissions;
    type FileType = FileType;

    fn file_type(&self) -> Self::FileType {
        FileType(self.0.file_type())
    }
    fn is_dir(&self) -> bool {
        self.0.is_dir()
    }
    fn is_file(&self) -> bool {
        self.0.is_file()
    }
    fn len(&self) -> u64 {
        self.0.len()
    }
    fn permissions(&self) -> Self::Permissions {
        Permissions(self.0.permissions())
    }
}

/// A single element tuple containing a [`std::fs::OpenOptions`].
///
/// [`std::fs::OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
#[derive(Debug)]
pub struct OpenOptions(rs_fs::OpenOptions);

impl fs::OpenOptions for OpenOptions {
    type File = File;

    fn read(&mut self, read: bool) -> &mut Self {
        self.0.read(read);
        self
    }
    fn write(&mut self, write: bool) -> &mut Self {
        self.0.write(write);
        self
    }
    fn append(&mut self, append: bool) -> &mut Self {
        self.0.append(append);
        self
    }
    fn truncate(&mut self, truncate: bool) -> &mut Self {
        self.0.truncate(truncate);
        self
    }
    fn create(&mut self, create: bool) -> &mut Self {
        self.0.create(create);
        self
    }
    fn create_new(&mut self, create_new: bool) -> &mut Self {
        self.0.create_new(create_new);
        self
    }
    fn open<P: AsRef<Path>>(&self, path: P) -> Result<Self::File> {
        self.0.open(path).map(File)
    }
}

#[cfg(unix)]
impl unix_ext::OpenOptionsExt for OpenOptions {
    fn mode(&mut self, mode: u32) -> &mut Self {
        self.0.mode(mode);
        self
    }
}

/// A single element tuple containing a [`std::fs::Permissions`].
///
/// [`std::fs::Permissions`]: https://doc.rust-lang.org/std/fs/struct.Permissions.html
#[derive(Debug)]
pub struct Permissions(rs_fs::Permissions);

impl fs::Permissions for Permissions {
    fn readonly(&self) -> bool {
        self.0.readonly()
    }
    fn set_readonly(&mut self, readonly: bool) {
        self.0.set_readonly(readonly)
    }
}

#[cfg(unix)]
impl unix_ext::PermissionsExt for Permissions {
    fn mode(&self) -> u32 {
        self.0.mode()
    }
    fn set_mode(&mut self, mode: u32) {
        self.0.set_mode(mode)
    }
    fn from_mode(mode: u32) -> Self {
        Permissions(rs_fs::Permissions::from_mode(mode))
    }
}

/// A single element tuple containing a [`std::fs::ReadDir`].
///
/// [`std::fs::ReadDir`]: https://doc.rust-lang.org/std/fs/struct.ReadDir.html
#[derive(Debug)]
pub struct ReadDir(rs_fs::ReadDir);

impl Iterator for ReadDir {
    type Item = Result<DirEntry>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|res_dirent| res_dirent.map(DirEntry))
    }
}

/// An empty struct that satisfies [`rsfs::FS`] by calling [`std::fs`] functions.
///
/// [`rsfs::FS`]: ../trait.FS.html
/// [`std::fs`]: https://doc.rust-lang.org/std/fs/
#[derive(Copy, Clone, Debug)]
pub struct FS;

impl fs::GenFS for FS {
    type DirBuilder = DirBuilder;
    type DirEntry = DirEntry;
    type Metadata = Metadata;
    type OpenOptions = OpenOptions;
    type Permissions = Permissions;
    type ReadDir = ReadDir;

    fn metadata<P: AsRef<Path>>(&self, path: P) -> Result<Self::Metadata> {
        rs_fs::metadata(path).map(Metadata)
    }
    fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<Self::ReadDir> {
        rs_fs::read_dir(path).map(ReadDir)
    }
    fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        rs_fs::remove_dir(path)
    }
    fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        rs_fs::remove_dir_all(path)
    }
    fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        rs_fs::remove_file(path)
    }
    fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to: Q) -> Result<()> {
        rs_fs::rename(from, to)
    }
    fn set_permissions<P: AsRef<Path>>(&self, path: P, perm: Self::Permissions) -> Result<()> {
        rs_fs::set_permissions(path, perm.0)
    }
    fn new_openopts(&self) -> Self::OpenOptions {
        OpenOptions(rs_fs::OpenOptions::new())
    }
    fn new_dirbuilder(&self) -> Self::DirBuilder {
        DirBuilder(rs_fs::DirBuilder::new())
    }
}
<|endoftext|>


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

#![feature(slice_patterns)]

#[macro_use]
extern crate log;
extern crate ilc_base;
extern crate chrono;

use std::io::{BufRead, Write};
use std::borrow::{Cow, ToOwned};
use std::iter::Iterator;

use ilc_base::event::{Event, Time, Type};
use ilc_base::format::{rejoin, strip_one};
use ilc_base::{Context, Decode, Encode};

use log::LogLevel::Info;

use chrono::*;

pub struct Energymech;

static TIME_FORMAT: &'static str = "%H:%M:%S";

pub struct Iter<'a> {
    context: &'a Context,
    input: &'a mut BufRead,
    buffer: Vec<u8>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = ilc_base::Result<Event<'a>>;
    fn next(&mut self) -> Option<ilc_base::Result<Event<'a>>> {
        fn parse_time(context: &Context, time: &str) -> Time {
            let h = time[1..3].parse::<u32>().unwrap();
            let m = time[4..6].parse::<u32>().unwrap();
            let s = time[7..9].parse::<u32>().unwrap();
            if let Some(date) = context.override_date {
                Time::Timestamp(context.timezone
                                       .from_local_date(&date)
                                       .and_time(NaiveTime::from_hms(h, m, s))
                                       .single()
                                       .expect("Transformed log times can't be represented, due \
                                                to timezone transitions")
                                       .timestamp())
            } else {
                Time::Hms(h as u8, m as u8, s as u8)
            }
        }

        loop {
            self.buffer.clear();
            match self.input.read_until(b'\n', &mut self.buffer) {
                Ok(0) | Err(_) => return None,
                Ok(_) => (),
            }

            let buffer = String::from_utf8_lossy(&self.buffer);

            let mut split_tokens: Vec<char> = Vec::new();
            let tokens = buffer.split(|c: char| {
                                   if c.is_whitespace() {
                                       split_tokens.push(c);
                                       true
                                   } else {
                                       false
                                   }
                               })
                               .collect::<Vec<_>>();

            if log_enabled!(Info) {
                info!("Original:  `{}`", buffer);
                info!("Parsing:   {:?}", tokens);
            }

            match &tokens[..tokens.len() - 1] {
                [time, "*", nick, content..] => {
                    return Some(Ok(Event {
                        ty: Type::Action {
                            from: nick.to_owned().into(),
                            content: rejoin(content, &split_tokens[3..]),
                        },
                        time: parse_time(&self.context, time),
                        channel: self.context.channel.clone().map(Into::into),
                    }))
                }
                [time, "***", old, "is", "now", "known", "as", new] => {
                    return Some(Ok(Event {
                        ty: Type::Nick {
                            old_nick: old.to_owned().into(),
                            new_nick: new.to_owned().into(),
                        },
                        time: parse_time(&self.context, time),
                        channel: self.context.channel.clone().map(Into::into),
                    }))
                }
                [time, "***", nick, "sets", "mode:", mode, masks..] => {
                    return Some(Ok(Event {
                        ty: Type::Mode {
                            nick: Some(nick.to_owned().into()),
                            mode: mode.to_owned().into(),
                            masks: rejoin(&masks, &split_tokens[6..]).to_owned().into(),
                        },
                        time: parse_time(&self.context, time),
                        channel: self.context.channel.clone().map(Into::into),
                    }))
                }
                [time, "***", "Joins:", nick, host] => {
                    return Some(Ok(Event {
                        ty: Type::Join {
                            nick: nick.to_owned().into(),
                            mask: Some(strip_one(host).into()),
                        },
                        time: parse_time(&self.context, time),
                        channel: self.context.channel.clone().map(Into::into),
                    }))
                }
                [time, "***", "Parts:", nick, host, reason..] => {
                    return Some(Ok(Event {
                        ty: Type::Part {
                            nick: nick.to_owned().into(),
                            mask: Some(strip_one(host).into()),
                            reason: Some(strip_one(&rejoin(reason, &split_tokens[5..])).into()),
                        },
                        time: parse_time(&self.context, time),
                        channel: self.context.channel.clone().map(Into::into),
                    }))
                }
                [time, "***", "Quits:", nick, host, reason..] => {
                    return Some(Ok(Event {
                        ty: Type::Quit {
                            nick: nick.to_owned().into(),
                            mask: Some(strip_one(host).into()),
                            reason: Some(strip_one(&rejoin(reason, &split_tokens[5..])).into()),
                        },
                        time: parse_time(&self.context, time),
                        channel: self.context.channel.clone().map(Into::into),
                    }))
                }
                [time, "***", nick, "changes", "topic", "to", topic..] => {
                    return Some(Ok(Event {
                        ty: Type::TopicChange {
                            nick: Some(nick.to_owned().into()),
                            new_topic: strip_one(&rejoin(topic, &split_tokens[6..])).into(),
                        },
                        time: parse_time(&self.context, time),
                        channel: self.context.channel.clone().map(Into::into),
                    }))
                }
                [time, nick, content..] if nick.starts_with('<') && nick.ends_with('>') => {
                    return Some(Ok(Event {
                        ty: Type::Msg {
                            from: strip_one(nick).into(),
                            content: rejoin(content, &split_tokens[2..]),
                        },
                        time: parse_time(&self.context, time),
                        channel: self.context.channel.clone().map(Into::into),
                    }))
                }
                _ => (),
            }
        }
    }
}

impl Decode for Energymech {
    fn decode<'a>(&'a mut self,
                  context: &'a Context,
                  input: &'a mut BufRead)
                  -> Box<Iterator<Item = ilc_base::Result<Event<'a>>> + 'a> {
        Box::new(Iter {
            context: context,
            input: input,
            buffer: Vec::new(),
        })
    }
}

impl Encode for Energymech {
    fn encode<'a>(&'a self,
                  context: &'a Context,
                  mut output: &'a mut Write,
                  event: &'a Event)
                  -> ilc_base::Result<()> {
        match event {
            &Event { ty: Type::Msg { ref from, ref content }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] <{}> {}",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              from,
                              content))
            }
            &Event { ty: Type::Action { ref from, ref content }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] * {} {}",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              from,
                              content))
            }
            &Event { ty: Type::Nick { ref old_nick, ref new_nick }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** {} is now known as {}",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              old_nick,
                              new_nick))
            }
            &Event { ty: Type::Mode { ref nick, ref mode, ref masks }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** {} sets mode: {} {}",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick.as_ref().expect("Nickname not present, but required."),
                              mode,
                              masks))
            }
            &Event { ty: Type::Join { ref nick, ref mask }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** Joins: {} ({})",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick,
                              mask.as_ref().expect("Mask not present, but required.")))
            }
            &Event { ty: Type::Part { ref nick, ref mask, ref reason }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** Parts: {} ({}) ({})",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick,
                              mask.as_ref().expect("Mask not present, but required."),
                              reason.as_ref().unwrap_or(&Cow::Borrowed(""))))
            }
            &Event { ty: Type::Quit { ref nick, ref mask, ref reason }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** Quits: {} ({}) ({})",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick,
                              mask.as_ref().expect("Mask not present, but required."),
                              reason.as_ref().expect("Reason not present, but required.")))
            }
            &Event { ty: Type::TopicChange { ref nick, ref new_topic }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** {} changes topic to '{}'",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick.as_ref().expect("Nick not present, but required."),
                              new_topic))
            }
            _ => (),
        }
        Ok(())
    }
}
<commit_msg>Rewrite to remove slice_patterns requirement<commit_after>// Copyright 2015 Till Höppner
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate log;
extern crate ilc_base;
extern crate chrono;

use std::io::{BufRead, Write};
use std::borrow::{Cow, ToOwned};
use std::iter::Iterator;

use ilc_base::event::{Event, Time, Type};
use ilc_base::format::{rejoin, strip_one};
use ilc_base::{Context, Decode, Encode};

use log::LogLevel::Info;

use chrono::*;

pub struct Energymech;

static TIME_FORMAT: &'static str = "%H:%M:%S";

pub struct Iter<'a> {
    context: &'a Context,
    input: &'a mut BufRead,
    buffer: Vec<u8>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = ilc_base::Result<Event<'a>>;
    fn next(&mut self) -> Option<ilc_base::Result<Event<'a>>> {
        fn parse_time(context: &Context, time: &str) -> Time {
            let h = time[1..3].parse::<u32>().unwrap();
            let m = time[4..6].parse::<u32>().unwrap();
            let s = time[7..9].parse::<u32>().unwrap();
            if let Some(date) = context.override_date {
                Time::Timestamp(context.timezone
                                       .from_local_date(&date)
                                       .and_time(NaiveTime::from_hms(h, m, s))
                                       .single()
                                       .expect("Transformed log times can't be represented, due \
                                                to timezone transitions")
                                       .timestamp())
            } else {
                Time::Hms(h as u8, m as u8, s as u8)
            }
        }

        loop {
            self.buffer.clear();
            match self.input.read_until(b'\n', &mut self.buffer) {
                Ok(0) | Err(_) => return None,
                Ok(_) => (),
            }

            let buffer = String::from_utf8_lossy(&self.buffer);

            let mut split_tokens: Vec<char> = Vec::new();
            let tokens = buffer.split(|c: char| {
                                   if c.is_whitespace() {
                                       split_tokens.push(c);
                                       true
                                   } else {
                                       false
                                   }
                               })
                               .collect::<Vec<_>>();

            if log_enabled!(Info) {
                info!("Original:  `{}`", buffer);
                info!("Parsing:   {:?}", tokens);
            }

            // slice pattern matching is not stable as of Feb. 2016 and was replaced with
            // nested if-else chains in this module.

            let len = tokens.len();

            // [21:53:49] * Foo emotes
            if len >= 4 && tokens[1] == "*" {
                return Some(Ok(Event {
                    ty: Type::Action {
                        from: tokens[2].to_owned().into(),
                        content: rejoin(&tokens[3..], &split_tokens[3..]),
                    },
                    time: parse_time(&self.context, tokens[0]),
                    channel: self.context.channel.clone().map(Into::into),
                }));
            }

            if len >= 2 && tokens[1] == "***" {
                // [21:24:57] *** Foo is now known as Bar
                if len >= 8 && tokens[3] == "is" && tokens[4] == "now" && tokens[5] == "known" &&
                   tokens[6] == "as" {
                    return Some(Ok(Event {
                        ty: Type::Nick {
                            old_nick: tokens[2].to_owned().into(),
                            new_nick: tokens[7].to_owned().into(),
                        },
                        time: parse_time(&self.context, tokens[0]),
                        channel: self.context.channel.clone().map(Into::into),
                    }));
                }

                // [23:21:17] *** Paster was kicked by fripp.mozilla.org (Channel flood triggered (limit is 5 lines in 3 secs))
                if len >= 8 && tokens[3] == "was" && tokens[4] == "kicked" && tokens[5] == "by" {
                    return Some(Ok(Event {
                        ty: Type::Kick {
                            kicked_nick: tokens[2].to_owned().into(),
                            kicking_nick: Some(tokens[6].to_owned().into()),
                            kick_message: Some(strip_one(&rejoin(&tokens[7..],
                                                                 &split_tokens[7..]))
                                                   .into()),
                        },
                        time: parse_time(&self.context, tokens[0]),
                        channel: self.context.channel.clone().map(Into::into),
                    }));
                }

                // [21:49:59] *** ChanServ sets mode: +v Foo
                if len >= 7 && tokens[3] == "sets" && tokens[4] == "mode:" {
                    return Some(Ok(Event {
                        ty: Type::Mode {
                            nick: Some(tokens[2].to_owned().into()),
                            mode: tokens[5].to_owned().into(),
                            masks: rejoin(&tokens[6..], &split_tokens[6..]).to_owned().into(),
                        },
                        time: parse_time(&self.context, tokens[0]),
                        channel: self.context.channel.clone().map(Into::into),
                    }));
                }

                // [21:49:59] *** Joins: Foo (host@some.mask)
                if len >= 5 && tokens[2] == "Joins:" {
                    return Some(Ok(Event {
                        ty: Type::Join {
                            nick: tokens[3].to_owned().into(),
                            mask: Some(strip_one(tokens[4]).into()),
                        },
                        time: parse_time(&self.context, tokens[0]),
                        channel: self.context.channel.clone().map(Into::into),
                    }));
                }

                // [03:52:11] *** Parts: Foo (some@host.mask) (A reason? Nah...)
                if len >= 6 && tokens[2] == "Parts:" {
                    return Some(Ok(Event {
                        ty: Type::Part {
                            nick: tokens[3].to_owned().into(),
                            mask: Some(strip_one(tokens[4]).into()),
                            reason: Some(strip_one(&rejoin(&tokens[5..], &split_tokens[5..]))
                                             .into()),
                        },
                        time: parse_time(&self.context, tokens[0]),
                        channel: self.context.channel.clone().map(Into::into),
                    }));
                }

                // [03:48:33] *** Quits: Foo (just@a.hostmask) (Ping timeout: 42 seconds)
                if len >= 6 && tokens[2] == "Quits:" {
                    return Some(Ok(Event {
                        ty: Type::Quit {
                            nick: tokens[3].to_owned().into(),
                            mask: Some(strip_one(tokens[4]).into()),
                            reason: Some(strip_one(&rejoin(&tokens[5..], &split_tokens[5..]))
                                             .into()),
                        },
                        time: parse_time(&self.context, tokens[0]),
                        channel: self.context.channel.clone().map(Into::into),
                    }));
                }

                // [09:44:56] *** Foo changes topic to 'Hi there, why are you reading this comment?'
                if len >= 7 && tokens[3] == "changes" && tokens[4] == "topic" && tokens[5] == "to" {
                    return Some(Ok(Event {
                        ty: Type::TopicChange {
                            nick: Some(tokens[2].to_owned().into()),
                            new_topic: strip_one(&rejoin(&tokens[6..], &split_tokens[6..])).into(),
                        },
                        time: parse_time(&self.context, tokens[0]),
                        channel: self.context.channel.clone().map(Into::into),
                    }));
                }
            }

            // [03:36:01] <Foo> Just some moderately ugly code, nothing special to be found here.
            if len >= 3 && tokens[1].starts_with('<') && tokens[1].ends_with('>') {
                return Some(Ok(Event {
                    ty: Type::Msg {
                        from: strip_one(tokens[1]).into(),
                        content: rejoin(&tokens[2..], &split_tokens[2..]),
                    },
                    time: parse_time(&self.context, tokens[0]),
                    channel: self.context.channel.clone().map(Into::into),
                }));
            }

            // [10:25:22] -playbot- true
            if len >= 3 && tokens[1].starts_with('-') && tokens[1].ends_with('-') {
                return Some(Ok(Event {
                    ty: Type::Notice {
                        from: strip_one(tokens[1]).into(),
                        content: rejoin(&tokens[2..], &split_tokens[2..]),
                    },
                    time: parse_time(&self.context, tokens[0]),
                    channel: self.context.channel.clone().map(Into::into),
                }));
            }
        }
    }
}

impl Decode for Energymech {
    fn decode<'a>(&'a mut self,
                  context: &'a Context,
                  input: &'a mut BufRead)
                  -> Box<Iterator<Item = ilc_base::Result<Event<'a>>> + 'a> {
        Box::new(Iter {
            context: context,
            input: input,
            buffer: Vec::new(),
        })
    }
}

impl Encode for Energymech {
    fn encode<'a>(&'a self,
                  context: &'a Context,
                  mut output: &'a mut Write,
                  event: &'a Event)
                  -> ilc_base::Result<()> {
        match event {
            &Event { ty: Type::Msg { ref from, ref content }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] <{}> {}",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              from,
                              content))
            }
            &Event { ty: Type::Action { ref from, ref content }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] * {} {}",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              from,
                              content))
            }
            &Event { ty: Type::Nick { ref old_nick, ref new_nick }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** {} is now known as {}",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              old_nick,
                              new_nick))
            }
            &Event { ty: Type::Mode { ref nick, ref mode, ref masks }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** {} sets mode: {} {}",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick.as_ref().expect("Nickname not present, but required."),
                              mode,
                              masks))
            }
            &Event { ty: Type::Join { ref nick, ref mask }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** Joins: {} ({})",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick,
                              mask.as_ref().expect("Mask not present, but required.")))
            }
            &Event { ty: Type::Part { ref nick, ref mask, ref reason }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** Parts: {} ({}) ({})",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick,
                              mask.as_ref().expect("Mask not present, but required."),
                              reason.as_ref().unwrap_or(&Cow::Borrowed(""))))
            }
            &Event { ty: Type::Quit { ref nick, ref mask, ref reason }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** Quits: {} ({}) ({})",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick,
                              mask.as_ref().expect("Mask not present, but required."),
                              reason.as_ref().expect("Reason not present, but required.")))
            }
            &Event { ty: Type::TopicChange { ref nick, ref new_topic }, ref time, .. } => {
                try!(writeln!(&mut output,
                              "[{}] *** {} changes topic to '{}'",
                              time.with_format(&context.timezone, TIME_FORMAT),
                              nick.as_ref().expect("Nick not present, but required."),
                              new_topic))
            }
            _ => (),
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Starts a timely dataflow execution from configuration information and per-worker logic.

use timely_communication::{initialize, Configuration, Allocator, WorkerGuards};
use dataflow::scopes::{Root, Child};
use logging::LoggerConfig;

/// Executes a single-threaded timely dataflow computation.
///
/// The `example` method takes a closure on a `Scope` which it executes to initialize and run a
/// timely dataflow computation on a single thread. This method is intended for use in examples,
/// rather than programs that may need to run across multiple workers.
///
/// The `example` method returns whatever the single worker returns from its closure.
/// This is often nothing, but the worker can return something about the data it saw in order to
/// test computations.
///
/// The method aggressively unwraps returned `Result<_>` types.
///
/// #Examples
///
/// The simplest example creates a stream of data and inspects it.
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect};
///
/// timely::example(|scope| {
///     (0..10).to_stream(scope)
///            .inspect(|x| println!("seen: {:?}", x));
/// });
/// ```
///
/// This next example captures the data and displays them once the computation is complete.
///
/// More precisely, the example captures a stream of events (receiving batches of data,
/// updates to input capabilities) and displays these events.
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect, Capture};
/// use timely::dataflow::operators::capture::Extract;
///
/// let data = timely::example(|scope| {
///     (0..10).to_stream(scope)
///            .inspect(|x| println!("seen: {:?}", x))
///            .capture()
/// });
///
/// // the extracted data should have data (0..10) at timestamp 0.
/// assert_eq!(data.extract()[0].1, (0..10).collect::<Vec<_>>());
/// ```
pub fn example<T, F>(func: F) -> T
where T: Send+'static,
      F: Fn(&mut Child<Root<Allocator>,u64>)->T+Send+Sync+'static {
    let logging_config: LoggerConfig = Default::default();
    let timely_logging = logging_config.timely_logging.clone();
    let guards = initialize(Configuration::Thread, move |allocator| {
        let mut root = Root::new(allocator, timely_logging.clone());
        let result = root.dataflow(|x| func(x));
        while root.step() { }
        result
    }, logging_config.communication_logging);

    guards.unwrap() // assert the computation started correctly
          .join()   // wait for the worker to finish
          .pop()    // grab the known-to-exist result
          .unwrap() // assert that the result exists
          .unwrap() // crack open the result to get a T
}

/// Executes a timely dataflow from a configuration and per-communicator logic.
///
/// The `execute` method takes a `Configuration` and spins up some number of
/// workers threads, each of which execute the supplied closure to construct
/// and run a timely dataflow computation.
///
/// The closure may return a `T: Send+'static`, and `execute` returns a result
/// containing a `WorkerGuards<T>` (or error information), which can be joined
/// to recover the result `T` values from the local workers.
///
/// #Examples
/// ```rust,ignore
/// use timely::dataflow::operators::{ToStream, Inspect};
///
/// // execute a timely dataflow using three worker threads.
/// timely::execute(timely::Configuration::Process(3), |worker| {
///     worker.dataflow::<(),_,_>(|scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x));
///     })
/// }).unwrap();
/// ```
///
/// The following example demonstrates how one can extract data from a multi-worker execution.
/// In a multi-process setting, each process will only receive those records present at workers
/// in the process.
///
/// ```rust,ignore
/// use std::sync::{Arc, Mutex};
/// use timely::dataflow::operators::{ToStream, Inspect, Capture};
/// use timely::dataflow::operators::capture::Extract;
///
/// // get send and recv endpoints, wrap send to share
/// let (send, recv) = ::std::sync::mpsc::channel();
/// let send = Arc::new(Mutex::new(send));
///
/// // execute a timely dataflow using three worker threads.
/// timely::execute(timely::Configuration::Process(3), move |worker| {
///     let send = send.lock().unwrap().clone();
///     worker.dataflow::<(),_,_>(move |scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x))
///                .capture_into(send);
///     });
/// }).unwrap();
///
/// // the extracted data should have data (0..10) thrice at timestamp 0.
/// assert_eq!(recv.extract()[0].1, (0..30).map(|x| x / 3).collect::<Vec<_>>());
/// ```
pub fn execute<T, F>(config: Configuration, func: F) -> Result<WorkerGuards<T>,String>
where T:Send+'static,
      F: Fn(&mut Root<Allocator>)->T+Send+Sync+'static {
    // let logging_config = ::logging::blackhole();
    execute_logging(config, Default::default(), func)
}

/// Executes a timely dataflow from a configuration and per-communicator logic.
///
/// TODO(andreal)
///
/// Supports providing a logging configuration.
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect};
/// use timely::logging::{LogManager, LoggerConfig};
///
/// let mut log_manager = LogManager::new();
///
/// // execute a timely dataflow using command line parameters
/// timely::execute_logging(timely::Configuration::Process(3), LoggerConfig::new(log_manager), |worker| {
///     worker.dataflow::<(),_,_>(|scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x));
///     })
/// }).unwrap();
/// ```
pub fn execute_logging<T, F>(config: Configuration, logging_config: LoggerConfig, func: F) -> Result<WorkerGuards<T>,String>
where T:Send+'static,
      F: Fn(&mut Root<Allocator>)->T+Send+Sync+'static {
    let timely_logging = logging_config.timely_logging.clone();
    initialize(config, move |allocator| {
        let mut root = Root::new(allocator, timely_logging.clone());
        let result = func(&mut root);
        while root.step() { }
        result
    }, logging_config.communication_logging.clone())
}

/// Executes a timely dataflow from supplied arguments and per-communicator logic.
///
/// The `execute` method takes arguments (typically `std::env::args()`) and spins up some number of
/// workers threads, each of which execute the supplied closure to construct and run a timely
/// dataflow computation.
///
/// The closure may return a `T: Send+'static`, and `execute` returns a result
/// containing a `WorkerGuards<T>` (or error information), which can be joined
/// to recover the result `T` values from the local workers.
///
/// The arguments `execute` currently understands are:
///
/// `-w, --workers`: number of per-process worker threads.
///
/// `-n, --processes`: number of processes involved in the computation.
///
/// `-p, --process`: identity of this process; from 0 to n-1.
///
/// `-h, --hostfile`: a text file whose lines are "hostname:port" in order of process identity.
/// If not specified, `localhost` will be used, with port numbers increasing from 2101 (chosen
/// arbitrarily).
///
/// #Examples
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect};
///
/// // execute a timely dataflow using command line parameters
/// timely::execute_from_args(std::env::args(), |worker| {
///     worker.dataflow::<(),_,_>(|scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x));
///     })
/// }).unwrap();
/// ```
/// ```ignore
/// host0% cargo run -- -w 2 -n 4 -h hosts.txt -p 0
/// host1% cargo run -- -w 2 -n 4 -h hosts.txt -p 1
/// host2% cargo run -- -w 2 -n 4 -h hosts.txt -p 2
/// host3% cargo run -- -w 2 -n 4 -h hosts.txt -p 3
/// ```
/// ```ignore
/// % cat hosts.txt
/// host0:port
/// host1:port
/// host2:port
/// host3:port
/// ```
pub fn execute_from_args<I, T, F>(iter: I, func: F) -> Result<WorkerGuards<T>,String>
    where I: Iterator<Item=String>,
          T:Send+'static,
          F: Fn(&mut Root<Allocator>)->T+Send+Sync+'static, {
    // let logging_config = ::logging::blackhole();
    execute_from_args_logging(iter, Default::default(), func)
}

/// Executes a timely dataflow from supplied arguments and per-communicator logic.
///
/// TODO(andreal)
///
/// Supports providing a logging configuration.
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect};
/// use timely::logging::{LogManager, LoggerConfig};
///
/// let mut log_manager = LogManager::new();
///
/// // execute a timely dataflow using command line parameters
/// timely::execute_from_args_logging(std::env::args(), LoggerConfig::new(log_manager), |worker| {
///     worker.dataflow::<(),_,_>(|scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x));
///     })
/// }).unwrap();
/// ```
pub fn execute_from_args_logging<I, T, F>(iter: I, logging_config: LoggerConfig, func: F) -> Result<WorkerGuards<T>,String>
    where I: Iterator<Item=String>,
          T:Send+'static,
          F: Fn(&mut Root<Allocator>)->T+Send+Sync+'static, {
    execute_logging(try!(Configuration::from_args(iter)), logging_config, func)
}
<commit_msg>re-enable and fix docstring tests<commit_after>//! Starts a timely dataflow execution from configuration information and per-worker logic.

use timely_communication::{initialize, Configuration, Allocator, WorkerGuards};
use dataflow::scopes::{Root, Child};
use logging::LoggerConfig;

/// Executes a single-threaded timely dataflow computation.
///
/// The `example` method takes a closure on a `Scope` which it executes to initialize and run a
/// timely dataflow computation on a single thread. This method is intended for use in examples,
/// rather than programs that may need to run across multiple workers.
///
/// The `example` method returns whatever the single worker returns from its closure.
/// This is often nothing, but the worker can return something about the data it saw in order to
/// test computations.
///
/// The method aggressively unwraps returned `Result<_>` types.
///
/// #Examples
///
/// The simplest example creates a stream of data and inspects it.
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect};
///
/// timely::example(|scope| {
///     (0..10).to_stream(scope)
///            .inspect(|x| println!("seen: {:?}", x));
/// });
/// ```
///
/// This next example captures the data and displays them once the computation is complete.
///
/// More precisely, the example captures a stream of events (receiving batches of data,
/// updates to input capabilities) and displays these events.
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect, Capture};
/// use timely::dataflow::operators::capture::Extract;
///
/// let data = timely::example(|scope| {
///     (0..10).to_stream(scope)
///            .inspect(|x| println!("seen: {:?}", x))
///            .capture()
/// });
///
/// // the extracted data should have data (0..10) at timestamp 0.
/// assert_eq!(data.extract()[0].1, (0..10).collect::<Vec<_>>());
/// ```
pub fn example<T, F>(func: F) -> T
where T: Send+'static,
      F: Fn(&mut Child<Root<Allocator>,u64>)->T+Send+Sync+'static {
    let logging_config: LoggerConfig = Default::default();
    let timely_logging = logging_config.timely_logging.clone();
    let guards = initialize(Configuration::Thread, move |allocator| {
        let mut root = Root::new(allocator, timely_logging.clone());
        let result = root.dataflow(|x| func(x));
        while root.step() { }
        result
    }, logging_config.communication_logging);

    guards.unwrap() // assert the computation started correctly
          .join()   // wait for the worker to finish
          .pop()    // grab the known-to-exist result
          .unwrap() // assert that the result exists
          .unwrap() // crack open the result to get a T
}

/// Executes a timely dataflow from a configuration and per-communicator logic.
///
/// The `execute` method takes a `Configuration` and spins up some number of
/// workers threads, each of which execute the supplied closure to construct
/// and run a timely dataflow computation.
///
/// The closure may return a `T: Send+'static`, and `execute` returns a result
/// containing a `WorkerGuards<T>` (or error information), which can be joined
/// to recover the result `T` values from the local workers.
///
/// #Examples
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect};
///
/// // execute a timely dataflow using three worker threads.
/// timely::execute(timely::Configuration::Process(3), |worker| {
///     worker.dataflow::<(),_,_>(|scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x));
///     })
/// }).unwrap();
/// ```
///
/// The following example demonstrates how one can extract data from a multi-worker execution.
/// In a multi-process setting, each process will only receive those records present at workers
/// in the process.
///
/// ```rust
/// use std::sync::{Arc, Mutex};
/// use timely::dataflow::operators::{ToStream, Inspect, Capture};
/// use timely::dataflow::operators::capture::Extract;
///
/// // get send and recv endpoints, wrap send to share
/// let (send, recv) = ::std::sync::mpsc::channel();
/// let send = Arc::new(Mutex::new(send));
///
/// // execute a timely dataflow using three worker threads.
/// timely::execute(timely::Configuration::Process(3), move |worker| {
///     let send = send.lock().unwrap().clone();
///     worker.dataflow::<(),_,_>(move |scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x))
///                .capture_into(send);
///     });
/// }).unwrap();
///
/// // the extracted data should have data (0..10) thrice at timestamp 0.
/// assert_eq!(recv.extract()[0].1, (0..30).map(|x| x / 3).collect::<Vec<_>>());
/// ```
pub fn execute<T, F>(config: Configuration, func: F) -> Result<WorkerGuards<T>,String>
where T:Send+'static,
      F: Fn(&mut Root<Allocator>)->T+Send+Sync+'static {
    // let logging_config = ::logging::blackhole();
    execute_logging(config, Default::default(), func)
}

/// Executes a timely dataflow from a configuration and per-communicator logic.
///
/// TODO(andreal)
///
/// Supports providing a logging configuration.
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect};
/// use timely::logging::{LoggerConfig, EventPusherTee};
///
/// let logger_config = LoggerConfig::new(
///     |_setup| EventPusherTee::new() /* setup logging destinations */,
///     |_setup| EventPusherTee::new() /* setup logging destinations */);
///
/// // execute a timely dataflow using command line parameters
/// timely::execute_logging(timely::Configuration::Process(3), logger_config, |worker| {
///     worker.dataflow::<(),_,_>(|scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x));
///     })
/// }).unwrap();
/// ```
pub fn execute_logging<T, F>(config: Configuration, logging_config: LoggerConfig, func: F) -> Result<WorkerGuards<T>,String>
where T:Send+'static,
      F: Fn(&mut Root<Allocator>)->T+Send+Sync+'static {
    let timely_logging = logging_config.timely_logging.clone();
    initialize(config, move |allocator| {
        let mut root = Root::new(allocator, timely_logging.clone());
        let result = func(&mut root);
        while root.step() { }
        result
    }, logging_config.communication_logging.clone())
}

/// Executes a timely dataflow from supplied arguments and per-communicator logic.
///
/// The `execute` method takes arguments (typically `std::env::args()`) and spins up some number of
/// workers threads, each of which execute the supplied closure to construct and run a timely
/// dataflow computation.
///
/// The closure may return a `T: Send+'static`, and `execute` returns a result
/// containing a `WorkerGuards<T>` (or error information), which can be joined
/// to recover the result `T` values from the local workers.
///
/// The arguments `execute` currently understands are:
///
/// `-w, --workers`: number of per-process worker threads.
///
/// `-n, --processes`: number of processes involved in the computation.
///
/// `-p, --process`: identity of this process; from 0 to n-1.
///
/// `-h, --hostfile`: a text file whose lines are "hostname:port" in order of process identity.
/// If not specified, `localhost` will be used, with port numbers increasing from 2101 (chosen
/// arbitrarily).
///
/// #Examples
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect};
///
/// // execute a timely dataflow using command line parameters
/// timely::execute_from_args(std::env::args(), |worker| {
///     worker.dataflow::<(),_,_>(|scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x));
///     })
/// }).unwrap();
/// ```
/// ```ignore
/// host0% cargo run -- -w 2 -n 4 -h hosts.txt -p 0
/// host1% cargo run -- -w 2 -n 4 -h hosts.txt -p 1
/// host2% cargo run -- -w 2 -n 4 -h hosts.txt -p 2
/// host3% cargo run -- -w 2 -n 4 -h hosts.txt -p 3
/// ```
/// ```ignore
/// % cat hosts.txt
/// host0:port
/// host1:port
/// host2:port
/// host3:port
/// ```
pub fn execute_from_args<I, T, F>(iter: I, func: F) -> Result<WorkerGuards<T>,String>
    where I: Iterator<Item=String>,
          T:Send+'static,
          F: Fn(&mut Root<Allocator>)->T+Send+Sync+'static, {
    execute_from_args_logging(iter, Default::default(), func)
}

/// Executes a timely dataflow from supplied arguments and per-communicator logic.
///
/// TODO(andreal)
///
/// Supports providing a logging configuration.
///
/// ```rust
/// use timely::dataflow::operators::{ToStream, Inspect};
/// use timely::logging::{LoggerConfig, EventPusherTee};
///
/// let logger_config = LoggerConfig::new(
///     |_setup| EventPusherTee::new() /* setup logging destinations */,
///     |_setup| EventPusherTee::new() /* setup logging destinations */);
///
/// // execute a timely dataflow using command line parameters
/// timely::execute_from_args_logging(std::env::args(), logger_config, |worker| {
///     worker.dataflow::<(),_,_>(|scope| {
///         (0..10).to_stream(scope)
///                .inspect(|x| println!("seen: {:?}", x));
///     })
/// }).unwrap();
/// ```
pub fn execute_from_args_logging<I, T, F>(iter: I, logging_config: LoggerConfig, func: F) -> Result<WorkerGuards<T>,String>
    where I: Iterator<Item=String>,
          T:Send+'static,
          F: Fn(&mut Root<Allocator>)->T+Send+Sync+'static, {
    execute_logging(try!(Configuration::from_args(iter)), logging_config, func)
}
<|endoftext|>