Skip to main content

rotor_tools/
loop_ext.rs

1//! The traits which make main loop construction nicer
2use rotor::{Machine, Scope, EarlyScope, Loop, LoopInstance, SpawnError};
3use rotor::{Response, Void};
4
5
6/// Convenience enhancements to the main loop creator
7pub trait LoopExt<M> {
8    /// This method is useful for things that have a state machine and an
9    /// accessor to it.
10    ///
11    /// Function looks a little bit complicated with generic params. But it
12    /// solves very useful pattern in easier way.
13    ///
14    /// Examples:
15    ///
16    /// * `rotor_dns::create_resolve()`
17    /// * `rotor_carbon::connect_ip()`
18    ///
19    /// Usage is simple (carbon example):
20    ///
21    /// ```ignore
22    /// let sink = loop_inst.add_and_fetch(Fsm::Carbon, |scope| {
23    ///     connect_ip(addr, scope)
24    /// });
25    /// ```
26    ///
27    /// Compare it to *traditional* way:
28    ///
29    /// ```ignore
30    /// let mut sink_opt = None;
31    /// loop_creator.add_machine_with(|scope| {
32    ///     let (fsm, sink) = connect_ip(addr, scope).unwrap();
33    ///     sink_opt = Some(sink);
34    ///     Ok(Fsm::Carbon(fsm))
35    /// }).unwrap();
36    /// let sink = sink_opt.unwrap();
37    /// ```
38    ///
39    fn add_and_fetch<F, W, T, N>(&mut self, fsm_wrapper: W, fun: F)
40        -> Result<T, SpawnError<()>>
41        where W: FnOnce(N) -> M,
42              F: FnOnce(&mut EarlyScope) -> Response<(N, T), Void>;
43}
44
45/// Convenience enhancements to the main loop creator instance
46pub trait LoopInstanceExt<M: Machine> {
47    /// This method is useful for things that have a state machine and an
48    /// accessor to it.
49    ///
50    /// Function looks a little bit complicated with generic params. But it
51    /// solves very useful pattern in easier way.
52    ///
53    /// Examples:
54    ///
55    /// * `rotor_dns::create_resolve()`
56    /// * `rotor_carbon::connect_ip()`
57    ///
58    /// Usage is simple (carbon example):
59    ///
60    /// ```ignore
61    /// let sink = loop_inst.add_and_fetch(Fsm::Carbon, |scope| {
62    ///     connect_ip(addr, scope)
63    /// });
64    /// ```
65    ///
66    /// Compare it to *traditional* way:
67    ///
68    /// ```ignore
69    /// let mut sink_opt = None;
70    /// loop_creator.add_machine_with(|scope| {
71    ///     let (fsm, sink) = connect_ip(addr, scope).unwrap();
72    ///     sink_opt = Some(sink);
73    ///     Ok(Fsm::Carbon(fsm))
74    /// }).unwrap();
75    /// let sink = sink_opt.unwrap();
76    /// ```
77    ///
78    fn add_and_fetch<F, W, T, N>(&mut self, fsm_wrapper: W, fun: F)
79        -> Result<T, SpawnError<()>>
80        where W: FnOnce(N) -> M,
81              F: FnOnce(&mut Scope<M::Context>) -> Response<(N, T), Void>;
82}
83
84impl<M: Machine> LoopExt<M> for Loop<M> {
85    fn add_and_fetch<F, W, T, N>(&mut self, fsm_wrapper: W, fun: F)
86        -> Result<T, SpawnError<()>>
87        where W: FnOnce(N) -> M,
88              F: FnOnce(&mut EarlyScope) -> Response<(N, T), Void>
89    {
90        let mut result_opt = None;
91        try!(self.add_machine_with(|scope| {
92            fun(scope).wrap(|(fsm, value)| {
93                result_opt = Some(value);
94                fsm_wrapper(fsm)
95            })
96        }));
97        Ok(result_opt.unwrap())
98    }
99}
100
101
102impl<M: Machine> LoopInstanceExt<M> for LoopInstance<M> {
103    fn add_and_fetch<F, W, T, N>(&mut self, fsm_wrapper: W, fun: F)
104        -> Result<T, SpawnError<()>>
105        where W: FnOnce(N) -> M,
106              F: FnOnce(&mut Scope<M::Context>) -> Response<(N, T), Void>
107    {
108        let mut result_opt = None;
109        try!(self.add_machine_with(|scope| {
110            fun(scope).wrap(|(fsm, value)| {
111                result_opt = Some(value);
112                fsm_wrapper(fsm)
113            })
114        }));
115        Ok(result_opt.unwrap())
116    }
117}