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`].
607#[non_exhaustive]
608pub struct AppHandlerArgs<'a> {
609    /// Handle to the [`AppHandler`] subscription.
610    pub handle: &'a dyn AppWeakHandle,
611    /// If the handler is invoked in a *preview* context.
612    pub is_preview: bool,
613}
614
615/// Represents an event handler in the app context.
616///
617/// There are different flavors of handlers, you can use macros to declare then.
618/// See [`app_hn!`], [`app_hn_once!`] or [`async_app_hn!`], [`async_app_hn_once!`] to start.
619#[diagnostic::on_unimplemented(
620    note = "use `app_hn!(|args: &{A}, _| {{ }})` to declare an app handler closure",
621    note = "use `app_hn_once!`, `async_app_hn!` or `async_app_hn_once!` for other closure types"
622)]
623pub trait AppHandler<A: Clone + 'static>: Any + Send {
624    /// Called every time the event happens.
625    ///
626    /// The `handler_args` can be used to unsubscribe the handler. Async handlers are expected to schedule
627    /// their tasks to run somewhere in the app, usually in the [`UPDATES.on_update`]. The `handle` is
628    /// **not** expected to cancel running async tasks, only to drop `self` before the next event happens.
629    ///
630    /// [`UPDATES.on_update`]: crate::update::UPDATES::on_update
631    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs);
632
633    /// Boxes the handler.
634    ///
635    /// The type `Box<dyn AppHandler<A>>` implements `AppHandler<A>` and just returns itself
636    /// in this method, avoiding double boxing.
637    fn boxed(self) -> Box<dyn AppHandler<A>>
638    where
639        Self: Sized,
640    {
641        Box::new(self)
642    }
643
644    /// Boxes the handler if the `feature = "dyn_closure"` is enabled, otherwise maintain the same type.
645    #[cfg(feature = "dyn_closure")]
646    fn cfg_boxed(self) -> Box<dyn AppHandler<A>>
647    where
648        Self: Sized,
649    {
650        self.boxed()
651    }
652
653    /// Boxes the handler if the `feature = "dyn_closure"` is enabled, otherwise maintain the same type.    
654    #[cfg(not(feature = "dyn_closure"))]
655    fn cfg_boxed(self) -> Self
656    where
657        Self: Sized,
658    {
659        self
660    }
661}
662impl<A: Clone + 'static> AppHandler<A> for Box<dyn AppHandler<A>> {
663    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
664        self.as_mut().event(args, handler_args)
665    }
666
667    fn boxed(self) -> Box<dyn AppHandler<A>> {
668        self
669    }
670}
671
672#[doc(hidden)]
673pub struct FnMutAppHandler<H> {
674    handler: H,
675}
676impl<A, H> AppHandler<A> for FnMutAppHandler<H>
677where
678    A: Clone + 'static,
679    H: FnMut(&A, &dyn AppWeakHandle) + Send + 'static,
680{
681    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
682        (self.handler)(args, handler_args.handle);
683    }
684}
685#[doc(hidden)]
686#[cfg(not(feature = "dyn_closure"))]
687pub fn app_hn<A, H>(handler: H) -> FnMutAppHandler<H>
688where
689    A: Clone + 'static,
690    H: FnMut(&A, &dyn AppWeakHandle) + Send + 'static,
691{
692    FnMutAppHandler { handler }
693}
694
695#[cfg(feature = "dyn_closure")]
696type BoxedAppHn<A> = Box<dyn FnMut(&A, &dyn AppWeakHandle) + Send>;
697
698#[doc(hidden)]
699#[cfg(feature = "dyn_closure")]
700pub fn app_hn<A, H>(handler: H) -> FnMutAppHandler<BoxedAppHn<A>>
701where
702    A: Clone + 'static,
703    H: FnMut(&A, &dyn AppWeakHandle) + Send + 'static,
704{
705    FnMutAppHandler {
706        handler: Box::new(handler),
707    }
708}
709
710///<span data-del-macro-root></span> Declare a mutable *clone-move* app event handler.
711///
712/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
713/// the input is the same syntax.
714///
715/// # Examples
716///
717/// The example declares an event handler for the `CLICK_EVENT`.
718///
719/// ```
720/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
721/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
722/// # use zng_app::handler::app_hn;
723/// # let _scope = zng_app::APP.minimal();
724/// # fn assert_type() {
725/// CLICK_EVENT.on_event(app_hn!(|_, _| {
726///     println!("Clicked Somewhere!");
727/// })).perm();
728/// # }
729/// ```
730///
731/// The closure input is `&A, &dyn AppWeakHandle` with `&A` equaling `&ClickArgs` for this event. Note that
732/// if you want to use the event args you must annotate the input type, the context and handle type is inferred.
733///
734/// The handle can be used to unsubscribe the event handler, if [`unsubscribe`](AppWeakHandle::unsubscribe) is called the handler
735/// will be dropped some time before the next event update.
736///
737/// ```
738/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
739/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
740/// # use zng_app::handler::app_hn;
741/// # let _scope = zng_app::APP.minimal();
742/// # fn assert_type() {
743/// CLICK_EVENT.on_event(app_hn!(|args: &ClickArgs, handle| {
744///     println!("Clicked {}!", args.target);
745///     handle.unsubscribe();
746/// })).perm();
747/// # }
748/// ```
749///
750/// Internally the [`clmv!`] macro is used so you can *clone-move* variables into the handler.
751///
752/// ```
753/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
754/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
755/// # use zng_txt::{formatx, ToTxt};
756/// # use zng_var::{var, Var};
757/// # use zng_app::handler::app_hn;
758/// # let _scope = zng_app::APP.minimal();
759/// # fn assert_type() {
760/// let foo = var("".to_txt());
761///
762/// CLICK_EVENT.on_event(app_hn!(foo, |args: &ClickArgs, _| {
763///     foo.set(args.target.to_txt());
764/// })).perm();
765///
766/// // can still use after:
767/// let bar = foo.map(|c| formatx!("last click: {c}"));
768///
769/// # }
770/// ```
771///
772/// 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
773/// listed in the *clone-move* section it would not be available after the handler is created. See [`clmv!`] for details.
774///
775/// [`clmv!`]: zng_clone_move::clmv
776#[macro_export]
777macro_rules! app_hn {
778    ($($tt:tt)+) => {
779        $crate::handler::app_hn($crate::handler::clmv!{ $($tt)+ })
780    }
781}
782#[doc(inline)]
783pub use crate::app_hn;
784
785#[doc(hidden)]
786pub struct FnOnceAppHandler<H> {
787    handler: Option<H>,
788}
789impl<A, H> AppHandler<A> for FnOnceAppHandler<H>
790where
791    A: Clone + 'static,
792    H: FnOnce(&A) + Send + 'static,
793{
794    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
795        if let Some(handler) = self.handler.take() {
796            handler(args);
797            handler_args.handle.unsubscribe();
798        } else {
799            tracing::error!("`app_hn_once!` called after requesting unsubscribe");
800        }
801    }
802}
803#[doc(hidden)]
804#[cfg(not(feature = "dyn_closure"))]
805pub fn app_hn_once<A, H>(handler: H) -> FnOnceAppHandler<H>
806where
807    A: Clone + 'static,
808    H: FnOnce(&A) + Send + 'static,
809{
810    FnOnceAppHandler { handler: Some(handler) }
811}
812#[doc(hidden)]
813#[cfg(feature = "dyn_closure")]
814pub fn app_hn_once<A, H>(handler: H) -> FnOnceAppHandler<Box<dyn FnOnce(&A) + Send>>
815where
816    A: Clone + 'static,
817    H: FnOnce(&A) + Send + 'static,
818{
819    FnOnceAppHandler {
820        handler: Some(Box::new(handler)),
821    }
822}
823
824///<span data-del-macro-root></span> Declare a *clone-move* app event handler that is only called once.
825///
826/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
827/// the input is the same syntax.
828///
829/// # Examples
830///
831/// The example captures `data` by move and then destroys it in the first call, this cannot be done using [`app_hn!`] because
832/// the `data` needs to be available for all event calls. In this case the closure is only called once, subsequent events
833/// are ignored by the handler and it automatically requests unsubscribe.
834///
835/// ```
836/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
837/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
838/// # use zng_app::handler::app_hn_once;
839/// # let _scope = zng_app::APP.minimal();
840/// # fn assert_type() {
841/// let data = vec![1, 2, 3];
842///
843/// CLICK_EVENT.on_event(app_hn_once!(|_| {
844///     for i in data {
845///         print!("{i}, ");
846///     }
847/// })).perm();
848/// # }
849/// ```
850///
851/// Other then declaring a `FnOnce` this macro behaves like [`app_hn!`], so the same considerations apply. You can *clone-move* variables,
852/// the type of the input is the event arguments and must be annotated.
853///
854/// ```
855/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
856/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
857/// # use zng_app::handler::app_hn_once;
858/// # let _scope = zng_app::APP.minimal();
859/// # fn assert_type() {
860/// let data = vec![1, 2, 3];
861///
862/// CLICK_EVENT.on_event(app_hn_once!(data, |args: &ClickArgs| {
863///     drop(data);
864/// })).perm();
865///
866/// println!("{data:?}");
867/// # }
868/// ```
869///
870/// [`clmv!`]: zng_clone_move::clmv
871#[macro_export]
872macro_rules! app_hn_once {
873    ($($tt:tt)+) => {
874        $crate::handler::app_hn_once($crate::handler::clmv! { $($tt)+ })
875    }
876}
877#[doc(inline)]
878pub use crate::app_hn_once;
879
880#[doc(hidden)]
881pub struct AsyncFnMutAppHandler<H> {
882    handler: H,
883}
884impl<A, F, H> AppHandler<A> for AsyncFnMutAppHandler<H>
885where
886    A: Clone + 'static,
887    F: Future<Output = ()> + Send + 'static,
888    H: FnMut(A, Box<dyn AppWeakHandle>) -> F + Send + 'static,
889{
890    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
891        let handler = &mut self.handler;
892        let mut task = UiTask::new(None, handler(args.clone(), handler_args.handle.clone_boxed()));
893        if task.update().is_none() {
894            if handler_args.is_preview {
895                UPDATES
896                    .on_pre_update(app_hn!(|_, handle| {
897                        if task.update().is_some() {
898                            handle.unsubscribe();
899                        }
900                    }))
901                    .perm();
902            } else {
903                UPDATES
904                    .on_update(app_hn!(|_, handle| {
905                        if task.update().is_some() {
906                            handle.unsubscribe();
907                        }
908                    }))
909                    .perm();
910            }
911        }
912    }
913}
914#[doc(hidden)]
915#[cfg(not(feature = "dyn_closure"))]
916pub fn async_app_hn<A, F, H>(handler: H) -> AsyncFnMutAppHandler<H>
917where
918    A: Clone + 'static,
919    F: Future<Output = ()> + Send + 'static,
920    H: FnMut(A, Box<dyn AppWeakHandle>) -> F + Send + 'static,
921{
922    AsyncFnMutAppHandler { handler }
923}
924
925#[cfg(feature = "dyn_closure")]
926type BoxedAsyncAppHn<A> = Box<dyn FnMut(A, Box<dyn AppWeakHandle>) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send>> + Send>;
927
928#[doc(hidden)]
929#[cfg(feature = "dyn_closure")]
930pub fn async_app_hn<A, F, H>(mut handler: H) -> AsyncFnMutAppHandler<BoxedAsyncAppHn<A>>
931where
932    A: Clone + 'static,
933    F: Future<Output = ()> + Send + 'static,
934    H: FnMut(A, Box<dyn AppWeakHandle>) -> F + Send + 'static,
935{
936    AsyncFnMutAppHandler {
937        handler: Box::new(move |args, handle| Box::pin(handler(args, handle))),
938    }
939}
940
941///<span data-del-macro-root></span> Declare an async *clone-move* app event handler.
942///
943/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn!`] so
944/// the input is the same syntax.
945///
946/// The handler generates a future for each event, the future is polled immediately if it does not finish it is scheduled
947/// to update in [`on_pre_update`](crate::update::UPDATES::on_pre_update) or [`on_update`](crate::update::UPDATES::on_update) depending
948/// on if the handler was assigned to a *preview* event or not.
949///
950/// Note that this means [`propagation`](crate::event::AnyEventArgs::propagation) can only be meaningfully stopped before the
951/// first `.await`, after, the event has already propagated.
952///
953/// # Examples
954///
955/// The example declares an async event handler for the `CLICK_EVENT`.
956///
957/// ```
958/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
959/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
960/// # use zng_app::handler::async_app_hn;
961/// # use zng_task as task;
962/// # let _scope = zng_app::APP.minimal();
963/// # fn assert_type() {
964/// CLICK_EVENT.on_event(async_app_hn!(|_, _| {
965///     println!("Clicked Somewhere!");
966///
967///     task::run(async {
968///         println!("In other thread!");
969///     }).await;
970///
971///     println!("Back in UI thread, in an app update.");
972/// })).perm();
973/// # }
974/// ```
975///
976/// The closure input is `A, Box<dyn AppWeakHandle>` for all handlers and `A` is `ClickArgs` for this example. Note that
977/// if you want to use the event args you must annotate the input type, the context and handle types are inferred.
978///
979/// The handle can be used to unsubscribe the event handler, if [`unsubscribe`](AppWeakHandle::unsubscribe) is called the handler
980/// will be dropped some time before the next event update. Running tasks are not canceled by unsubscribing, the only way to *cancel*
981/// then is by returning early inside the async blocks.
982///
983/// ```
984/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
985/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
986/// # use zng_app::handler::async_app_hn;
987/// # use zng_task as task;
988/// # let _scope = zng_app::APP.minimal();
989/// # fn assert_type() {
990/// CLICK_EVENT.on_event(async_app_hn!(|args: ClickArgs, handle| {
991///     println!("Clicked {}!", args.target);
992///     task::run(async move {
993///         handle.unsubscribe();
994///     });
995/// })).perm();
996/// # }
997/// ```
998///
999/// Internally the [`async_clmv_fn!`] macro is used so you can *clone-move* variables into the handler.
1000///
1001/// ```
1002/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
1003/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
1004/// # use zng_app::handler::async_app_hn;
1005/// # use zng_var::{var, Var};
1006/// # use zng_task as task;
1007/// # use zng_txt::{formatx, ToTxt};
1008/// #
1009/// # let _scope = zng_app::APP.minimal();
1010/// # fn assert_type() {
1011/// let status = var("pending..".to_txt());
1012///
1013/// CLICK_EVENT.on_event(async_app_hn!(status, |args: ClickArgs, _| {
1014///     status.set(formatx!("processing {}..", args.target));
1015///
1016///     task::run(async move {
1017///         println!("do something slow");
1018///     }).await;
1019///
1020///     status.set(formatx!("finished {}", args.target));
1021/// })).perm();
1022///
1023/// // can still use after:
1024/// let text = status;
1025///
1026/// # }
1027/// ```
1028///
1029/// 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
1030/// listed in the *clone-move* section it would not be available after the handler is created. See [`async_clmv_fn!`] for details.
1031///
1032/// ## Futures and Clone-Move
1033///
1034/// You may want to always *clone-move* captures for async handlers, because they then automatically get cloned again for each event. This
1035/// 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.
1036///
1037/// This second cloning can be avoided by using the [`async_hn_once!`] macro instead, but only if you expect a single event.
1038///
1039/// [`async_clmv_fn!`]: zng_clone_move::async_clmv_fn
1040#[macro_export]
1041macro_rules! async_app_hn {
1042    ($($tt:tt)+) => {
1043        $crate::handler::async_app_hn($crate::handler::async_clmv_fn! { $($tt)+ })
1044    }
1045}
1046#[doc(inline)]
1047pub use crate::async_app_hn;
1048
1049#[doc(hidden)]
1050pub struct AsyncFnOnceAppHandler<H> {
1051    handler: Option<H>,
1052}
1053
1054impl<A, F, H> AppHandler<A> for AsyncFnOnceAppHandler<H>
1055where
1056    A: Clone + 'static,
1057    F: Future<Output = ()> + Send + 'static,
1058    H: FnOnce(A) -> F + Send + 'static,
1059{
1060    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
1061        if let Some(handler) = self.handler.take() {
1062            handler_args.handle.unsubscribe();
1063
1064            let mut task = UiTask::new(None, handler(args.clone()));
1065            if task.update().is_none() {
1066                if handler_args.is_preview {
1067                    UPDATES
1068                        .on_pre_update(app_hn!(|_, handle| {
1069                            if task.update().is_some() {
1070                                handle.unsubscribe();
1071                            }
1072                        }))
1073                        .perm();
1074                } else {
1075                    UPDATES
1076                        .on_update(app_hn!(|_, handle| {
1077                            if task.update().is_some() {
1078                                handle.unsubscribe();
1079                            }
1080                        }))
1081                        .perm();
1082                }
1083            }
1084        } else {
1085            tracing::error!("`async_app_hn_once!` called after requesting unsubscribe");
1086        }
1087    }
1088}
1089#[doc(hidden)]
1090#[cfg(not(feature = "dyn_closure"))]
1091pub fn async_app_hn_once<A, F, H>(handler: H) -> AsyncFnOnceAppHandler<H>
1092where
1093    A: Clone + 'static,
1094    F: Future<Output = ()> + Send + 'static,
1095    H: FnOnce(A) -> F + Send + 'static,
1096{
1097    AsyncFnOnceAppHandler { handler: Some(handler) }
1098}
1099
1100#[cfg(feature = "dyn_closure")]
1101type BoxedAsyncAppHnOnce<A> = Box<dyn FnOnce(A) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send>> + Send>;
1102
1103#[doc(hidden)]
1104#[cfg(feature = "dyn_closure")]
1105pub fn async_app_hn_once<A, F, H>(handler: H) -> AsyncFnOnceAppHandler<BoxedAsyncAppHnOnce<A>>
1106where
1107    A: Clone + 'static,
1108    F: Future<Output = ()> + Send + 'static,
1109    H: FnOnce(A) -> F + Send + 'static,
1110{
1111    AsyncFnOnceAppHandler {
1112        handler: Some(Box::new(move |args| Box::pin(handler(args)))),
1113    }
1114}
1115
1116///<span data-del-macro-root></span> Declare an async *clone-move* app event handler that is only called once.
1117///
1118/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn_once!`] so
1119/// the input is the same syntax.
1120///
1121/// # Examples
1122///
1123/// 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!`]
1124/// 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
1125/// to capture by *clone-move* just to use `data`.
1126///
1127/// ```
1128/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
1129/// # use zng_app::handler::async_hn_once;
1130/// # use zng_task as task;
1131/// # let _scope = zng_app::APP.minimal();
1132/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
1133/// let data = vec![1, 2, 3];
1134/// # let
1135/// on_open = async_hn_once!(|_| {
1136///     task::run(async move {
1137///          for i in data {
1138///              print!("{i}, ");
1139///          }    
1140///     }).await;
1141///
1142///     println!("Done!");
1143/// });
1144/// # on_open }
1145/// ```
1146///
1147/// 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
1148/// but will just be moved to the other thread, avoiding a needless clone.
1149///
1150/// ```
1151/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
1152/// # use zng_app::handler::async_hn_once;
1153/// # use zng_task as task;
1154/// # let _scope = zng_app::APP.minimal();
1155/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
1156/// let data = vec![1, 2, 3];
1157/// # let
1158/// on_open = async_hn_once!(data, |_| {
1159///     task::run(async move {
1160///          for i in data {
1161///              print!("{i}, ");
1162///          }    
1163///     }).await;
1164///
1165///     println!("Done!");
1166/// });
1167/// println!("{data:?}");
1168/// # on_open }
1169/// ```
1170///
1171/// [`async_clmv_fn_once!`]: zng_clone_move::async_clmv_fn_once
1172#[macro_export]
1173macro_rules! async_app_hn_once {
1174    ($($tt:tt)+) => {
1175        $crate::handler::async_app_hn_once($crate::handler::async_clmv_fn_once! { $($tt)+ })
1176    }
1177}
1178#[doc(inline)]
1179pub use crate::async_app_hn_once;
1180use crate::update::UPDATES;
1181use crate::widget::{UiTaskWidget, WIDGET};
1182
1183/// Widget handler wrapper that filters the events, only delegating to `self` when `filter` returns `true`.
1184pub struct FilterWidgetHandler<A, H, F> {
1185    _args: PhantomData<fn() -> A>,
1186    handler: H,
1187    filter: F,
1188}
1189impl<A, H, F> FilterWidgetHandler<A, H, F>
1190where
1191    A: Clone + 'static,
1192    H: WidgetHandler<A>,
1193    F: FnMut(&A) -> bool + Send + 'static,
1194{
1195    /// New filter handler.
1196    pub fn new(handler: H, filter: F) -> Self {
1197        Self {
1198            handler,
1199            filter,
1200            _args: PhantomData,
1201        }
1202    }
1203}
1204impl<A, H, F> WidgetHandler<A> for FilterWidgetHandler<A, H, F>
1205where
1206    A: Clone + 'static,
1207    H: WidgetHandler<A>,
1208    F: FnMut(&A) -> bool + Send + 'static,
1209{
1210    fn event(&mut self, args: &A) -> bool {
1211        if (self.filter)(args) { self.handler.event(args) } else { false }
1212    }
1213
1214    fn update(&mut self) -> bool {
1215        self.handler.update()
1216    }
1217}
1218
1219/// App handler wrapper that filters the events, only delegating to `self` when `filter` returns `true`.
1220pub struct FilterAppHandler<A, H, F> {
1221    _args: PhantomData<fn() -> A>,
1222    handler: H,
1223    filter: F,
1224}
1225impl<A, H, F> FilterAppHandler<A, H, F>
1226where
1227    A: Clone + 'static,
1228    H: AppHandler<A>,
1229    F: FnMut(&A) -> bool + Send + 'static,
1230{
1231    /// New filter handler.
1232    pub fn new(handler: H, filter: F) -> Self {
1233        Self {
1234            handler,
1235            filter,
1236            _args: PhantomData,
1237        }
1238    }
1239}
1240impl<A, H, F> AppHandler<A> for FilterAppHandler<A, H, F>
1241where
1242    A: Clone + 'static,
1243    H: AppHandler<A>,
1244    F: FnMut(&A) -> bool + Send + 'static,
1245{
1246    fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
1247        if (self.filter)(args) {
1248            self.handler.event(args, handler_args);
1249        }
1250    }
1251}
1252
1253impl HeadlessApp {
1254    /// Calls an [`AppHandler<A>`] once and blocks until the update tasks started during the call complete.
1255    ///
1256    /// This function *spins* until all update tasks are completed. Timers or send events can
1257    /// be received during execution but the loop does not sleep, it just spins requesting an update
1258    /// for each pass.
1259    pub fn block_on<A>(&mut self, handler: &mut dyn AppHandler<A>, args: &A, timeout: Duration) -> Result<(), String>
1260    where
1261        A: Clone + 'static,
1262    {
1263        self.block_on_multi(vec![handler], args, timeout)
1264    }
1265
1266    /// Calls multiple [`AppHandler<A>`] once each and blocks until all update tasks are complete.
1267    ///
1268    /// This function *spins* until all update tasks are completed. Timers or send events can
1269    /// be received during execution but the loop does not sleep, it just spins requesting an update
1270    /// for each pass.
1271    pub fn block_on_multi<A>(&mut self, handlers: Vec<&mut dyn AppHandler<A>>, args: &A, timeout: Duration) -> Result<(), String>
1272    where
1273        A: Clone + 'static,
1274    {
1275        let (pre_len, pos_len) = UPDATES.handler_lens();
1276
1277        let handler_args = AppHandlerArgs {
1278            handle: &Handle::dummy(()).downgrade(),
1279            is_preview: false,
1280        };
1281        for handler in handlers {
1282            handler.event(args, &handler_args);
1283        }
1284
1285        let mut pending = UPDATES.new_update_handlers(pre_len, pos_len);
1286
1287        if !pending.is_empty() {
1288            let start_time = INSTANT.now();
1289            while {
1290                pending.retain(|h| h());
1291                !pending.is_empty()
1292            } {
1293                UPDATES.update(None);
1294                let flow = self.update(false);
1295                if INSTANT.now().duration_since(start_time) >= timeout {
1296                    return Err(format!(
1297                        "block_on reached timeout of {timeout:?} before the handler task could finish",
1298                    ));
1299                }
1300
1301                match flow {
1302                    AppControlFlow::Poll => continue,
1303                    AppControlFlow::Wait => {
1304                        thread::yield_now();
1305                        continue;
1306                    }
1307                    AppControlFlow::Exit => return Ok(()),
1308                }
1309            }
1310        }
1311
1312        Ok(())
1313    }
1314
1315    /// Polls a `future` and updates the app repeatedly until it completes or the `timeout` is reached.
1316    pub fn block_on_fut<F: Future>(&mut self, future: F, timeout: Duration) -> Result<F::Output, String> {
1317        let future = task::with_deadline(future, timeout);
1318        let mut future = std::pin::pin!(future);
1319
1320        let waker = UPDATES.waker(None);
1321        let mut cx = std::task::Context::from_waker(&waker);
1322
1323        loop {
1324            let mut fut_poll = future.as_mut().poll(&mut cx);
1325            let flow = self.update_observe(
1326                || {
1327                    if fut_poll.is_pending() {
1328                        fut_poll = future.as_mut().poll(&mut cx);
1329                    }
1330                },
1331                true,
1332            );
1333
1334            match fut_poll {
1335                std::task::Poll::Ready(r) => match r {
1336                    Ok(r) => return Ok(r),
1337                    Err(e) => return Err(e.to_string()),
1338                },
1339                std::task::Poll::Pending => {}
1340            }
1341
1342            match flow {
1343                AppControlFlow::Poll => continue,
1344                AppControlFlow::Wait => {
1345                    thread::yield_now();
1346                    continue;
1347                }
1348                AppControlFlow::Exit => return Err("app exited".to_owned()),
1349            }
1350        }
1351    }
1352
1353    /// Calls the `handler` once and [`block_on`] it with a 60 seconds timeout using the minimal headless app.
1354    ///
1355    /// [`block_on`]: Self::block_on
1356    #[track_caller]
1357    #[cfg(any(test, doc, feature = "test_util"))]
1358    pub fn doc_test<A, H>(args: A, mut handler: H)
1359    where
1360        A: Clone + 'static,
1361        H: AppHandler<A>,
1362    {
1363        let mut app = crate::APP.minimal().run_headless(false);
1364        app.block_on(&mut handler, &args, DOC_TEST_BLOCK_ON_TIMEOUT).unwrap();
1365    }
1366
1367    /// Calls the `handlers` once each and [`block_on_multi`] with a 60 seconds timeout.
1368    ///
1369    /// [`block_on_multi`]: Self::block_on_multi
1370    #[track_caller]
1371    #[cfg(any(test, doc, feature = "test_util"))]
1372    pub fn doc_test_multi<A>(args: A, mut handlers: Vec<Box<dyn AppHandler<A>>>)
1373    where
1374        A: Clone + 'static,
1375    {
1376        let mut app = crate::APP.minimal().run_headless(false);
1377        app.block_on_multi(handlers.iter_mut().map(|h| h.as_mut()).collect(), &args, DOC_TEST_BLOCK_ON_TIMEOUT)
1378            .unwrap()
1379    }
1380}
1381
1382#[cfg(any(test, doc, feature = "test_util"))]
1383const DOC_TEST_BLOCK_ON_TIMEOUT: Duration = Duration::from_secs(60);