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}