1 | //! Macros for helping with common operations in Calloop. |
2 | |
3 | /// Register a set of event sources. Effectively calls |
4 | /// [`EventSource::register()`] for all the sources provided. |
5 | /// |
6 | /// Usage: |
7 | /// |
8 | /// ```none,actually-rust-but-see-https://github.com/rust-lang/rust/issues/63193 |
9 | /// calloop::batch_register!( |
10 | /// poll, token_factory, |
11 | /// self.source_one, |
12 | /// self.source_two, |
13 | /// self.source_three, |
14 | /// self.source_four, |
15 | /// ) |
16 | /// ``` |
17 | /// |
18 | /// Note that there is no scope for customisation; if you need to do special |
19 | /// things with a particular source, you'll need to leave it off the list. Also |
20 | /// note that this only does try-or-early-return error handling in the order |
21 | /// that you list the sources; if you need anything else, don't use this macro. |
22 | /// |
23 | /// [`EventSource::register()`]: crate::EventSource::register() |
24 | #[macro_export ] |
25 | macro_rules! batch_register { |
26 | ($poll:ident, $token_fac:ident, $( $source:expr ),* $(,)?) => { |
27 | { |
28 | $( |
29 | $source.register($poll, $token_fac)?; |
30 | )* |
31 | $crate::Result::<_>::Ok(()) |
32 | } |
33 | }; |
34 | } |
35 | |
36 | /// Reregister a set of event sources. Effectively calls |
37 | /// [`EventSource::reregister()`] for all the sources provided. |
38 | /// |
39 | /// Usage: |
40 | /// |
41 | /// ```none,actually-rust-but-see-https://github.com/rust-lang/rust/issues/63193 |
42 | /// calloop::batch_reregister!( |
43 | /// poll, token_factory, |
44 | /// self.source_one, |
45 | /// self.source_two, |
46 | /// self.source_three, |
47 | /// self.source_four, |
48 | /// ) |
49 | /// ``` |
50 | /// |
51 | /// Note that there is no scope for customisation; if you need to do special |
52 | /// things with a particular source, you'll need to leave it off the list. Also |
53 | /// note that this only does try-or-early-return error handling in the order |
54 | /// that you list the sources; if you need anything else, don't use this macro. |
55 | /// |
56 | /// [`EventSource::reregister()`]: crate::EventSource::reregister() |
57 | #[macro_export ] |
58 | macro_rules! batch_reregister { |
59 | ($poll:ident, $token_fac:ident, $( $source:expr ),* $(,)?) => { |
60 | { |
61 | $( |
62 | $source.reregister($poll, $token_fac)?; |
63 | )* |
64 | $crate::Result::<_>::Ok(()) |
65 | } |
66 | }; |
67 | } |
68 | |
69 | /// Unregister a set of event sources. Effectively calls |
70 | /// [`EventSource::unregister()`] for all the sources provided. |
71 | /// |
72 | /// Usage: |
73 | /// |
74 | /// ```none,actually-rust-but-see-https://github.com/rust-lang/rust/issues/63193 |
75 | /// calloop::batch_unregister!( |
76 | /// poll, |
77 | /// self.source_one, |
78 | /// self.source_two, |
79 | /// self.source_three, |
80 | /// self.source_four, |
81 | /// ) |
82 | /// ``` |
83 | /// |
84 | /// Note that there is no scope for customisation; if you need to do special |
85 | /// things with a particular source, you'll need to leave it off the list. Also |
86 | /// note that this only does try-or-early-return error handling in the order |
87 | /// that you list the sources; if you need anything else, don't use this macro. |
88 | /// |
89 | /// [`EventSource::unregister()`]: crate::EventSource::unregister() |
90 | #[macro_export ] |
91 | macro_rules! batch_unregister { |
92 | ($poll:ident, $( $source:expr ),* $(,)?) => { |
93 | { |
94 | $( |
95 | $source.unregister($poll)?; |
96 | )* |
97 | $crate::Result::<_>::Ok(()) |
98 | } |
99 | }; |
100 | } |
101 | |
102 | #[cfg (test)] |
103 | mod tests { |
104 | use std::time::Duration; |
105 | |
106 | use crate::{ |
107 | ping::{make_ping, PingSource}, |
108 | EventSource, PostAction, |
109 | }; |
110 | |
111 | struct BatchSource { |
112 | ping0: PingSource, |
113 | ping1: PingSource, |
114 | ping2: PingSource, |
115 | } |
116 | |
117 | impl EventSource for BatchSource { |
118 | type Event = usize; |
119 | type Metadata = (); |
120 | type Ret = (); |
121 | type Error = Box<dyn std::error::Error + Sync + Send>; |
122 | |
123 | fn process_events<F>( |
124 | &mut self, |
125 | readiness: crate::Readiness, |
126 | token: crate::Token, |
127 | mut callback: F, |
128 | ) -> Result<crate::PostAction, Self::Error> |
129 | where |
130 | F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, |
131 | { |
132 | self.ping0 |
133 | .process_events(readiness, token, |_, m| callback(0, m))?; |
134 | self.ping1 |
135 | .process_events(readiness, token, |_, m| callback(1, m))?; |
136 | self.ping2 |
137 | .process_events(readiness, token, |_, m| callback(2, m))?; |
138 | Ok(PostAction::Continue) |
139 | } |
140 | |
141 | fn register( |
142 | &mut self, |
143 | poll: &mut crate::Poll, |
144 | token_factory: &mut crate::TokenFactory, |
145 | ) -> crate::Result<()> { |
146 | crate::batch_register!(poll, token_factory, self.ping0, self.ping1, self.ping2) |
147 | } |
148 | |
149 | fn reregister( |
150 | &mut self, |
151 | poll: &mut crate::Poll, |
152 | token_factory: &mut crate::TokenFactory, |
153 | ) -> crate::Result<()> { |
154 | crate::batch_reregister!(poll, token_factory, self.ping0, self.ping1, self.ping2) |
155 | } |
156 | |
157 | fn unregister(&mut self, poll: &mut crate::Poll) -> crate::Result<()> { |
158 | crate::batch_unregister!(poll, self.ping0, self.ping1, self.ping2) |
159 | } |
160 | } |
161 | |
162 | #[test ] |
163 | fn test_batch_operations() { |
164 | let mut fired = [false; 3]; |
165 | |
166 | let (send0, ping0) = make_ping().unwrap(); |
167 | let (send1, ping1) = make_ping().unwrap(); |
168 | let (send2, ping2) = make_ping().unwrap(); |
169 | |
170 | let top = BatchSource { |
171 | ping0, |
172 | ping1, |
173 | ping2, |
174 | }; |
175 | |
176 | let mut event_loop = crate::EventLoop::<[bool; 3]>::try_new().unwrap(); |
177 | let handle = event_loop.handle(); |
178 | |
179 | let token = handle |
180 | .insert_source(top, |idx, _, fired| { |
181 | fired[idx] = true; |
182 | }) |
183 | .unwrap(); |
184 | |
185 | send0.ping(); |
186 | send1.ping(); |
187 | send2.ping(); |
188 | |
189 | event_loop |
190 | .dispatch(Duration::new(0, 0), &mut fired) |
191 | .unwrap(); |
192 | |
193 | assert_eq!(fired, [true; 3]); |
194 | |
195 | fired = [false; 3]; |
196 | |
197 | handle.update(&token).unwrap(); |
198 | |
199 | send0.ping(); |
200 | send1.ping(); |
201 | send2.ping(); |
202 | |
203 | event_loop |
204 | .dispatch(Duration::new(0, 0), &mut fired) |
205 | .unwrap(); |
206 | |
207 | assert_eq!(fired, [true; 3]); |
208 | |
209 | fired = [false; 3]; |
210 | |
211 | handle.remove(token); |
212 | |
213 | send0.ping(); |
214 | send1.ping(); |
215 | send2.ping(); |
216 | |
217 | event_loop |
218 | .dispatch(Duration::new(0, 0), &mut fired) |
219 | .unwrap(); |
220 | |
221 | assert_eq!(fired, [false; 3]); |
222 | } |
223 | } |
224 | |