zng_app/
handler.rs

1//! Handler types and macros.
2
3use std::any::Any;
4use std::marker::PhantomData;
5use std::time::Duration;
6use std::{mem, thread};
7
8#[doc(hidden)]
9pub use zng_clone_move::*;
10
11use zng_handle::{Handle, WeakHandle};
12use zng_task::{self as task, UiTask};
13
14use crate::INSTANT;
15
16/// Represents a handler in a widget context.
17///
18/// There are different flavors of handlers, you can use macros to declare then.
19/// See [`hn!`], [`hn_once!`] or [`async_hn!`], [`async_hn_once!`] to start.
20#[diagnostic::on_unimplemented(
21    note = "use `hn!(|args: &{A}| {{ }})` to declare a widget handler from a `FnMut` closure",
22    note = "use `hn_once!`, `async_hn!` or `async_hn_once!` for other closure types"
23)]
24pub trait WidgetHandler<A: Clone + 'static>: Any + Send {
25    /// Called every time the handler's event happens in the widget context.
26    ///
27    /// Returns `true` when the event handler is async and it has not finished handling the event.
28    ///
29    /// [`update`]: WidgetHandler::update
30    /// [`info`]: crate::widget::node::UiNode::info
31    fn event(&mut self, args: &A) -> bool;
32
33    /// Called every widget update.
34    ///
35    /// Returns `false` when all pending async tasks are completed. Note that event properties
36    /// will call this method every update even if it is returning `false`.
37    ///
38    /// [`update`]: WidgetHandler::update
39    fn update(&mut self) -> bool {
40        false
41    }
42
43    /// Box the handler.
44    ///
45    /// The type `Box<dyn WidgetHandler<A>>` implements `WidgetHandler<A>` and just returns itself
46    /// in this method, avoiding double boxing.
47    fn boxed(self) -> Box<dyn WidgetHandler<A>>
48    where
49        Self: Sized,
50    {
51        Box::new(self)
52    }
53    /// Boxes the handler if the `feature = "dyn_closure"` is active, otherwise retains the same handler type.    
54    #[cfg(feature = "dyn_closure")]
55    fn cfg_boxed(self) -> Box<dyn WidgetHandler<A>>
56    where
57        Self: Sized,
58    {
59        self.boxed()
60    }
61    /// Boxes the handler if the `feature = "dyn_closure"` is active, otherwise retains the same handler type.
62    #[cfg(not(feature = "dyn_closure"))]
63    fn cfg_boxed(self) -> Self
64    where
65        Self: Sized,
66    {
67        self
68    }
69}
70impl<A: Clone + 'static> WidgetHandler<A> for Box<dyn WidgetHandler<A>> {
71    fn event(&mut self, args: &A) -> bool {
72        self.as_mut().event(args)
73    }
74
75    fn update(&mut self) -> bool {
76        self.as_mut().update()
77    }
78
79    fn boxed(self) -> Box<dyn WidgetHandler<A>>
80    where
81        Self: Sized,
82    {
83        self
84    }
85}
86
87#[doc(hidden)]
88pub struct FnMutWidgetHandler<H> {
89    handler: H,
90}
91impl<A, H> WidgetHandler<A> for FnMutWidgetHandler<H>
92where
93    A: Clone + 'static,
94    H: FnMut(&A) + Send + 'static,
95{
96    fn event(&mut self, args: &A) -> bool {
97        (self.handler)(args);
98        false
99    }
100}
101
102#[doc(hidden)]
103#[cfg(not(feature = "dyn_closure"))]
104pub fn hn<A, H>(handler: H) -> FnMutWidgetHandler<H>
105where
106    A: Clone + 'static,
107    H: FnMut(&A) + Send + 'static,
108{
109    FnMutWidgetHandler { handler }
110}
111#[doc(hidden)]
112#[cfg(feature = "dyn_closure")]
113pub fn hn<A, H>(handler: H) -> FnMutWidgetHandler<Box<dyn FnMut(&A) + Send>>
114where
115    A: Clone + 'static,
116    H: FnMut(&A) + Send + 'static,
117{
118    FnMutWidgetHandler {
119        handler: Box::new(handler),
120    }
121}
122
123///<span data-del-macro-root></span> Declare a mutable *clone-move* event handler.
124///
125/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
126/// the input is the same syntax.
127///
128/// # Examples
129///
130/// The example declares an event handler for the `on_click` property.
131///
132/// ```
133/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
134/// # use zng_app::handler::hn;
135/// # let _scope = zng_app::APP.minimal();
136/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
137/// # let
138/// on_click = hn!(|_| {
139///     println!("Clicked!");
140/// });
141/// # on_click }
142/// ```
143///
144/// The closure input is `&ClickArgs` for this property. Note that
145/// if you want to use the event args you must annotate the input type, the context type is inferred.
146///
147/// ```
148/// # #[derive(Clone)] pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize }
149/// # use zng_app::handler::hn;
150/// # let _scope = zng_app::APP.minimal();
151/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
152/// # let
153/// on_click = hn!(|args: &ClickArgs| {
154///     println!("Clicked {}!", args.click_count);
155/// });
156/// # on_click }
157/// ```
158///
159/// Internally the [`clmv!`] macro is used so you can *clone-move* variables into the handler.
160///
161/// ```
162/// # #[derive(Clone)] pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize }
163/// # use zng_txt::formatx;
164/// # use zng_var::{var, Var};
165/// # use zng_app::handler::hn;
166/// # let _scope = zng_app::APP.minimal();
167/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
168/// let foo = var(0);
169///
170/// // ..
171///
172/// # let
173/// on_click = hn!(foo, |args: &ClickArgs| {
174///     foo.set(args.click_count);
175/// });
176///
177/// // can still use after:
178/// let bar = foo.map(|c| formatx!("click_count: {c}"));
179///
180/// # on_click }
181/// ```
182///
183/// In the example above only a clone of `foo` is moved into the handler. Note that handlers always capture by move, if `foo` was not
184/// listed in the *clone-move* section it would not be available after the handler is created. See [`clmv!`] for details.
185///
186/// [`clmv!`]: zng_clone_move::clmv
187#[macro_export]
188macro_rules! hn {
189    ($($tt:tt)+) => {
190        $crate::handler::hn($crate::handler::clmv!{ $($tt)+ })
191    }
192}
193#[doc(inline)]
194pub use crate::hn;
195use crate::{AppControlFlow, HeadlessApp};
196
197#[doc(hidden)]
198pub struct FnOnceWidgetHandler<H> {
199    handler: Option<H>,
200}
201impl<A, H> WidgetHandler<A> for FnOnceWidgetHandler<H>
202where
203    A: Clone + 'static,
204    H: FnOnce(&A) + Send + 'static,
205{
206    fn event(&mut self, args: &A) -> bool {
207        if let Some(handler) = self.handler.take() {
208            handler(args);
209        }
210        false
211    }
212}
213#[doc(hidden)]
214#[cfg(not(feature = "dyn_closure"))]
215pub fn hn_once<A, H>(handler: H) -> FnOnceWidgetHandler<H>
216where
217    A: Clone + 'static,
218    H: FnOnce(&A) + Send + 'static,
219{
220    FnOnceWidgetHandler { handler: Some(handler) }
221}
222#[doc(hidden)]
223#[cfg(feature = "dyn_closure")]
224pub fn hn_once<A, H>(handler: H) -> FnOnceWidgetHandler<Box<dyn FnOnce(&A) + Send>>
225where
226    A: Clone + 'static,
227    H: FnOnce(&A) + Send + 'static,
228{
229    FnOnceWidgetHandler {
230        handler: Some(Box::new(handler)),
231    }
232}
233
234///<span data-del-macro-root></span> Declare a *clone-move* event handler that is only called once.
235///
236/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
237/// the input is the same syntax.
238///
239/// # Examples
240///
241/// The example captures `data` by move and then destroys it in the first call, this cannot be done using [`hn!`] because
242/// the `data` needs to be available for all event calls. In this case the closure is only called once, subsequent events
243/// are ignored by the handler.
244///
245/// ```
246/// # use zng_app::handler::hn_once;
247/// # let _scope = zng_app::APP.minimal();
248/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<()> {
249/// let data = vec![1, 2, 3];
250/// # let
251/// on_click = hn_once!(|_| {
252///     for i in data {
253///         print!("{i}, ");
254///     }
255/// });
256/// # on_click }
257/// ```
258///
259/// Other then declaring a `FnOnce` this macro behaves like [`hn!`], so the same considerations apply. You can *clone-move* variables,
260/// the type of the input is the event arguments and must be annotated.
261///
262/// ```
263/// # use zng_app::handler::hn_once;
264/// # let _scope = zng_app::APP.minimal();
265/// # #[derive(Clone)]
266/// # pub struct ClickArgs { click_count: usize }
267/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
268/// let data = vec![1, 2, 3];
269/// # let
270/// on_click = hn_once!(data, |args: &ClickArgs| {
271///     drop(data);
272/// });
273///
274/// println!("{data:?}");
275/// # on_click }
276/// ```
277///
278/// [`clmv!`]: zng_clone_move::clmv
279#[macro_export]
280macro_rules! hn_once {
281    ($($tt:tt)+) => {
282        $crate::handler::hn_once($crate::handler::clmv! { $($tt)+ })
283    }
284}
285#[doc(inline)]
286pub use crate::hn_once;
287
288#[doc(hidden)]
289pub struct AsyncFnMutWidgetHandler<H> {
290    handler: H,
291    tasks: Vec<UiTask<()>>,
292}
293impl<A, F, H> WidgetHandler<A> for AsyncFnMutWidgetHandler<H>
294where
295    A: Clone + 'static,
296    F: Future<Output = ()> + Send + 'static,
297    H: FnMut(A) -> F + Send + 'static,
298{
299    fn event(&mut self, args: &A) -> bool {
300        let handler = &mut self.handler;
301        let mut task = UiTask::new(Some(WIDGET.id()), handler(args.clone()));
302        let need_update = task.update().is_none();
303        if need_update {
304            self.tasks.push(task);
305        }
306        need_update
307    }
308
309    fn update(&mut self) -> bool {
310        self.tasks.retain_mut(|t| t.update().is_none());
311        !self.tasks.is_empty()
312    }
313}
314#[doc(hidden)]
315#[cfg(not(feature = "dyn_closure"))]
316pub fn async_hn<A, F, H>(handler: H) -> AsyncFnMutWidgetHandler<H>
317where
318    A: Clone + 'static,
319    F: Future<Output = ()> + Send + 'static,
320    H: FnMut(A) -> F + Send + 'static,
321{
322    AsyncFnMutWidgetHandler { handler, tasks: vec![] }
323}
324
325#[cfg(feature = "dyn_closure")]
326type BoxedAsyncHn<A> = Box<dyn FnMut(A) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send>> + Send>;
327
328#[doc(hidden)]
329#[cfg(feature = "dyn_closure")]
330pub fn async_hn<A, F, H>(mut handler: H) -> AsyncFnMutWidgetHandler<BoxedAsyncHn<A>>
331where
332    A: Clone + 'static,
333    F: Future<Output = ()> + Send + 'static,
334    H: FnMut(A) -> F + Send + 'static,
335{
336    AsyncFnMutWidgetHandler {
337        handler: Box::new(move |args| Box::pin(handler(args))),
338        tasks: vec![],
339    }
340}
341
342///<span data-del-macro-root></span> Declare an async *clone-move* event handler.
343///
344/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn!`] so
345/// the input is the same syntax.
346///
347/// # Examples
348///
349/// The example declares an async event handler for the `on_click` property.
350///
351/// ```
352/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
353/// # use zng_app::handler::async_hn;
354/// # use zng_task as task;
355/// # let _scope = zng_app::APP.minimal();
356/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
357/// # let
358/// on_click = async_hn!(|_| {
359///     println!("Clicked!");
360///
361///     task::run(async {
362///         println!("In other thread!");
363///     }).await;
364///
365///     println!("Back in UI thread, in a widget update.");
366/// });
367/// # on_click }
368/// ```
369///
370/// The closure input is `ClickArgs` for this property. Note that
371/// if you want to use the event args you must annotate the input type.
372///
373/// ```
374/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
375/// # use zng_app::handler::async_hn;
376/// # use zng_app::widget::WIDGET;
377/// # let _scope = zng_app::APP.minimal();
378/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
379/// # let
380/// on_click = async_hn!(|args: ClickArgs| {
381///     println!("Clicked {} {} times!", WIDGET.id(), args.click_count);
382///     
383/// });
384/// # on_click }
385/// ```
386///
387/// Internally the [`async_clmv_fn!`] macro is used so you can *clone-move* variables into the handler.
388///
389/// ```
390/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
391/// # use zng_app::handler::async_hn;
392/// # use zng_var::{var, Var};
393/// # use zng_task as task;
394/// # use zng_txt::formatx;
395/// # let _scope = zng_app::APP.minimal();
396/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
397/// let enabled = var(true);
398///
399/// // ..
400///
401/// # let
402/// on_click = async_hn!(enabled, |args: ClickArgs| {
403///     enabled.set(false);
404///
405///     task::run(async move {
406///         println!("do something {}", args.click_count);
407///     }).await;
408///
409///     enabled.set(true);
410/// });
411///
412/// // can still use after:
413/// # let
414/// text = enabled.map(|&e| if e { "Click Me!" } else { "Busy.." });
415/// enabled;
416///
417/// # on_click }
418/// ```
419///
420/// In the example above only a clone of `enabled` is moved into the handler. Note that handlers always capture by move, if `enabled` was not
421/// listed in the *clone-move* section it would not be available after the handler is created. See [`async_clmv_fn!`] for details.
422///
423/// The example also demonstrates a common pattern with async handlers, most events are only raised when the widget is enabled, so you can
424/// disable the widget while the async task is running. This way you don't block the UI running a task but the user cannot spawn a second
425/// task while the first is still running.
426///
427/// ## Futures and Clone-Move
428///
429/// You want to always *clone-move* captures for async handlers, because they then automatically get cloned again for each event. This
430/// needs to happen because you can have more then one *handler task* running at the same type, and both want access to the captured variables.
431///
432/// This second cloning can be avoided by using the [`async_hn_once!`] macro instead, but only if you expect a single event.
433///
434/// Note that this means you are declaring a normal closure that returns a `'static` future, not an async closure, see [`async_clmv_fn!`].
435///
436/// [`async_clmv_fn!`]: zng_clone_move::async_clmv_fn
437#[macro_export]
438macro_rules! async_hn {
439    ($($tt:tt)+) => {
440        $crate::handler::async_hn($crate::handler::async_clmv_fn! { $($tt)+ })
441    }
442}
443#[doc(inline)]
444pub use crate::async_hn;
445
446enum AsyncFnOnceWhState<H> {
447    NotCalled(H),
448    Pending(UiTask<()>),
449    Done,
450}
451#[doc(hidden)]
452pub struct AsyncFnOnceWidgetHandler<H> {
453    state: AsyncFnOnceWhState<H>,
454}
455impl<A, F, H> WidgetHandler<A> for AsyncFnOnceWidgetHandler<H>
456where
457    A: Clone + 'static,
458    F: Future<Output = ()> + Send + 'static,
459    H: FnOnce(A) -> F + Send + 'static,
460{
461    fn event(&mut self, args: &A) -> bool {
462        match mem::replace(&mut self.state, AsyncFnOnceWhState::Done) {
463            AsyncFnOnceWhState::NotCalled(handler) => {
464                let mut task = UiTask::new(Some(WIDGET.id()), handler(args.clone()));
465                let is_pending = task.update().is_none();
466                if is_pending {
467                    self.state = AsyncFnOnceWhState::Pending(task);
468                }
469                is_pending
470            }
471            AsyncFnOnceWhState::Pending(t) => {
472                self.state = AsyncFnOnceWhState::Pending(t);
473                false
474            }
475            AsyncFnOnceWhState::Done => false,
476        }
477    }
478
479    fn update(&mut self) -> bool {
480        let mut is_pending = false;
481        if let AsyncFnOnceWhState::Pending(t) = &mut self.state {
482            is_pending = t.update().is_none();
483            if !is_pending {
484                self.state = AsyncFnOnceWhState::Done;
485            }
486        }
487        is_pending
488    }
489}
490#[doc(hidden)]
491#[cfg(not(feature = "dyn_closure"))]
492pub fn async_hn_once<A, F, H>(handler: H) -> AsyncFnOnceWidgetHandler<H>
493where
494    A: Clone + 'static,
495    F: Future<Output = ()> + Send + 'static,
496    H: FnOnce(A) -> F + Send + 'static,
497{
498    AsyncFnOnceWidgetHandler {
499        state: AsyncFnOnceWhState::NotCalled(handler),
500    }
501}
502
503#[cfg(feature = "dyn_closure")]
504type BoxedAsyncHnOnce<A> = Box<dyn FnOnce(A) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send>> + Send>;
505
506#[doc(hidden)]
507#[cfg(feature = "dyn_closure")]
508pub fn async_hn_once<A, F, H>(handler: H) -> AsyncFnOnceWidgetHandler<BoxedAsyncHnOnce<A>>
509where
510    A: Clone + 'static,
511    F: Future<Output = ()> + Send + 'static,
512    H: FnOnce(A) -> F + Send + 'static,
513{
514    AsyncFnOnceWidgetHandler {
515        state: AsyncFnOnceWhState::NotCalled(Box::new(move |args| Box::pin(handler(args)))),
516    }
517}
518
519///<span data-del-macro-root></span> Declare an async *clone-move* event handler that is only called once.
520///
521/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn_once!`] so
522/// the input is the same syntax.
523///
524/// # Examples
525///
526/// The example captures `data` by move and then moves it again to another thread. This is not something you can do using [`async_hn!`]
527/// because that handler expects to be called many times. We expect `on_open` to only be called once, so we can don't need to capture by
528/// *clone-move* here just to use `data`.
529///
530/// ```
531/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
532/// # use zng_app::handler::async_hn_once;
533/// # use zng_task as task;
534/// # let _scope = zng_app::APP.minimal();
535/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
536/// let data = vec![1, 2, 3];
537/// # let
538/// on_open = async_hn_once!(|_| {
539///     task::run(async move {
540///          for i in data {
541///              print!("{i}, ");
542///          }    
543///     }).await;
544///
545///     println!("Done!");
546/// });
547/// # on_open }
548/// ```
549///
550/// You can still *clone-move* to have access to the variable after creating the handler, in this case the `data` will be cloned into the handler
551/// but will just be moved to the other thread, avoiding a needless clone.
552///
553/// ```
554/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
555/// # use zng_app::handler::async_hn_once;
556/// # use zng_task as task;
557/// # let _scope = zng_app::APP.minimal();
558/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
559/// let data = vec![1, 2, 3];
560/// # let
561/// on_open = async_hn_once!(data, |_| {
562///     task::run(async move {
563///          for i in data {
564///              print!("{i}, ");
565///          }    
566///     }).await;
567///
568///     println!("Done!");
569/// });
570/// println!("{data:?}");
571/// # on_open }
572/// ```
573///
574/// [`async_clmv_fn_once!`]: zng_clone_move::async_clmv_fn_once
575#[macro_export]
576macro_rules! async_hn_once {
577    ($($tt:tt)+) => {
578        $crate::handler::async_hn_once($crate::handler::async_clmv_fn_once! { $($tt)+ })
579    }
580}
581#[doc(inline)]
582pub use crate::async_hn_once;
583
584/// Represents a weak handle to an [`AppHandler`] subscription.
585pub trait AppWeakHandle: Send {
586    /// Dynamic clone.
587    fn clone_boxed(&self) -> Box<dyn AppWeakHandle>;
588
589    /// Unsubscribes the [`AppHandler`].
590    ///
591    /// This stops the handler from being called again and causes it to be dropped in a future app update.
592    fn unsubscribe(&self);
593}
594impl<D: Send + Sync + 'static> AppWeakHandle for WeakHandle<D> {
595    fn clone_boxed(&self) -> Box<dyn AppWeakHandle> {
596        Box::new(self.clone())
597    }
598
599    fn unsubscribe(&self) {
600        if let Some(handle) = self.upgrade() {
601            handle.force_drop();
602        }
603    }
604}
605
606/// Arguments for a call of [`AppHandler::event`].
607pub struct AppHandlerArgs<'a> {
608    /// Handle to the [`AppHandler`] subscription.
609    pub handle: &'a dyn AppWeakHandle,
610    /// If the handler is invoked in a *preview* context.
611    pub is_preview: bool,
612}
613
614/// Represents an event handler in the app context.
615///
616/// There are different flavors of handlers, you can use macros to declare then.
617/// See [`app_hn!`], [`app_hn_once!`] or [`async_app_hn!`], [`async_app_hn_once!`] to start.
618#[diagnostic::on_unimplemented(
619    note = "use `app_hn!(|args: &{A}, _| {{ }})` to declare an app handler closure",
620    note = "use `app_hn_once!`, `async_app_hn!` or `async_app_hn_once!` for other closure types"
621)]
622pub trait AppHandler<A: Clone + 'static>: Any + Send {
623    /// Called every time the event happens.
624    ///
625    /// The `handler_args` can be used to unsubscribe the handler. Async handlers are expected to schedule
626    /// their tasks to run somewhere in the app, usually in the [`UPDATES.on_update`]. The `handle` is
627    /// **not** expected to cancel running async tasks, only to drop `self` before the next event happens.
628    ///
629    /// [`UPDATES.on_update`]: crate::update::UPDATES::on_update
630    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs);
631
632    /// Boxes the handler.
633    ///
634    /// The type `Box<dyn AppHandler<A>>` implements `AppHandler<A>` and just returns itself
635    /// in this method, avoiding double boxing.
636    fn boxed(self) -> Box<dyn AppHandler<A>>
637    where
638        Self: Sized,
639    {
640        Box::new(self)
641    }
642
643    /// Boxes the handler if the `feature = "dyn_closure"` is enabled, otherwise maintain the same type.
644    #[cfg(feature = "dyn_closure")]
645    fn cfg_boxed(self) -> Box<dyn AppHandler<A>>
646    where
647        Self: Sized,
648    {
649        self.boxed()
650    }
651
652    /// Boxes the handler if the `feature = "dyn_closure"` is enabled, otherwise maintain the same type.    
653    #[cfg(not(feature = "dyn_closure"))]
654    fn cfg_boxed(self) -> Self
655    where
656        Self: Sized,
657    {
658        self
659    }
660}
661impl<A: Clone + 'static> AppHandler<A> for Box<dyn AppHandler<A>> {
662    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
663        self.as_mut().event(args, handler_args)
664    }
665
666    fn boxed(self) -> Box<dyn AppHandler<A>> {
667        self
668    }
669}
670
671#[doc(hidden)]
672pub struct FnMutAppHandler<H> {
673    handler: H,
674}
675impl<A, H> AppHandler<A> for FnMutAppHandler<H>
676where
677    A: Clone + 'static,
678    H: FnMut(&A, &dyn AppWeakHandle) + Send + 'static,
679{
680    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
681        (self.handler)(args, handler_args.handle);
682    }
683}
684#[doc(hidden)]
685#[cfg(not(feature = "dyn_closure"))]
686pub fn app_hn<A, H>(handler: H) -> FnMutAppHandler<H>
687where
688    A: Clone + 'static,
689    H: FnMut(&A, &dyn AppWeakHandle) + Send + 'static,
690{
691    FnMutAppHandler { handler }
692}
693
694#[cfg(feature = "dyn_closure")]
695type BoxedAppHn<A> = Box<dyn FnMut(&A, &dyn AppWeakHandle) + Send>;
696
697#[doc(hidden)]
698#[cfg(feature = "dyn_closure")]
699pub fn app_hn<A, H>(handler: H) -> FnMutAppHandler<BoxedAppHn<A>>
700where
701    A: Clone + 'static,
702    H: FnMut(&A, &dyn AppWeakHandle) + Send + 'static,
703{
704    FnMutAppHandler {
705        handler: Box::new(handler),
706    }
707}
708
709///<span data-del-macro-root></span> Declare a mutable *clone-move* app event handler.
710///
711/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
712/// the input is the same syntax.
713///
714/// # Examples
715///
716/// The example declares an event handler for the `CLICK_EVENT`.
717///
718/// ```
719/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
720/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
721/// # use zng_app::handler::app_hn;
722/// # let _scope = zng_app::APP.minimal();
723/// # fn assert_type() {
724/// CLICK_EVENT.on_event(app_hn!(|_, _| {
725///     println!("Clicked Somewhere!");
726/// })).perm();
727/// # }
728/// ```
729///
730/// The closure input is `&A, &dyn AppWeakHandle` with `&A` equaling `&ClickArgs` for this event. Note that
731/// if you want to use the event args you must annotate the input type, the context and handle type is inferred.
732///
733/// The handle can be used to unsubscribe the event handler, if [`unsubscribe`](AppWeakHandle::unsubscribe) is called the handler
734/// will be dropped some time before the next event update.
735///
736/// ```
737/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
738/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
739/// # use zng_app::handler::app_hn;
740/// # let _scope = zng_app::APP.minimal();
741/// # fn assert_type() {
742/// CLICK_EVENT.on_event(app_hn!(|args: &ClickArgs, handle| {
743///     println!("Clicked {}!", args.target);
744///     handle.unsubscribe();
745/// })).perm();
746/// # }
747/// ```
748///
749/// Internally the [`clmv!`] macro is used so you can *clone-move* variables into the handler.
750///
751/// ```
752/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
753/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
754/// # use zng_txt::{formatx, ToTxt};
755/// # use zng_var::{var, Var};
756/// # use zng_app::handler::app_hn;
757/// # let _scope = zng_app::APP.minimal();
758/// # fn assert_type() {
759/// let foo = var("".to_txt());
760///
761/// CLICK_EVENT.on_event(app_hn!(foo, |args: &ClickArgs, _| {
762///     foo.set(args.target.to_txt());
763/// })).perm();
764///
765/// // can still use after:
766/// let bar = foo.map(|c| formatx!("last click: {c}"));
767///
768/// # }
769/// ```
770///
771/// In the example above only a clone of `foo` is moved into the handler. Note that handlers always capture by move, if `foo` was not
772/// listed in the *clone-move* section it would not be available after the handler is created. See [`clmv!`] for details.
773///
774/// [`clmv!`]: zng_clone_move::clmv
775#[macro_export]
776macro_rules! app_hn {
777    ($($tt:tt)+) => {
778        $crate::handler::app_hn($crate::handler::clmv!{ $($tt)+ })
779    }
780}
781#[doc(inline)]
782pub use crate::app_hn;
783
784#[doc(hidden)]
785pub struct FnOnceAppHandler<H> {
786    handler: Option<H>,
787}
788impl<A, H> AppHandler<A> for FnOnceAppHandler<H>
789where
790    A: Clone + 'static,
791    H: FnOnce(&A) + Send + 'static,
792{
793    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
794        if let Some(handler) = self.handler.take() {
795            handler(args);
796            handler_args.handle.unsubscribe();
797        } else {
798            tracing::error!("`app_hn_once!` called after requesting unsubscribe");
799        }
800    }
801}
802#[doc(hidden)]
803#[cfg(not(feature = "dyn_closure"))]
804pub fn app_hn_once<A, H>(handler: H) -> FnOnceAppHandler<H>
805where
806    A: Clone + 'static,
807    H: FnOnce(&A) + Send + 'static,
808{
809    FnOnceAppHandler { handler: Some(handler) }
810}
811#[doc(hidden)]
812#[cfg(feature = "dyn_closure")]
813pub fn app_hn_once<A, H>(handler: H) -> FnOnceAppHandler<Box<dyn FnOnce(&A) + Send>>
814where
815    A: Clone + 'static,
816    H: FnOnce(&A) + Send + 'static,
817{
818    FnOnceAppHandler {
819        handler: Some(Box::new(handler)),
820    }
821}
822
823///<span data-del-macro-root></span> Declare a *clone-move* app event handler that is only called once.
824///
825/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
826/// the input is the same syntax.
827///
828/// # Examples
829///
830/// The example captures `data` by move and then destroys it in the first call, this cannot be done using [`app_hn!`] because
831/// the `data` needs to be available for all event calls. In this case the closure is only called once, subsequent events
832/// are ignored by the handler and it automatically requests unsubscribe.
833///
834/// ```
835/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
836/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
837/// # use zng_app::handler::app_hn_once;
838/// # let _scope = zng_app::APP.minimal();
839/// # fn assert_type() {
840/// let data = vec![1, 2, 3];
841///
842/// CLICK_EVENT.on_event(app_hn_once!(|_| {
843///     for i in data {
844///         print!("{i}, ");
845///     }
846/// })).perm();
847/// # }
848/// ```
849///
850/// Other then declaring a `FnOnce` this macro behaves like [`app_hn!`], so the same considerations apply. You can *clone-move* variables,
851/// the type of the input is the event arguments and must be annotated.
852///
853/// ```
854/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
855/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
856/// # use zng_app::handler::app_hn_once;
857/// # let _scope = zng_app::APP.minimal();
858/// # fn assert_type() {
859/// let data = vec![1, 2, 3];
860///
861/// CLICK_EVENT.on_event(app_hn_once!(data, |args: &ClickArgs| {
862///     drop(data);
863/// })).perm();
864///
865/// println!("{data:?}");
866/// # }
867/// ```
868///
869/// [`clmv!`]: zng_clone_move::clmv
870#[macro_export]
871macro_rules! app_hn_once {
872    ($($tt:tt)+) => {
873        $crate::handler::app_hn_once($crate::handler::clmv! { $($tt)+ })
874    }
875}
876#[doc(inline)]
877pub use crate::app_hn_once;
878
879#[doc(hidden)]
880pub struct AsyncFnMutAppHandler<H> {
881    handler: H,
882}
883impl<A, F, H> AppHandler<A> for AsyncFnMutAppHandler<H>
884where
885    A: Clone + 'static,
886    F: Future<Output = ()> + Send + 'static,
887    H: FnMut(A, Box<dyn AppWeakHandle>) -> F + Send + 'static,
888{
889    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
890        let handler = &mut self.handler;
891        let mut task = UiTask::new(None, handler(args.clone(), handler_args.handle.clone_boxed()));
892        if task.update().is_none() {
893            if handler_args.is_preview {
894                UPDATES
895                    .on_pre_update(app_hn!(|_, handle| {
896                        if task.update().is_some() {
897                            handle.unsubscribe();
898                        }
899                    }))
900                    .perm();
901            } else {
902                UPDATES
903                    .on_update(app_hn!(|_, handle| {
904                        if task.update().is_some() {
905                            handle.unsubscribe();
906                        }
907                    }))
908                    .perm();
909            }
910        }
911    }
912}
913#[doc(hidden)]
914#[cfg(not(feature = "dyn_closure"))]
915pub fn async_app_hn<A, F, H>(handler: H) -> AsyncFnMutAppHandler<H>
916where
917    A: Clone + 'static,
918    F: Future<Output = ()> + Send + 'static,
919    H: FnMut(A, Box<dyn AppWeakHandle>) -> F + Send + 'static,
920{
921    AsyncFnMutAppHandler { handler }
922}
923
924#[cfg(feature = "dyn_closure")]
925type BoxedAsyncAppHn<A> = Box<dyn FnMut(A, Box<dyn AppWeakHandle>) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send>> + Send>;
926
927#[doc(hidden)]
928#[cfg(feature = "dyn_closure")]
929pub fn async_app_hn<A, F, H>(mut handler: H) -> AsyncFnMutAppHandler<BoxedAsyncAppHn<A>>
930where
931    A: Clone + 'static,
932    F: Future<Output = ()> + Send + 'static,
933    H: FnMut(A, Box<dyn AppWeakHandle>) -> F + Send + 'static,
934{
935    AsyncFnMutAppHandler {
936        handler: Box::new(move |args, handle| Box::pin(handler(args, handle))),
937    }
938}
939
940///<span data-del-macro-root></span> Declare an async *clone-move* app event handler.
941///
942/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn!`] so
943/// the input is the same syntax.
944///
945/// The handler generates a future for each event, the future is polled immediately if it does not finish it is scheduled
946/// to update in [`on_pre_update`](crate::update::UPDATES::on_pre_update) or [`on_update`](crate::update::UPDATES::on_update) depending
947/// on if the handler was assigned to a *preview* event or not.
948///
949/// Note that this means [`propagation`](crate::event::AnyEventArgs::propagation) can only be meaningfully stopped before the
950/// first `.await`, after, the event has already propagated.
951///
952/// # Examples
953///
954/// The example declares an async event handler for the `CLICK_EVENT`.
955///
956/// ```
957/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
958/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
959/// # use zng_app::handler::async_app_hn;
960/// # use zng_task as task;
961/// # let _scope = zng_app::APP.minimal();
962/// # fn assert_type() {
963/// CLICK_EVENT.on_event(async_app_hn!(|_, _| {
964///     println!("Clicked Somewhere!");
965///
966///     task::run(async {
967///         println!("In other thread!");
968///     }).await;
969///
970///     println!("Back in UI thread, in an app update.");
971/// })).perm();
972/// # }
973/// ```
974///
975/// The closure input is `A, Box<dyn AppWeakHandle>` for all handlers and `A` is `ClickArgs` for this example. Note that
976/// if you want to use the event args you must annotate the input type, the context and handle types are inferred.
977///
978/// The handle can be used to unsubscribe the event handler, if [`unsubscribe`](AppWeakHandle::unsubscribe) is called the handler
979/// will be dropped some time before the next event update. Running tasks are not canceled by unsubscribing, the only way to *cancel*
980/// then is by returning early inside the async blocks.
981///
982/// ```
983/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
984/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
985/// # use zng_app::handler::async_app_hn;
986/// # use zng_task as task;
987/// # let _scope = zng_app::APP.minimal();
988/// # fn assert_type() {
989/// CLICK_EVENT.on_event(async_app_hn!(|args: ClickArgs, handle| {
990///     println!("Clicked {}!", args.target);
991///     task::run(async move {
992///         handle.unsubscribe();
993///     });
994/// })).perm();
995/// # }
996/// ```
997///
998/// Internally the [`async_clmv_fn!`] macro is used so you can *clone-move* variables into the handler.
999///
1000/// ```
1001/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
1002/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
1003/// # use zng_app::handler::async_app_hn;
1004/// # use zng_var::{var, Var};
1005/// # use zng_task as task;
1006/// # use zng_txt::{formatx, ToTxt};
1007/// #
1008/// # let _scope = zng_app::APP.minimal();
1009/// # fn assert_type() {
1010/// let status = var("pending..".to_txt());
1011///
1012/// CLICK_EVENT.on_event(async_app_hn!(status, |args: ClickArgs, _| {
1013///     status.set(formatx!("processing {}..", args.target));
1014///
1015///     task::run(async move {
1016///         println!("do something slow");
1017///     }).await;
1018///
1019///     status.set(formatx!("finished {}", args.target));
1020/// })).perm();
1021///
1022/// // can still use after:
1023/// let text = status;
1024///
1025/// # }
1026/// ```
1027///
1028/// In the example above only a clone of `status` is moved into the handler. Note that handlers always capture by move, if `status` was not
1029/// listed in the *clone-move* section it would not be available after the handler is created. See [`async_clmv_fn!`] for details.
1030///
1031/// ## Futures and Clone-Move
1032///
1033/// You may want to always *clone-move* captures for async handlers, because they then automatically get cloned again for each event. This
1034/// needs to happen because you can have more then one *handler task* running at the same type, and both want access to the captured variables.
1035///
1036/// This second cloning can be avoided by using the [`async_hn_once!`] macro instead, but only if you expect a single event.
1037///
1038/// [`async_clmv_fn!`]: zng_clone_move::async_clmv_fn
1039#[macro_export]
1040macro_rules! async_app_hn {
1041    ($($tt:tt)+) => {
1042        $crate::handler::async_app_hn($crate::handler::async_clmv_fn! { $($tt)+ })
1043    }
1044}
1045#[doc(inline)]
1046pub use crate::async_app_hn;
1047
1048#[doc(hidden)]
1049pub struct AsyncFnOnceAppHandler<H> {
1050    handler: Option<H>,
1051}
1052
1053impl<A, F, H> AppHandler<A> for AsyncFnOnceAppHandler<H>
1054where
1055    A: Clone + 'static,
1056    F: Future<Output = ()> + Send + 'static,
1057    H: FnOnce(A) -> F + Send + 'static,
1058{
1059    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
1060        if let Some(handler) = self.handler.take() {
1061            handler_args.handle.unsubscribe();
1062
1063            let mut task = UiTask::new(None, handler(args.clone()));
1064            if task.update().is_none() {
1065                if handler_args.is_preview {
1066                    UPDATES
1067                        .on_pre_update(app_hn!(|_, handle| {
1068                            if task.update().is_some() {
1069                                handle.unsubscribe();
1070                            }
1071                        }))
1072                        .perm();
1073                } else {
1074                    UPDATES
1075                        .on_update(app_hn!(|_, handle| {
1076                            if task.update().is_some() {
1077                                handle.unsubscribe();
1078                            }
1079                        }))
1080                        .perm();
1081                }
1082            }
1083        } else {
1084            tracing::error!("`async_app_hn_once!` called after requesting unsubscribe");
1085        }
1086    }
1087}
1088#[doc(hidden)]
1089#[cfg(not(feature = "dyn_closure"))]
1090pub fn async_app_hn_once<A, F, H>(handler: H) -> AsyncFnOnceAppHandler<H>
1091where
1092    A: Clone + 'static,
1093    F: Future<Output = ()> + Send + 'static,
1094    H: FnOnce(A) -> F + Send + 'static,
1095{
1096    AsyncFnOnceAppHandler { handler: Some(handler) }
1097}
1098
1099#[cfg(feature = "dyn_closure")]
1100type BoxedAsyncAppHnOnce<A> = Box<dyn FnOnce(A) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send>> + Send>;
1101
1102#[doc(hidden)]
1103#[cfg(feature = "dyn_closure")]
1104pub fn async_app_hn_once<A, F, H>(handler: H) -> AsyncFnOnceAppHandler<BoxedAsyncAppHnOnce<A>>
1105where
1106    A: Clone + 'static,
1107    F: Future<Output = ()> + Send + 'static,
1108    H: FnOnce(A) -> F + Send + 'static,
1109{
1110    AsyncFnOnceAppHandler {
1111        handler: Some(Box::new(move |args| Box::pin(handler(args)))),
1112    }
1113}
1114
1115///<span data-del-macro-root></span> Declare an async *clone-move* app event handler that is only called once.
1116///
1117/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn_once!`] so
1118/// the input is the same syntax.
1119///
1120/// # Examples
1121///
1122/// The example captures `data` by move and then moves it again to another thread. This is not something you can do using [`async_app_hn!`]
1123/// because that handler expects to be called many times. We want to handle `CLICK_EVENT` once in this example, so we can don't need
1124/// to capture by *clone-move* just to use `data`.
1125///
1126/// ```
1127/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
1128/// # use zng_app::handler::async_hn_once;
1129/// # use zng_task as task;
1130/// # let _scope = zng_app::APP.minimal();
1131/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
1132/// let data = vec![1, 2, 3];
1133/// # let
1134/// on_open = async_hn_once!(|_| {
1135///     task::run(async move {
1136///          for i in data {
1137///              print!("{i}, ");
1138///          }    
1139///     }).await;
1140///
1141///     println!("Done!");
1142/// });
1143/// # on_open }
1144/// ```
1145///
1146/// You can still *clone-move* to have access to the variable after creating the handler, in this case the `data` will be cloned into the handler
1147/// but will just be moved to the other thread, avoiding a needless clone.
1148///
1149/// ```
1150/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
1151/// # use zng_app::handler::async_hn_once;
1152/// # use zng_task as task;
1153/// # let _scope = zng_app::APP.minimal();
1154/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
1155/// let data = vec![1, 2, 3];
1156/// # let
1157/// on_open = async_hn_once!(data, |_| {
1158///     task::run(async move {
1159///          for i in data {
1160///              print!("{i}, ");
1161///          }    
1162///     }).await;
1163///
1164///     println!("Done!");
1165/// });
1166/// println!("{data:?}");
1167/// # on_open }
1168/// ```
1169///
1170/// [`async_clmv_fn_once!`]: zng_clone_move::async_clmv_fn_once
1171#[macro_export]
1172macro_rules! async_app_hn_once {
1173    ($($tt:tt)+) => {
1174        $crate::handler::async_app_hn_once($crate::handler::async_clmv_fn_once! { $($tt)+ })
1175    }
1176}
1177#[doc(inline)]
1178pub use crate::async_app_hn_once;
1179use crate::update::UPDATES;
1180use crate::widget::{UiTaskWidget, WIDGET};
1181
1182/// Widget handler wrapper that filters the events, only delegating to `self` when `filter` returns `true`.
1183pub struct FilterWidgetHandler<A, H, F> {
1184    _args: PhantomData<fn() -> A>,
1185    handler: H,
1186    filter: F,
1187}
1188impl<A, H, F> FilterWidgetHandler<A, H, F>
1189where
1190    A: Clone + 'static,
1191    H: WidgetHandler<A>,
1192    F: FnMut(&A) -> bool + Send + 'static,
1193{
1194    /// New filter handler.
1195    pub fn new(handler: H, filter: F) -> Self {
1196        Self {
1197            handler,
1198            filter,
1199            _args: PhantomData,
1200        }
1201    }
1202}
1203impl<A, H, F> WidgetHandler<A> for FilterWidgetHandler<A, H, F>
1204where
1205    A: Clone + 'static,
1206    H: WidgetHandler<A>,
1207    F: FnMut(&A) -> bool + Send + 'static,
1208{
1209    fn event(&mut self, args: &A) -> bool {
1210        if (self.filter)(args) { self.handler.event(args) } else { false }
1211    }
1212
1213    fn update(&mut self) -> bool {
1214        self.handler.update()
1215    }
1216}
1217
1218/// App handler wrapper that filters the events, only delegating to `self` when `filter` returns `true`.
1219pub struct FilterAppHandler<A, H, F> {
1220    _args: PhantomData<fn() -> A>,
1221    handler: H,
1222    filter: F,
1223}
1224impl<A, H, F> FilterAppHandler<A, H, F>
1225where
1226    A: Clone + 'static,
1227    H: AppHandler<A>,
1228    F: FnMut(&A) -> bool + Send + 'static,
1229{
1230    /// New filter handler.
1231    pub fn new(handler: H, filter: F) -> Self {
1232        Self {
1233            handler,
1234            filter,
1235            _args: PhantomData,
1236        }
1237    }
1238}
1239impl<A, H, F> AppHandler<A> for FilterAppHandler<A, H, F>
1240where
1241    A: Clone + 'static,
1242    H: AppHandler<A>,
1243    F: FnMut(&A) -> bool + Send + 'static,
1244{
1245    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
1246        if (self.filter)(args) {
1247            self.handler.event(args, handler_args);
1248        }
1249    }
1250}
1251
1252impl HeadlessApp {
1253    /// Calls an [`AppHandler<A>`] once and blocks until the update tasks started during the call complete.
1254    ///
1255    /// This function *spins* until all update tasks are completed. Timers or send events can
1256    /// be received during execution but the loop does not sleep, it just spins requesting an update
1257    /// for each pass.
1258    pub fn block_on<A>(&mut self, handler: &mut dyn AppHandler<A>, args: &A, timeout: Duration) -> Result<(), String>
1259    where
1260        A: Clone + 'static,
1261    {
1262        self.block_on_multi(vec![handler], args, timeout)
1263    }
1264
1265    /// Calls multiple [`AppHandler<A>`] once each and blocks until all update tasks are complete.
1266    ///
1267    /// This function *spins* until all update tasks are completed. Timers or send events can
1268    /// be received during execution but the loop does not sleep, it just spins requesting an update
1269    /// for each pass.
1270    pub fn block_on_multi<A>(&mut self, handlers: Vec<&mut dyn AppHandler<A>>, args: &A, timeout: Duration) -> Result<(), String>
1271    where
1272        A: Clone + 'static,
1273    {
1274        let (pre_len, pos_len) = UPDATES.handler_lens();
1275
1276        let handler_args = AppHandlerArgs {
1277            handle: &Handle::dummy(()).downgrade(),
1278            is_preview: false,
1279        };
1280        for handler in handlers {
1281            handler.event(args, &handler_args);
1282        }
1283
1284        let mut pending = UPDATES.new_update_handlers(pre_len, pos_len);
1285
1286        if !pending.is_empty() {
1287            let start_time = INSTANT.now();
1288            while {
1289                pending.retain(|h| h());
1290                !pending.is_empty()
1291            } {
1292                UPDATES.update(None);
1293                let flow = self.update(false);
1294                if INSTANT.now().duration_since(start_time) >= timeout {
1295                    return Err(format!(
1296                        "block_on reached timeout of {timeout:?} before the handler task could finish",
1297                    ));
1298                }
1299
1300                match flow {
1301                    AppControlFlow::Poll => continue,
1302                    AppControlFlow::Wait => {
1303                        thread::yield_now();
1304                        continue;
1305                    }
1306                    AppControlFlow::Exit => return Ok(()),
1307                }
1308            }
1309        }
1310
1311        Ok(())
1312    }
1313
1314    /// Polls a `future` and updates the app repeatedly until it completes or the `timeout` is reached.
1315    pub fn block_on_fut<F: Future>(&mut self, future: F, timeout: Duration) -> Result<F::Output, String> {
1316        let future = task::with_deadline(future, timeout);
1317        let mut future = std::pin::pin!(future);
1318
1319        let waker = UPDATES.waker(None);
1320        let mut cx = std::task::Context::from_waker(&waker);
1321
1322        loop {
1323            let mut fut_poll = future.as_mut().poll(&mut cx);
1324            let flow = self.update_observe(
1325                || {
1326                    if fut_poll.is_pending() {
1327                        fut_poll = future.as_mut().poll(&mut cx);
1328                    }
1329                },
1330                true,
1331            );
1332
1333            match fut_poll {
1334                std::task::Poll::Ready(r) => match r {
1335                    Ok(r) => return Ok(r),
1336                    Err(e) => return Err(e.to_string()),
1337                },
1338                std::task::Poll::Pending => {}
1339            }
1340
1341            match flow {
1342                AppControlFlow::Poll => continue,
1343                AppControlFlow::Wait => {
1344                    thread::yield_now();
1345                    continue;
1346                }
1347                AppControlFlow::Exit => return Err("app exited".to_owned()),
1348            }
1349        }
1350    }
1351
1352    /// Calls the `handler` once and [`block_on`] it with a 60 seconds timeout using the minimal headless app.
1353    ///
1354    /// [`block_on`]: Self::block_on
1355    #[track_caller]
1356    #[cfg(any(test, doc, feature = "test_util"))]
1357    pub fn doc_test<A, H>(args: A, mut handler: H)
1358    where
1359        A: Clone + 'static,
1360        H: AppHandler<A>,
1361    {
1362        let mut app = crate::APP.minimal().run_headless(false);
1363        app.block_on(&mut handler, &args, DOC_TEST_BLOCK_ON_TIMEOUT).unwrap();
1364    }
1365
1366    /// Calls the `handlers` once each and [`block_on_multi`] with a 60 seconds timeout.
1367    ///
1368    /// [`block_on_multi`]: Self::block_on_multi
1369    #[track_caller]
1370    #[cfg(any(test, doc, feature = "test_util"))]
1371    pub fn doc_test_multi<A>(args: A, mut handlers: Vec<Box<dyn AppHandler<A>>>)
1372    where
1373        A: Clone + 'static,
1374    {
1375        let mut app = crate::APP.minimal().run_headless(false);
1376        app.block_on_multi(handlers.iter_mut().map(|h| h.as_mut()).collect(), &args, DOC_TEST_BLOCK_ON_TIMEOUT)
1377            .unwrap()
1378    }
1379}
1380
1381#[cfg(any(test, doc, feature = "test_util"))]
1382const DOC_TEST_BLOCK_ON_TIMEOUT: Duration = Duration::from_secs(60);