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