| 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 | |