zng_app/event/
args.rs
1use std::{
2 any::Any,
3 fmt,
4 sync::{
5 Arc,
6 atomic::{AtomicBool, Ordering::Relaxed},
7 },
8};
9
10pub trait EventArgs: AnyEventArgs + Clone {
16 fn handle<F, R>(&self, handler: F) -> Option<R>
20 where
21 F: FnOnce(&Self) -> R,
22 {
23 if self.propagation().is_stopped() {
24 None
25 } else {
26 let r = handler(self);
27 self.propagation().stop();
28 Some(r)
29 }
30 }
31}
32
33pub trait AnyEventArgs: fmt::Debug + Send + Sync + Any {
35 fn clone_any(&self) -> Box<dyn AnyEventArgs>;
37
38 fn as_any(&self) -> &dyn Any;
40
41 fn timestamp(&self) -> crate::DInstant;
43
44 fn delivery_list(&self, list: &mut UpdateDeliveryList);
46
47 fn propagation(&self) -> &EventPropagationHandle;
52}
53
54#[derive(Debug, Clone)]
61pub struct EventPropagationHandle(Arc<AtomicBool>);
62impl EventPropagationHandle {
63 pub fn new() -> Self {
65 EventPropagationHandle(Arc::new(AtomicBool::new(false)))
66 }
67
68 pub fn stop(&self) {
70 self.0.store(true, Relaxed);
73 }
74
75 pub fn is_stopped(&self) -> bool {
84 self.0.load(Relaxed)
85 }
86}
87impl Default for EventPropagationHandle {
88 fn default() -> Self {
89 EventPropagationHandle::new()
90 }
91}
92impl PartialEq for EventPropagationHandle {
93 fn eq(&self, other: &Self) -> bool {
94 Arc::ptr_eq(&self.0, &other.0)
95 }
96}
97impl Eq for EventPropagationHandle {}
98impl std::hash::Hash for EventPropagationHandle {
99 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
100 let ptr = Arc::as_ptr(&self.0) as usize;
101 std::hash::Hash::hash(&ptr, state);
102 }
103}
104
105#[macro_export]
155macro_rules! event_args {
156 ($(
157 $(#[$outer:meta])*
158 $vis:vis struct $Args:ident {
159 $($(#[$arg_outer:meta])* $arg_vis:vis $arg:ident : $arg_ty:ty,)*
160 ..
161 $(#[$delivery_list_outer:meta])*
162 fn delivery_list(&$self:ident, $delivery_list_ident:ident: &mut UpdateDeliveryList) { $($delivery_list:tt)* }
163
164 $(
165 $(#[$validate_outer:meta])*
166 fn validate(&$self_v:ident) -> Result<(), $ValidationError:path> { $($validate:tt)+ }
167 )?
168 }
169 )+) => {$(
170 $crate::__event_args! {
171 $(#[$outer])*
172 $vis struct $Args {
173 $($(#[$arg_outer])* $arg_vis $arg: $arg_ty,)*
174
175 ..
176
177 $(#[$delivery_list_outer])*
178 fn delivery_list(&$self, $delivery_list_ident: &mut UpdateDeliveryList) { $($delivery_list)* }
179
180 $(
181 $(#[$validate_outer])*
182 fn validate(&$self_v) -> Result<(), $ValidationError> { $($validate)+ }
183 )?
184 }
185 }
186 )+};
187}
188#[doc(hidden)]
189#[macro_export]
190macro_rules! __event_args {
191 (
193 $(#[$outer:meta])*
194 $vis:vis struct $Args:ident {
195 $($(#[$arg_outer:meta])* $arg_vis:vis $arg:ident : $arg_ty:ty,)*
196 ..
197 $(#[$delivery_list_outer:meta])*
198 fn delivery_list(&$self:ident, $delivery_list_ident:ident: &mut UpdateDeliveryList) { $($delivery_list:tt)* }
199
200 $(#[$validate_outer:meta])*
201 fn validate(&$self_v:ident) -> Result<(), $ValidationError:path> { $($validate:tt)+ }
202 }
203 ) => {
204 $crate::__event_args! {common=>
205
206 $(#[$outer])*
207 $vis struct $Args {
208 $($(#[$arg_outer])* $arg_vis $arg: $arg_ty,)*
209 ..
210 $(#[$delivery_list_outer])*
211 fn delivery_list(&$self, $delivery_list_ident: &mut UpdateDeliveryList) { $($delivery_list)* }
212 }
213 }
214 impl $Args {
215 #[allow(clippy::too_many_arguments)]
221 pub fn new(
222 timestamp: impl Into<$crate::DInstant>,
223 propagation_handle: $crate::event::EventPropagationHandle,
224 $($arg : impl Into<$arg_ty>),*
225 ) -> Self {
226 let args = $Args {
227 timestamp: timestamp.into(),
228 $($arg: $arg.into(),)*
229 propagation_handle,
230 };
231 args.assert_valid();
232 args
233 }
234
235 #[allow(clippy::too_many_arguments)]
239 pub fn try_new(
240 timestamp: impl Into<$crate::DInstant>,
241 propagation_handle: $crate::event::EventPropagationHandle,
242 $($arg : impl Into<$arg_ty>),*
243 ) -> Result<Self, $ValidationError> {
244 let args = $Args {
245 timestamp: timestamp.into(),
246 $($arg: $arg.into(),)*
247 propagation_handle,
248 };
249 args.validate()?;
250 Ok(args)
251 }
252
253 #[allow(clippy::too_many_arguments)]
259 pub fn now($($arg : impl Into<$arg_ty>),*) -> Self {
260 Self::new($crate::INSTANT.now(), $crate::event::EventPropagationHandle::new(), $($arg),*)
261 }
262
263 #[allow(clippy::too_many_arguments)]
267 pub fn try_now($($arg : impl Into<$arg_ty>),*) -> Result<Self, $ValidationError> {
268 Self::try_new($crate::INSTANT.now(), $crate::event::EventPropagationHandle::new(), $($arg),*)
269 }
270
271 $(#[$validate_outer])*
272 pub fn validate(&$self_v) -> Result<(), $ValidationError> {
273 $($validate)+
274 }
275
276 #[track_caller]
278 pub fn assert_valid(&self) {
279 if let Err(e) = self.validate() {
280 panic!("invalid `{}`, {e:?}", stringify!($Args));
281 }
282 }
283 }
284 };
285
286 (
288 $(#[$outer:meta])*
289 $vis:vis struct $Args:ident {
290 $($(#[$arg_outer:meta])* $arg_vis:vis $arg:ident : $arg_ty:ty,)*
291 ..
292 $(#[$delivery_list_outer:meta])*
293 fn delivery_list(&$self:ident, $delivery_list_ident:ident: &mut UpdateDeliveryList) { $($delivery_list:tt)* }
294 }
295 ) => {
296 $crate::__event_args! {common=>
297
298 $(#[$outer])*
299 $vis struct $Args {
300 $($(#[$arg_outer])* $arg_vis $arg: $arg_ty,)*
301 ..
302 $(#[$delivery_list_outer])*
303 fn delivery_list(&$self, $delivery_list_ident: &mut UpdateDeliveryList) { $($delivery_list)* }
304 }
305 }
306
307 impl $Args {
308 #[allow(clippy::too_many_arguments)]
310 pub fn new(
311 timestamp: impl Into<$crate::DInstant>,
312 propagation_handle: $crate::event::EventPropagationHandle,
313 $($arg : impl Into<$arg_ty>),*
314 ) -> Self {
315 $Args {
316 timestamp: timestamp.into(),
317 $($arg: $arg.into(),)*
318 propagation_handle,
319 }
320 }
321
322 #[allow(clippy::too_many_arguments)]
324 pub fn now($($arg : impl Into<$arg_ty>),*) -> Self {
325 Self::new($crate::INSTANT.now(), $crate::event::EventPropagationHandle::new(), $($arg),*)
326 }
327 }
328 };
329
330 (common=>
332
333 $(#[$outer:meta])*
334 $vis:vis struct $Args:ident {
335 $($(#[$arg_outer:meta])* $arg_vis:vis $arg:ident : $arg_ty:ty,)*
336 ..
337 $(#[$delivery_list_outer:meta])*
338 fn delivery_list(&$self:ident, $delivery_list_ident:ident: &mut UpdateDeliveryList) { $($delivery_list:tt)* }
339 }
340 ) => {
341 $(#[$outer])*
342 #[derive(Debug, Clone)]
343 $vis struct $Args {
344 pub timestamp: $crate::DInstant,
346 $($(#[$arg_outer])* $arg_vis $arg : $arg_ty,)*
347
348 propagation_handle: $crate::event::EventPropagationHandle,
349 }
350 impl $crate::event::EventArgs for $Args {
351 }
352 impl $crate::event::AnyEventArgs for $Args {
353 fn clone_any(&self) -> std::boxed::Box<dyn $crate::event::AnyEventArgs> {
354 Box::new(self.clone())
355 }
356
357 fn as_any(&self) -> &dyn std::any::Any {
358 self
359 }
360
361 fn timestamp(&self) -> $crate::DInstant {
362 self.timestamp
363 }
364
365 $(#[$delivery_list_outer])*
366 fn delivery_list(&$self, $delivery_list_ident: &mut $crate::update::UpdateDeliveryList) {
367 #[allow(unused_imports)]
368 use $crate::update::UpdateDeliveryList;
369
370 $($delivery_list)*
371 }
372
373 fn propagation(&self) -> &$crate::event::EventPropagationHandle {
374 &self.propagation_handle
375 }
376 }
377 };
378}
379#[doc(inline)]
380pub use crate::event_args;
381use crate::update::UpdateDeliveryList;