1use std::sync::{Arc, atomic::AtomicBool};
2
3use zng_var::{AnyVarValue, VarValue};
4
5use crate::widget::WidgetId;
6use atomic::Ordering::Relaxed;
7
8pub trait AnyEventArgs: AnyVarValue {
10 fn timestamp(&self) -> crate::DInstant;
12
13 fn propagation(&self) -> &EventPropagationHandle;
18
19 fn is_in_target(&self, widget: WidgetId) -> bool;
21
22 fn clone_boxed(&self) -> Box<dyn AnyEventArgs>;
24}
25
26pub trait EventArgs: AnyEventArgs + VarValue {}
28
29#[macro_export]
79macro_rules! event_args {
80 ($(
81 $(#[$outer:meta])*
82 $vis:vis struct $Args:ident {
83 $($(#[$arg_outer:meta])* $arg_vis:vis $arg:ident : $arg_ty:ty,)*
84 ..
85 $(#[$is_in_target_outer:meta])*
86 fn is_in_target(&$self:ident, $is_in_target_id:ident: WidgetId) -> bool { $($is_in_target:tt)* }
87
88 $(
89 $(#[$validate_outer:meta])*
90 fn validate(&$self_v:ident) -> Result<(), $ValidationError:path> { $($validate:tt)+ }
91 )?
92 }
93 )+) => {$(
94 $crate::__event_args! {
95 $(#[$outer])*
96 $vis struct $Args {
97 $($(#[$arg_outer])* $arg_vis $arg: $arg_ty,)*
98
99 ..
100
101 $(#[$is_in_target_outer])*
102 fn is_in_target(&$self, $is_in_target_id: WidgetId) -> bool { $($is_in_target)* }
103
104 $(
105 $(#[$validate_outer])*
106 fn validate(&$self_v) -> Result<(), $ValidationError> { $($validate)+ }
107 )?
108 }
109 }
110 )+};
111}
112#[doc(hidden)]
113#[macro_export]
114macro_rules! __event_args {
115 (
117 $(#[$outer:meta])*
118 $vis:vis struct $Args:ident {
119 $($(#[$arg_outer:meta])* $arg_vis:vis $arg:ident : $arg_ty:ty,)*
120 ..
121 $(#[$is_in_target_outer:meta])*
122 fn is_in_target(&$self:ident, $is_in_target_id:ident: WidgetId) -> bool { $($is_in_target:tt)* }
123
124 $(#[$validate_outer:meta])*
125 fn validate(&$self_v:ident) -> Result<(), $ValidationError:path> { $($validate:tt)+ }
126 }
127 ) => {
128 $crate::__event_args! {common=>
129
130 $(#[$outer])*
131 $vis struct $Args {
132 $($(#[$arg_outer])* $arg_vis $arg: $arg_ty,)*
133 ..
134 $(#[$is_in_target_outer])*
135 fn is_in_target(&$self, $is_in_target_id: WidgetId) -> bool { $($is_in_target)* }
136 }
137 }
138 impl $Args {
139 #[allow(clippy::too_many_arguments)]
145 pub fn new(
146 timestamp: impl Into<$crate::DInstant>,
147 propagation: $crate::event::EventPropagationHandle,
148 $($arg : impl Into<$arg_ty>),*
149 ) -> Self {
150 let args = $Args {
151 timestamp: timestamp.into(),
152 $($arg: $arg.into(),)*
153 propagation,
154 };
155 args.assert_valid();
156 args
157 }
158
159 #[allow(clippy::too_many_arguments)]
163 pub fn try_new(
164 timestamp: impl Into<$crate::DInstant>,
165 propagation: $crate::event::EventPropagationHandle,
166 $($arg : impl Into<$arg_ty>),*
167 ) -> Result<Self, $ValidationError> {
168 let args = $Args {
169 timestamp: timestamp.into(),
170 $($arg: $arg.into(),)*
171 propagation,
172 };
173 args.validate()?;
174 Ok(args)
175 }
176
177 #[allow(clippy::too_many_arguments)]
183 pub fn now($($arg : impl Into<$arg_ty>),*) -> Self {
184 Self::new($crate::INSTANT.now(), $crate::event::EventPropagationHandle::new(), $($arg),*)
185 }
186
187 #[allow(clippy::too_many_arguments)]
191 pub fn try_now($($arg : impl Into<$arg_ty>),*) -> Result<Self, $ValidationError> {
192 Self::try_new($crate::INSTANT.now(), $crate::event::EventPropagationHandle::new(), $($arg),*)
193 }
194
195 $(#[$validate_outer])*
196 pub fn validate(&$self_v) -> Result<(), $ValidationError> {
197 $($validate)+
198 }
199
200 #[track_caller]
202 pub fn assert_valid(&self) {
203 if let Err(e) = self.validate() {
204 panic!("invalid `{}`, {e:?}", stringify!($Args));
205 }
206 }
207 }
208 };
209
210 (
212 $(#[$outer:meta])*
213 $vis:vis struct $Args:ident {
214 $($(#[$arg_outer:meta])* $arg_vis:vis $arg:ident : $arg_ty:ty,)*
215 ..
216 $(#[$is_in_target_outer:meta])*
217 fn is_in_target(&$self:ident, $is_in_target_id:ident: WidgetId) -> bool { $($is_in_target:tt)* }
218 }
219 ) => {
220 $crate::__event_args! {common=>
221
222 $(#[$outer])*
223 $vis struct $Args {
224 $($(#[$arg_outer])* $arg_vis $arg: $arg_ty,)*
225 ..
226 $(#[$is_in_target_outer])*
227 fn is_in_target(&$self, $is_in_target_id: WidgetId) -> bool { $($is_in_target)* }
228 }
229 }
230
231 impl $Args {
232 #[allow(clippy::too_many_arguments)]
234 pub fn new(
235 timestamp: impl Into<$crate::DInstant>,
236 propagation: $crate::event::EventPropagationHandle,
237 $($arg : impl Into<$arg_ty>),*
238 ) -> Self {
239 $Args {
240 timestamp: timestamp.into(),
241 $($arg: $arg.into(),)*
242 propagation,
243 }
244 }
245
246 #[allow(clippy::too_many_arguments)]
248 pub fn now($($arg : impl Into<$arg_ty>),*) -> Self {
249 Self::new($crate::INSTANT.now(), $crate::event::EventPropagationHandle::new(), $($arg),*)
250 }
251 }
252 };
253
254 (common=>
256
257 $(#[$outer:meta])*
258 $vis:vis struct $Args:ident {
259 $($(#[$arg_outer:meta])* $arg_vis:vis $arg:ident : $arg_ty:ty,)*
260 ..
261 $(#[$is_in_target_outer:meta])*
262 fn is_in_target(&$self:ident, $is_in_target_id:ident: WidgetId) -> bool { $($is_in_target:tt)* }
263 }
264 ) => {
265 $(#[$outer])*
266 #[derive(Debug, Clone, PartialEq)]
267 $vis struct $Args {
268 pub timestamp: $crate::DInstant,
270 $($(#[$arg_outer])* $arg_vis $arg : $arg_ty,)*
271
272 pub propagation: $crate::event::EventPropagationHandle,
277 }
278 impl $crate::event::AnyEventArgs for $Args {
279 fn timestamp(&self) -> $crate::DInstant {
280 self.timestamp
281 }
282
283 $(#[$is_in_target_outer])*
284 fn is_in_target(&$self, $is_in_target_id: $crate::widget::WidgetId) -> bool {
285 let _ = $is_in_target_id;
286 $($is_in_target)*
287 }
288
289 fn propagation(&self) -> &$crate::event::EventPropagationHandle {
290 &self.propagation
291 }
292
293 fn clone_boxed(&self) -> std::boxed::Box<dyn $crate::event::AnyEventArgs> {
294 Box::new(self.clone())
295 }
296 }
297 impl $crate::event::EventArgs for $Args { }
298 };
299}
300#[doc(inline)]
301pub use crate::event_args;
302
303#[derive(Clone)]
310pub struct EventPropagationHandle(Arc<AtomicBool>);
311impl std::fmt::Debug for EventPropagationHandle {
312 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
313 f.debug_struct("EventPropagationHandle")
314 .field(".handle", &Arc::as_ptr(&self.0))
315 .field("is_stopped()", &self.is_stopped())
316 .finish()
317 }
318}
319impl EventPropagationHandle {
320 pub fn new() -> Self {
322 EventPropagationHandle(Arc::new(AtomicBool::new(false)))
323 }
324
325 pub fn stop(&self) {
327 self.0.store(true, Relaxed);
330 }
331
332 pub fn is_stopped(&self) -> bool {
338 self.0.load(Relaxed)
339 }
340}
341impl Default for EventPropagationHandle {
342 fn default() -> Self {
343 EventPropagationHandle::new()
344 }
345}
346impl PartialEq for EventPropagationHandle {
347 fn eq(&self, other: &Self) -> bool {
348 Arc::ptr_eq(&self.0, &other.0)
349 }
350}
351impl Eq for EventPropagationHandle {}
352impl std::hash::Hash for EventPropagationHandle {
353 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
354 let ptr = Arc::as_ptr(&self.0) as usize;
355 std::hash::Hash::hash(&ptr, state);
356 }
357}