zng_app/
timer.rs

1//! App timers, deadlines and timeouts.
2//!
3//! The primary `struct` of this module is [`TIMERS`]. You can use it to
4//! create UI bound timers that run using only the main thread and can awake the app event loop
5//! to notify updates.
6
7use crate::Deadline;
8use parking_lot::Mutex;
9use std::{
10    fmt, mem,
11    pin::Pin,
12    sync::{
13        Arc,
14        atomic::{AtomicBool, AtomicUsize, Ordering},
15    },
16    task::Waker,
17    time::Duration,
18};
19use zng_app_context::app_local;
20use zng_handle::{Handle, HandleOwner, WeakHandle};
21use zng_time::{DInstant, INSTANT, INSTANT_APP};
22use zng_var::{ReadOnlyArcVar, Var, WeakVar, types::WeakArcVar, var};
23
24use crate::{
25    LoopTimer,
26    handler::{AppHandler, AppHandlerArgs, AppWeakHandle},
27    update::UPDATES,
28};
29
30struct DeadlineHandlerEntry {
31    handle: HandleOwner<DeadlineState>,
32    handler: Mutex<Box<dyn FnMut(&dyn AppWeakHandle) + Send>>, // not actually locked, just makes this Sync
33    pending: bool,
34}
35
36struct TimerHandlerEntry {
37    handle: HandleOwner<TimerState>,
38    handler: Mutex<Box<dyn FnMut(&TimerArgs, &dyn AppWeakHandle) + Send>>, // not actually locked, just makes this Sync
39    pending: Option<Deadline>,                                             // the last expected deadline
40}
41
42struct WaitDeadline {
43    deadline: Deadline,
44    wakers: Mutex<Vec<Waker>>,
45}
46struct WaitDeadlineFut(Arc<WaitDeadline>);
47impl Future for WaitDeadlineFut {
48    type Output = ();
49
50    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> {
51        if self.0.deadline.has_elapsed() {
52            std::task::Poll::Ready(())
53        } else {
54            let waker = cx.waker().clone();
55            self.0.wakers.lock().push(waker);
56            std::task::Poll::Pending
57        }
58    }
59}
60
61struct TimerVarEntry {
62    handle: HandleOwner<TimerState>,
63    weak_var: WeakArcVar<Timer>,
64}
65
66app_local! {
67    pub(crate) static TIMERS_SV: TimersService = const { TimersService::new() };
68}
69
70pub(crate) struct TimersService {
71    deadlines: Vec<WeakArcVar<Deadline>>,
72    wait_deadlines: Vec<std::sync::Weak<WaitDeadline>>,
73    timers: Vec<TimerVarEntry>,
74    deadline_handlers: Vec<DeadlineHandlerEntry>,
75    timer_handlers: Vec<TimerHandlerEntry>,
76    has_pending_handlers: bool,
77}
78impl TimersService {
79    const fn new() -> Self {
80        Self {
81            deadlines: vec![],
82            wait_deadlines: vec![],
83            timers: vec![],
84            deadline_handlers: vec![],
85            timer_handlers: vec![],
86            has_pending_handlers: false,
87        }
88    }
89
90    fn deadline(&mut self, deadline: Deadline) -> DeadlineVar {
91        let timer = var(deadline);
92        self.deadlines.push(timer.downgrade());
93        UPDATES.send_awake();
94        timer.read_only()
95    }
96
97    fn wait_deadline(&mut self, deadline: Deadline) -> impl Future<Output = ()> + Send + Sync + use<> {
98        let deadline = Arc::new(WaitDeadline {
99            deadline,
100            wakers: Mutex::new(vec![]),
101        });
102        self.wait_deadlines.push(Arc::downgrade(&deadline));
103        UPDATES.send_awake();
104        WaitDeadlineFut(deadline)
105    }
106
107    fn interval(&mut self, interval: Duration, paused: bool) -> TimerVar {
108        let (owner, handle) = TimerHandle::new(interval, paused);
109        let timer = var(Timer(handle));
110        self.timers.push(TimerVarEntry {
111            handle: owner,
112            weak_var: timer.downgrade(),
113        });
114        UPDATES.send_awake();
115        timer.read_only()
116    }
117
118    fn on_deadline<H>(&mut self, deadline: Deadline, mut handler: H) -> DeadlineHandle
119    where
120        H: AppHandler<DeadlineArgs>,
121    {
122        let (handle_owner, handle) = DeadlineHandle::new(deadline);
123        self.deadline_handlers.push(DeadlineHandlerEntry {
124            handle: handle_owner,
125            handler: Mutex::new(Box::new(move |handle| {
126                handler.event(
127                    &DeadlineArgs {
128                        timestamp: INSTANT.now(),
129                        deadline,
130                    },
131                    &AppHandlerArgs { handle, is_preview: true },
132                )
133            })),
134            pending: false,
135        });
136        UPDATES.send_awake();
137        handle
138    }
139
140    fn on_interval<H>(&mut self, interval: Duration, paused: bool, mut handler: H) -> TimerHandle
141    where
142        H: AppHandler<TimerArgs>,
143    {
144        let (owner, handle) = TimerHandle::new(interval, paused);
145
146        self.timer_handlers.push(TimerHandlerEntry {
147            handle: owner,
148            handler: Mutex::new(Box::new(move |args, handle| {
149                handler.event(args, &AppHandlerArgs { handle, is_preview: true });
150            })),
151            pending: None,
152        });
153        UPDATES.send_awake();
154        handle
155    }
156
157    pub(crate) fn next_deadline(&self, timer: &mut LoopTimer) {
158        for wk in &self.deadlines {
159            if let Some(var) = wk.upgrade() {
160                timer.register(var.get());
161            }
162        }
163
164        for wk in &self.wait_deadlines {
165            if let Some(e) = wk.upgrade() {
166                timer.register(e.deadline);
167            }
168        }
169
170        for t in &self.timers {
171            if let Some(var) = t.weak_var.upgrade() {
172                if !t.handle.is_dropped() && !t.handle.data().paused.load(Ordering::Relaxed) {
173                    // not dropped and not paused
174                    var.with(|t| {
175                        let deadline = t.0.0.data().deadline.lock();
176                        timer.register(deadline.current_deadline());
177                    });
178                }
179            }
180        }
181
182        for e in &self.deadline_handlers {
183            if !e.handle.is_dropped() {
184                let deadline = e.handle.data().deadline;
185                timer.register(deadline);
186            }
187        }
188
189        for t in &self.timer_handlers {
190            if !t.handle.is_dropped() {
191                let state = t.handle.data();
192                if !state.paused.load(Ordering::Relaxed) {
193                    let deadline = state.deadline.lock();
194                    timer.register(deadline.current_deadline());
195                }
196            }
197        }
198    }
199
200    /// if the last `apply_updates` observed elapsed timers.
201    pub(crate) fn has_pending_updates(&self) -> bool {
202        self.has_pending_handlers
203    }
204
205    /// Update timer vars, flag handlers to be called in [`Self::notify`], returns new app wake time.
206    pub(crate) fn apply_updates(&mut self, timer: &mut LoopTimer) {
207        let now = INSTANT.now();
208
209        // update `deadline` vars
210        self.deadlines.retain(|wk| {
211            if let Some(var) = wk.upgrade() {
212                if !timer.elapsed(var.get()) {
213                    return true; // retain
214                }
215
216                var.update();
217            }
218            false // don't retain
219        });
220
221        // update `wait_deadline` vars
222        self.wait_deadlines.retain(|wk| {
223            if let Some(e) = wk.upgrade() {
224                if !e.deadline.has_elapsed() {
225                    return true; // retain
226                }
227                for w in mem::take(&mut *e.wakers.lock()) {
228                    w.wake();
229                }
230            }
231            false // don't retain
232        });
233
234        // update `interval` vars
235        self.timers.retain(|t| {
236            if let Some(var) = t.weak_var.upgrade() {
237                if !t.handle.is_dropped() {
238                    if !t.handle.data().paused.load(Ordering::Relaxed) {
239                        var.with(|t| {
240                            let mut deadline = t.0.0.data().deadline.lock();
241
242                            if timer.elapsed(deadline.current_deadline()) {
243                                t.0.0.data().count.fetch_add(1, Ordering::Relaxed);
244                                var.update();
245
246                                deadline.last = now;
247                                timer.register(deadline.current_deadline());
248                            }
249                        })
250                    }
251
252                    return true; // retain, var is alive and did not call stop.
253                }
254            }
255            false // don't retain.
256        });
257
258        // flag `on_deadline` handlers that need to run.
259        self.deadline_handlers.retain_mut(|e| {
260            if e.handle.is_dropped() {
261                return false; // cancel
262            }
263
264            let deadline = e.handle.data().deadline;
265            e.pending = timer.elapsed(deadline);
266
267            self.has_pending_handlers |= e.pending;
268
269            true // retain if not canceled, elapsed deadlines will be dropped in [`Self::notify`].
270        });
271
272        // flag `on_interval` handlers that need to run.
273        self.timer_handlers.retain_mut(|e| {
274            if e.handle.is_dropped() {
275                return false; // stop
276            }
277
278            let state = e.handle.data();
279            if !state.paused.load(Ordering::Relaxed) {
280                let mut deadline = state.deadline.lock();
281
282                if timer.elapsed(deadline.current_deadline()) {
283                    state.count.fetch_add(1, Ordering::Relaxed);
284                    e.pending = Some(deadline.current_deadline());
285                    self.has_pending_handlers = true;
286
287                    deadline.last = now;
288                    timer.register(deadline.current_deadline());
289                }
290            }
291
292            true // retain if stop was not called
293        });
294    }
295
296    /// does on_* notifications.
297    pub(crate) fn notify() {
298        let _s = tracing::trace_span!("TIMERS").entered();
299
300        let _t = INSTANT_APP.pause_for_update();
301
302        // we need to detach the handlers, so we can pass the context for then
303        // so we `mem::take` for the duration of the call. But new timers can be registered inside
304        // the handlers, so we add those handlers using `extend`.
305
306        let mut timers = TIMERS_SV.write();
307
308        if !mem::take(&mut timers.has_pending_handlers) {
309            return;
310        }
311
312        // call `on_deadline` handlers.
313        let mut handlers = mem::take(&mut timers.deadline_handlers);
314        drop(timers);
315        handlers.retain_mut(|h| {
316            if h.pending {
317                (h.handler.get_mut())(&h.handle.weak_handle());
318                h.handle.data().executed.store(true, Ordering::Relaxed);
319            }
320            !h.pending // drop if just called, deadline handlers are *once*.
321        });
322        let mut timers = TIMERS_SV.write();
323        handlers.append(&mut timers.deadline_handlers);
324        timers.deadline_handlers = handlers;
325
326        // call `on_interval` handlers.
327        let mut handlers = mem::take(&mut timers.timer_handlers);
328        drop(timers);
329        handlers.retain_mut(|h| {
330            if let Some(deadline) = h.pending.take() {
331                let args = TimerArgs {
332                    timestamp: INSTANT.now(),
333                    deadline,
334                    wk_handle: h.handle.weak_handle(),
335                };
336                (h.handler.get_mut())(&args, &h.handle.weak_handle());
337            }
338
339            !h.handle.is_dropped() // drop if called stop inside the handler.
340        });
341        let mut timers = TIMERS_SV.write();
342        handlers.append(&mut timers.timer_handlers);
343        timers.timer_handlers = handlers;
344    }
345}
346
347/// App timers, deadlines and timeouts.
348///
349/// You can use this service to create UI bound timers, these timers run using only the app loop and awake the app
350/// to notify updates.
351///
352/// Timer updates can be observed using variables that update when the timer elapses, or you can register
353/// handlers to be called directly when the time elapses. Timers can be *one-time*, updating only once when
354/// a [`deadline`] is reached; or they can update every time on a set [`interval`].
355///
356/// Note that you can also use the [`task::deadline`](zng_task::deadline) function to `.await` deadlines, in app
357/// threads this function uses the `TIMERS` service too.
358///
359/// # Precision
360///
361/// Timers elapse at the specified time or a little later, depending on how busy the app main loop is. High frequency
362/// timers can also have an effective lower frequency of updates because timers only elapse once per frame cycle.
363///
364/// [variable]: Var
365/// [`deadline`]: TIMERS::deadline
366/// [`interval`]: TIMERS::interval
367/// [`async_app_hn!`]: crate::handler::async_app_hn!
368/// [`async_app_hn_once!`]: crate::handler::async_app_hn_once!
369pub struct TIMERS;
370impl TIMERS {
371    /// Returns a [`DeadlineVar`] that will update once when the `deadline` is reached.
372    ///
373    /// If the `deadline` is in the past the variable will still update once in the next app update.
374    /// Drop all clones of the variable to cancel the timer.
375    ///
376    /// ```
377    /// # use zng_app::timer::*;
378    /// # use zng_app::handler::*;
379    /// # use zng_layout::unit::*;
380    /// # use zng_app::var::*;
381    /// # use std::time::Instant;
382    /// # fn foo() {
383    /// let deadline = TIMERS.deadline(20.secs());
384    ///
385    /// # let
386    /// text = deadline.map(|d| if d.has_elapsed() { "20 seconds have passed" } else { "..." });
387    /// # }
388    /// ```
389    ///
390    /// In the example above the deadline variable will update 20 seconds later when the deadline [`has_elapsed`]. The variable
391    /// is read-only and will only update once.
392    ///
393    /// [`has_elapsed`]: Deadline::has_elapsed
394    #[must_use]
395    pub fn deadline(&self, deadline: impl Into<Deadline>) -> DeadlineVar {
396        TIMERS_SV.write().deadline(deadline.into())
397    }
398
399    /// Returns a [`TimerVar`] that will update every time the `interval` elapses.
400    ///
401    /// The timer can be controlled using methods in the variable value. The timer starts
402    /// running immediately if `paused` is `false`.
403    ///
404    /// ```
405    /// # use zng_app::timer::*;
406    /// # use zng_app::handler::*;
407    /// # use zng_layout::unit::*;
408    /// # use zng_app::var::*;
409    /// # use zng_txt::*;
410    /// # use std::time::Instant;
411    /// # fn foo() {
412    /// let timer = TIMERS.interval(1.secs(), false);
413    ///
414    /// # let
415    /// text = timer.map(|t| match t.count() {
416    ///     0 => formatx!(""),
417    ///     1 => formatx!("1 second elapsed"),
418    ///     c => formatx!("{c} seconds elapsed")
419    /// });
420    /// # }
421    /// ```
422    ///
423    /// In the example above the timer variable will update every second, the variable keeps a [`count`](Timer::count)
424    /// of times the time elapsed, that is incremented every update. The variable is read-only but the value can
425    /// be used to control the timer to some extent, see [`TimerVar`] for details.
426    #[must_use]
427    pub fn interval(&self, interval: Duration, paused: bool) -> TimerVar {
428        TIMERS_SV.write().interval(interval, paused)
429    }
430
431    /// Register a `handler` that will be called once when the `deadline` is reached.
432    ///
433    /// If the `deadline` is in the past the `handler` will be called in the next app update.
434    ///
435    /// ```
436    /// # use zng_app::timer::*;
437    /// # use zng_app::handler::*;
438    /// # use zng_layout::unit::*;
439    /// # use std::time::Instant;
440    /// # fn foo() {
441    /// let handle = TIMERS.on_deadline(20.secs(), app_hn_once!(|_| {
442    ///     println!("20 seconds have passed");
443    /// }));
444    /// # }
445    /// ```
446    ///
447    /// # Handler
448    ///
449    /// The `handler` can be any of the *once* [`AppHandler`] implementers. You can use the macros
450    /// [`app_hn_once!`](crate::handler::app_hn_once!) or [`async_hn_once!`](crate::handler::async_app_hn_once!)
451    /// to declare a handler closure.
452    ///
453    /// Async handlers execute up to the first `.await` immediately when the `deadline` is reached, subsequent awakes
454    /// are scheduled like an async *preview* event handler.
455    ///
456    /// # Handle
457    ///
458    /// Returns a [`DeadlineHandle`] that can be used to cancel the timer, either by dropping the handle or by
459    /// calling [`cancel`](DeadlineHandle::cancel). You can also call [`perm`](DeadlineHandle::perm)
460    /// to drop the handle without cancelling.
461    pub fn on_deadline<H>(&self, deadline: impl Into<Deadline>, handler: H) -> DeadlineHandle
462    where
463        H: AppHandler<DeadlineArgs>,
464    {
465        TIMERS_SV.write().on_deadline(deadline.into(), handler)
466    }
467
468    /// Register a `handler` that will be called every time the `interval` elapses.
469    ///
470    /// The timer starts running immediately if `paused` is `false`.
471    pub fn on_interval<H>(&self, interval: Duration, paused: bool, handler: H) -> TimerHandle
472    where
473        H: AppHandler<TimerArgs>,
474    {
475        TIMERS_SV.write().on_interval(interval, paused, handler)
476    }
477}
478
479impl TIMERS {
480    /// Implementation of the [`task::deadline`] function when called from app threads.
481    ///
482    /// [`task::deadline`]: zng_task::deadline
483    pub fn wait_deadline(&self, deadline: impl Into<Deadline>) -> impl Future<Output = ()> + Send + Sync + 'static {
484        TIMERS_SV.write().wait_deadline(deadline.into())
485    }
486}
487
488/// A [`deadline`](TIMERS::deadline) timer.
489///
490/// This is a read-only variable of type [`Deadline`], it will update once when the timer elapses.
491///
492/// Drop all clones of this variable to cancel the timer.
493///
494/// ```
495/// # use zng_app::timer::*;
496/// # use zng_app::handler::*;
497/// # use zng_layout::unit::*;
498/// # use zng_app::var::*;
499/// # use std::time::Instant;
500/// # fn foo() {
501/// let deadline: DeadlineVar = TIMERS.deadline(20.secs());
502///
503/// # let
504/// text = deadline.map(|d| if d.has_elapsed() { "20 seconds have passed" } else { "..." });
505/// # }
506/// ```
507///
508/// In the example above the variable is mapped to a text, there are many other things you can do with variables,
509/// including `.await` for the update in UI bound async tasks. See [`Var<T>`] for details.
510///
511/// [`Var<T>`]: zng_var::Var
512pub type DeadlineVar = ReadOnlyArcVar<Deadline>;
513
514/// Represents a [`on_deadline`](TIMERS::on_deadline) handler.
515///
516/// Drop all clones of this handle to cancel the timer, or call [`perm`](Self::perm) to drop the handle
517/// without cancelling the timer.
518#[derive(Clone, PartialEq, Eq, Hash)]
519#[repr(transparent)]
520#[must_use = "the timer is canceled if the handler is dropped"]
521pub struct DeadlineHandle(Handle<DeadlineState>);
522struct DeadlineState {
523    deadline: Deadline,
524    executed: AtomicBool,
525}
526impl DeadlineHandle {
527    /// Create a handle to nothing, the handle always in the *canceled* state.
528    ///
529    /// Note that `Option<DeadlineHandle>` takes up the same space as `DeadlineHandle` and avoids an allocation.
530    pub fn dummy() -> DeadlineHandle {
531        DeadlineHandle(Handle::dummy(DeadlineState {
532            deadline: Deadline(DInstant::EPOCH),
533            executed: AtomicBool::new(false),
534        }))
535    }
536
537    fn new(deadline: Deadline) -> (HandleOwner<DeadlineState>, Self) {
538        let (owner, handle) = Handle::new(DeadlineState {
539            deadline,
540            executed: AtomicBool::new(false),
541        });
542        (owner, DeadlineHandle(handle))
543    }
544
545    /// Drops the handle but does **not** drop the handler closure.
546    ///
547    /// The handler closure will be dropped after it is executed or when the app exits.
548    pub fn perm(self) {
549        self.0.perm();
550    }
551
552    /// If [`perm`](Self::perm) was called in another handle.
553    ///
554    /// If `true` the closure will be dropped when it executes, when the app exits or if [`cancel`](Self::cancel) is called.
555    pub fn is_permanent(&self) -> bool {
556        self.0.is_permanent()
557    }
558
559    /// Drops the handle and forces the handler to drop.
560    ///
561    /// If the deadline has not been reached the handler will not be called, and will drop in the next app update.
562    pub fn cancel(self) {
563        self.0.force_drop();
564    }
565
566    /// The timeout deadline.
567    ///
568    /// The handler is called once when this deadline is reached.
569    pub fn deadline(&self) -> Deadline {
570        self.0.data().deadline
571    }
572
573    /// If the handler has executed. The handler executes once when the deadline is reached.
574    pub fn has_executed(&self) -> bool {
575        self.0.data().executed.load(Ordering::Relaxed)
576    }
577
578    /// If the timeout handler will never execute. Returns `true` if [`cancel`](Self::cancel) was called
579    /// before the handler could execute.
580    pub fn is_canceled(&self) -> bool {
581        !self.has_executed() && self.0.is_dropped()
582    }
583
584    /// Create a weak handle to the deadline.
585    pub fn downgrade(&self) -> WeakDeadlineHandle {
586        WeakDeadlineHandle(self.0.downgrade())
587    }
588}
589impl fmt::Debug for DeadlineHandle {
590    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591        f.debug_struct("DeadlineHandle")
592            .field("deadline", &self.deadline())
593            .field("handle", &self.0)
594            .field(
595                "state",
596                &if self.has_executed() {
597                    "has_executed"
598                } else if self.is_canceled() {
599                    "is_canceled"
600                } else {
601                    "awaiting"
602                },
603            )
604            .finish()
605    }
606}
607
608/// Weak [`DeadlineHandle`]
609#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
610pub struct WeakDeadlineHandle(WeakHandle<DeadlineState>);
611impl WeakDeadlineHandle {
612    /// New weak handle that does not upgrade.
613    pub fn new() -> Self {
614        Self(WeakHandle::new())
615    }
616
617    /// Get the strong handle is still waiting the deadline.
618    pub fn upgrade(&self) -> Option<DeadlineHandle> {
619        self.0.upgrade().map(DeadlineHandle)
620    }
621}
622
623/// Arguments for the handler of [`on_deadline`](TIMERS::on_deadline).
624#[derive(Clone, Debug)]
625#[non_exhaustive]
626pub struct DeadlineArgs {
627    /// When the handler was called.
628    pub timestamp: DInstant,
629    /// Timer deadline, is less-or-equal to the [`timestamp`](Self::timestamp).
630    pub deadline: Deadline,
631}
632
633/// Represents a [`on_interval`](TIMERS::on_interval) handler.
634///
635/// Drop all clones of this handler to stop the timer, or call [`perm`](Self::perm) to drop the handler
636/// without cancelling the timer.
637#[derive(Clone, PartialEq, Eq, Hash)]
638#[repr(transparent)]
639#[must_use = "the timer is stopped if the handler is dropped"]
640pub struct TimerHandle(Handle<TimerState>);
641struct TimerState {
642    paused: AtomicBool,
643    deadline: Mutex<TimerDeadline>,
644    count: AtomicUsize,
645}
646struct TimerDeadline {
647    interval: Duration,
648    last: DInstant,
649}
650impl TimerDeadline {
651    fn current_deadline(&self) -> Deadline {
652        Deadline(self.last + self.interval)
653    }
654}
655impl TimerHandle {
656    fn new(interval: Duration, paused: bool) -> (HandleOwner<TimerState>, TimerHandle) {
657        let (owner, handle) = Handle::new(TimerState {
658            paused: AtomicBool::new(paused),
659            deadline: Mutex::new(TimerDeadline {
660                interval,
661                last: INSTANT.now(),
662            }),
663            count: AtomicUsize::new(0),
664        });
665        (owner, TimerHandle(handle))
666    }
667
668    /// Create a handle to nothing, the handle is always in the *stopped* state.
669    ///
670    /// Note that `Option<TimerHandle>` takes up the same space as `TimerHandle` and avoids an allocation.
671    pub fn dummy() -> TimerHandle {
672        TimerHandle(Handle::dummy(TimerState {
673            paused: AtomicBool::new(true),
674            deadline: Mutex::new(TimerDeadline {
675                interval: Duration::MAX,
676                last: DInstant::EPOCH,
677            }),
678            count: AtomicUsize::new(0),
679        }))
680    }
681
682    /// Drops the handle but does **not** drop the handler closure.
683    ///
684    /// The handler closure will be dropped when the app exits or if it is stopped from the inside or using another handle.
685    pub fn perm(self) {
686        self.0.perm();
687    }
688
689    /// If [`perm`](Self::perm) was called in another handle.
690    ///
691    /// If `true` the closure will keep being called until the app exits or the timer is stopped from the inside or using
692    /// another handle.
693    pub fn is_permanent(&self) -> bool {
694        self.0.is_permanent()
695    }
696
697    /// Drops the handle and forces the handler to drop.
698    ///
699    /// The handler will no longer be called and will drop in the next app update.
700    pub fn stop(self) {
701        self.0.force_drop();
702    }
703
704    /// If the timer was stopped. The timer can be stopped from the inside, from another handle calling [`stop`](Self::stop)
705    /// or from the app shutting down.
706    pub fn is_stopped(&self) -> bool {
707        self.0.is_dropped()
708    }
709
710    /// The timer interval. Enabled handlers are called every time this interval elapses.
711    pub fn interval(&self) -> Duration {
712        self.0.data().deadline.lock().interval
713    }
714
715    /// Sets the [`interval`](Self::interval).
716    ///
717    /// Note that this method does not awake the app, so if this is called from outside the app
718    /// thread it will only apply on the next app update.
719    pub fn set_interval(&self, new_interval: Duration) {
720        self.0.data().deadline.lock().interval = new_interval;
721    }
722
723    /// Last elapsed time, or the start time if the timer has not elapsed yet.
724    pub fn timestamp(&self) -> DInstant {
725        self.0.data().deadline.lock().last
726    }
727
728    /// The next deadline.
729    ///
730    /// This is the [`timestamp`](Self::timestamp) plus the [`interval`](Self::interval).
731    pub fn deadline(&self) -> Deadline {
732        self.0.data().deadline.lock().current_deadline()
733    }
734
735    /// If the timer is not ticking, but can be started again.
736    pub fn is_paused(&self) -> bool {
737        self.0.data().paused.load(Ordering::Relaxed)
738    }
739
740    /// Disable the timer, this causes the timer to stop ticking until [`play`] is called.
741    ///
742    /// [`play`]: Self::play
743    pub fn pause(&self) {
744        self.0.data().paused.store(true, Ordering::Relaxed);
745    }
746
747    /// If the timer is ticking.
748    pub fn is_playing(&self) -> bool {
749        !self.is_paused() && !self.is_stopped()
750    }
751
752    /// Enable the timer, this causes it to start ticking again.
753    ///
754    /// If `reset` is `true` the last [`timestamp`] is set to now.
755    ///
756    /// Note that this method does not wake the app, so if this is called from outside the app
757    /// the timer will only start ticking in next app update.
758    ///
759    /// [`timestamp`]: Self::timestamp
760    pub fn play(&self, reset: bool) {
761        self.0.data().paused.store(false, Ordering::Relaxed);
762        if reset {
763            self.0.data().deadline.lock().last = INSTANT.now();
764        }
765    }
766
767    /// Count incremented by one every time the timer elapses.
768    pub fn count(&self) -> usize {
769        self.0.data().count.load(Ordering::Relaxed)
770    }
771
772    /// Resets the [`count`](Self::count).
773    pub fn set_count(&self, count: usize) {
774        self.0.data().count.store(count, Ordering::Relaxed)
775    }
776
777    /// Create a weak handle to the timer.
778    pub fn downgrade(&self) -> WeakTimerHandle {
779        WeakTimerHandle(self.0.downgrade())
780    }
781}
782impl fmt::Debug for TimerHandle {
783    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
784        f.debug_struct("TimerHandle")
785            .field("interval", &self.interval())
786            .field("count", &self.count())
787            .field("timestamp", &self.timestamp())
788            .field("handle", &self.0)
789            .field(
790                "state",
791                &if self.is_stopped() {
792                    "is_stopped"
793                } else if self.is_paused() {
794                    "is_paused"
795                } else {
796                    "playing"
797                },
798            )
799            .finish()
800    }
801}
802
803/// Weak [`TimerHandle`].
804#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
805pub struct WeakTimerHandle(WeakHandle<TimerState>);
806impl WeakTimerHandle {
807    /// New weak handle that does not upgrade.
808    pub fn new() -> Self {
809        Self(WeakHandle::new())
810    }
811
812    /// Get the strong handle if the timer has not stopped.
813    pub fn upgrade(&self) -> Option<TimerHandle> {
814        self.0.upgrade().map(TimerHandle)
815    }
816}
817
818/// An [`interval`](TIMERS::interval) timer.
819///
820/// This is a variable of type [`Timer`], it will update every time the timer elapses.
821///
822/// Drop all clones of this variable to stop the timer, you can also control the timer
823/// with methods in the [`Timer`] value even though the variable is read-only.
824///
825/// ```
826/// # use zng_app::timer::*;
827/// # use zng_app::handler::*;
828/// # use zng_app::var::*;
829/// # use zng_txt::*;
830/// # use zng_layout::unit::*;
831/// # use std::time::Instant;
832/// # fn foo() {
833/// let timer: TimerVar = TIMERS.interval(1.secs(), false);
834///
835/// # let
836/// text = timer.map(|d| match 20 - d.count() {
837///     0 => {
838///         d.stop();
839///         formatx!("Done!")
840///     },
841///     1 => formatx!("1 second left"),
842///     s => formatx!("{s} seconds left")
843/// });
844/// # }
845/// ```
846///
847/// In the example above the variable updates every second and stops after 20 seconds have elapsed. The variable
848/// is mapped to a text and controls the timer from inside the mapping closure. See [`Var<T>`] for other things you
849/// can do with variables, including `.await` for updates. Also see [`Timer`] for more timer control methods.
850///
851/// [`Var<T>`]: zng_var::Var
852pub type TimerVar = ReadOnlyArcVar<Timer>;
853
854/// Represents a timer state in a [`TimerVar`] or interval handler.
855///
856/// This type uses interior mutability to communicate with the timer, the values provided by the methods
857/// can be changed anytime by the [`TimerVar`] owners without the variable updating.
858#[derive(Clone, PartialEq)]
859pub struct Timer(TimerHandle);
860impl fmt::Debug for Timer {
861    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
862        f.debug_struct("Timer")
863            .field("interval", &self.interval())
864            .field("count", &self.count())
865            .field("is_paused", &self.is_paused())
866            .field("is_stopped", &self.is_stopped())
867            .finish_non_exhaustive()
868    }
869}
870impl Timer {
871    /// Permanently stops the timer.
872    pub fn stop(&self) {
873        self.0.clone().stop();
874    }
875
876    /// If the timer was stopped.
877    ///
878    /// If `true` the timer var will not update again, this is permanent.
879    pub fn is_stopped(&self) -> bool {
880        self.0.is_stopped()
881    }
882
883    /// The timer interval. Enabled variables update every time this interval elapses.
884    pub fn interval(&self) -> Duration {
885        self.0.interval()
886    }
887
888    /// Sets the [`interval`](Self::interval).
889    ///
890    /// Note that this method does not awake the app, so if this is called from outside the app
891    /// thread it will only apply on the next app update.
892    pub fn set_interval(&self, new_interval: Duration) {
893        self.0.set_interval(new_interval)
894    }
895
896    /// Last update time, or the start time if the timer has not updated yet.
897    pub fn timestamp(&self) -> DInstant {
898        self.0.timestamp()
899    }
900
901    /// The next deadline.
902    ///
903    /// This is the [`timestamp`](Self::timestamp) plus the [`interval`](Self::interval).
904    pub fn deadline(&self) -> Deadline {
905        self.0.deadline()
906    }
907
908    /// If the timer is not ticking, but can be started again.
909    pub fn is_paused(&self) -> bool {
910        self.0.is_paused()
911    }
912
913    /// If the timer is ticking.
914    pub fn is_playing(&self) -> bool {
915        self.0.is_playing()
916    }
917
918    /// Disable the timer, this causes the timer to stop ticking until [`play`] is called.
919    ///
920    /// [`play`]: Self::play
921    pub fn pause(&self) {
922        self.0.pause();
923    }
924
925    /// Enable the timer, this causes it to start ticking again.
926    ///
927    /// If `reset` is `true` the last [`timestamp`] is set to now.
928    ///
929    /// [`timestamp`]: Self::timestamp
930    pub fn play(&self, reset: bool) {
931        self.0.play(reset);
932    }
933
934    /// Count incremented by one every time the timer elapses.
935    pub fn count(&self) -> usize {
936        self.0.count()
937    }
938
939    /// Resets the [`count`](Self::count).
940    pub fn set_count(&self, count: usize) {
941        self.0.set_count(count)
942    }
943}
944
945/// Arguments for an [`on_interval`](TIMERS::on_interval) handler.
946///
947/// Note the timer can be stopped using the handlers [`unsubscribe`](crate::handler::AppWeakHandle::unsubscribe),
948/// and *once* handlers stop the timer automatically.
949///
950/// The field values are about the specific call to handler that received the args, the methods on the other hand
951/// are **connected** with the timer by a weak reference and always show the up-to-date state of the timer.
952/// For synchronous handlers this does not matter, but for async handlers this means that the values can be
953/// different after each `.await`. This can be useful to for example, disable the timer until the async task finishes
954/// but it can also be surprising.
955#[derive(Clone)]
956pub struct TimerArgs {
957    /// When the handler was called.
958    pub timestamp: DInstant,
959
960    /// Expected deadline, is less-or-equal to the [`timestamp`](Self::timestamp).
961    pub deadline: Deadline,
962
963    wk_handle: WeakHandle<TimerState>,
964}
965
966impl TimerArgs {
967    fn handle(&self) -> Option<TimerHandle> {
968        self.wk_handle.upgrade().map(TimerHandle)
969    }
970
971    /// The timer interval. Enabled handlers are called every time this interval elapses.
972    pub fn interval(&self) -> Duration {
973        self.handle().map(|h| h.interval()).unwrap_or_default()
974    }
975
976    /// Set the [`interval`](Self::interval).
977    ///
978    /// Note that this method does not awake the app, so if this is called from outside the app
979    /// thread it will only apply on the next app update.
980    pub fn set_interval(&self, new_interval: Duration) {
981        if let Some(h) = self.handle() {
982            h.set_interval(new_interval)
983        }
984    }
985
986    /// If the timer is not ticking, but can be started again.
987    pub fn is_paused(&self) -> bool {
988        self.handle().map(|h| h.is_paused()).unwrap_or(true)
989    }
990
991    /// If the timer is ticking.
992    pub fn is_playing(&self) -> bool {
993        self.handle().map(|h| h.is_playing()).unwrap_or(false)
994    }
995
996    /// Disable the timer, this causes the timer to stop ticking until [`play`] is called.
997    ///
998    /// [`play`]: Self::play
999    pub fn pause(&self) {
1000        if let Some(h) = self.handle() {
1001            h.pause();
1002        }
1003    }
1004
1005    /// Enable the timer, this causes it to start ticking again.
1006    ///
1007    /// If `reset` is `true` the last [`timestamp`] is set to now.
1008    ///
1009    /// [`timestamp`]: Self::timestamp
1010    pub fn play(&self, reset: bool) {
1011        if let Some(h) = self.handle() {
1012            h.play(reset);
1013        }
1014    }
1015
1016    /// Count incremented by one every time the timer elapses.
1017    pub fn count(&self) -> usize {
1018        self.handle().map(|h| h.count()).unwrap_or(0)
1019    }
1020
1021    /// Resets the [`count`](Self::count).
1022    pub fn set_count(&self, count: usize) {
1023        if let Some(h) = self.handle() {
1024            h.set_count(count)
1025        }
1026    }
1027
1028    /// The timestamp of the last update. This can be different from [`timestamp`](Self::timestamp)
1029    /// after the first `.await` in async handlers of if called from a different thread.
1030    pub fn last_timestamp(&self) -> DInstant {
1031        self.handle().map(|h| h.timestamp()).unwrap_or(self.timestamp)
1032    }
1033
1034    /// The next timer deadline.
1035    ///
1036    /// This is [`last_timestamp`](Self::last_timestamp) plus [`interval`](Self::interval).
1037    pub fn next_deadline(&self) -> Deadline {
1038        self.handle().map(|h| h.deadline()).unwrap_or(self.deadline)
1039    }
1040
1041    /// If the timer was stopped while the handler was running after it started handling.
1042    ///
1043    /// Note the timer can be stopped from the inside of the handler using the handlers
1044    /// [`unsubscribe`], and once handlers stop the timer automatically.
1045    ///
1046    /// Outside of the handler the [`TimerHandle`] can be used to stop the timer at any time, even from another thread.
1047    ///
1048    /// [`unsubscribe`]: crate::handler::AppWeakHandle::unsubscribe
1049    pub fn is_stopped(&self) -> bool {
1050        self.handle().is_none()
1051    }
1052}
1053
1054pub(crate) fn deadline_service(deadline: Deadline) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>> {
1055    Box::pin(TIMERS.wait_deadline(deadline))
1056}