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]
25macro_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]
58macro_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]
91macro_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)]
103mod 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