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)]
625pub struct DeadlineArgs {
626 /// When the handler was called.
627 pub timestamp: DInstant,
628 /// Timer deadline, is less-or-equal to the [`timestamp`](Self::timestamp).
629 pub deadline: Deadline,
630}
631
632/// Represents a [`on_interval`](TIMERS::on_interval) handler.
633///
634/// Drop all clones of this handler to stop the timer, or call [`perm`](Self::perm) to drop the handler
635/// without cancelling the timer.
636#[derive(Clone, PartialEq, Eq, Hash)]
637#[repr(transparent)]
638#[must_use = "the timer is stopped if the handler is dropped"]
639pub struct TimerHandle(Handle<TimerState>);
640struct TimerState {
641 paused: AtomicBool,
642 deadline: Mutex<TimerDeadline>,
643 count: AtomicUsize,
644}
645struct TimerDeadline {
646 interval: Duration,
647 last: DInstant,
648}
649impl TimerDeadline {
650 fn current_deadline(&self) -> Deadline {
651 Deadline(self.last + self.interval)
652 }
653}
654impl TimerHandle {
655 fn new(interval: Duration, paused: bool) -> (HandleOwner<TimerState>, TimerHandle) {
656 let (owner, handle) = Handle::new(TimerState {
657 paused: AtomicBool::new(paused),
658 deadline: Mutex::new(TimerDeadline {
659 interval,
660 last: INSTANT.now(),
661 }),
662 count: AtomicUsize::new(0),
663 });
664 (owner, TimerHandle(handle))
665 }
666
667 /// Create a handle to nothing, the handle is always in the *stopped* state.
668 ///
669 /// Note that `Option<TimerHandle>` takes up the same space as `TimerHandle` and avoids an allocation.
670 pub fn dummy() -> TimerHandle {
671 TimerHandle(Handle::dummy(TimerState {
672 paused: AtomicBool::new(true),
673 deadline: Mutex::new(TimerDeadline {
674 interval: Duration::MAX,
675 last: DInstant::EPOCH,
676 }),
677 count: AtomicUsize::new(0),
678 }))
679 }
680
681 /// Drops the handle but does **not** drop the handler closure.
682 ///
683 /// The handler closure will be dropped when the app exits or if it is stopped from the inside or using another handle.
684 pub fn perm(self) {
685 self.0.perm();
686 }
687
688 /// If [`perm`](Self::perm) was called in another handle.
689 ///
690 /// If `true` the closure will keep being called until the app exits or the timer is stopped from the inside or using
691 /// another handle.
692 pub fn is_permanent(&self) -> bool {
693 self.0.is_permanent()
694 }
695
696 /// Drops the handle and forces the handler to drop.
697 ///
698 /// The handler will no longer be called and will drop in the next app update.
699 pub fn stop(self) {
700 self.0.force_drop();
701 }
702
703 /// If the timer was stopped. The timer can be stopped from the inside, from another handle calling [`stop`](Self::stop)
704 /// or from the app shutting down.
705 pub fn is_stopped(&self) -> bool {
706 self.0.is_dropped()
707 }
708
709 /// The timer interval. Enabled handlers are called every time this interval elapses.
710 pub fn interval(&self) -> Duration {
711 self.0.data().deadline.lock().interval
712 }
713
714 /// Sets the [`interval`](Self::interval).
715 ///
716 /// Note that this method does not awake the app, so if this is called from outside the app
717 /// thread it will only apply on the next app update.
718 pub fn set_interval(&self, new_interval: Duration) {
719 self.0.data().deadline.lock().interval = new_interval;
720 }
721
722 /// Last elapsed time, or the start time if the timer has not elapsed yet.
723 pub fn timestamp(&self) -> DInstant {
724 self.0.data().deadline.lock().last
725 }
726
727 /// The next deadline.
728 ///
729 /// This is the [`timestamp`](Self::timestamp) plus the [`interval`](Self::interval).
730 pub fn deadline(&self) -> Deadline {
731 self.0.data().deadline.lock().current_deadline()
732 }
733
734 /// If the timer is not ticking, but can be started again.
735 pub fn is_paused(&self) -> bool {
736 self.0.data().paused.load(Ordering::Relaxed)
737 }
738
739 /// Disable the timer, this causes the timer to stop ticking until [`play`] is called.
740 ///
741 /// [`play`]: Self::play
742 pub fn pause(&self) {
743 self.0.data().paused.store(true, Ordering::Relaxed);
744 }
745
746 /// If the timer is ticking.
747 pub fn is_playing(&self) -> bool {
748 !self.is_paused() && !self.is_stopped()
749 }
750
751 /// Enable the timer, this causes it to start ticking again.
752 ///
753 /// If `reset` is `true` the last [`timestamp`] is set to now.
754 ///
755 /// Note that this method does not wake the app, so if this is called from outside the app
756 /// the timer will only start ticking in next app update.
757 ///
758 /// [`timestamp`]: Self::timestamp
759 pub fn play(&self, reset: bool) {
760 self.0.data().paused.store(false, Ordering::Relaxed);
761 if reset {
762 self.0.data().deadline.lock().last = INSTANT.now();
763 }
764 }
765
766 /// Count incremented by one every time the timer elapses.
767 pub fn count(&self) -> usize {
768 self.0.data().count.load(Ordering::Relaxed)
769 }
770
771 /// Resets the [`count`](Self::count).
772 pub fn set_count(&self, count: usize) {
773 self.0.data().count.store(count, Ordering::Relaxed)
774 }
775
776 /// Create a weak handle to the timer.
777 pub fn downgrade(&self) -> WeakTimerHandle {
778 WeakTimerHandle(self.0.downgrade())
779 }
780}
781impl fmt::Debug for TimerHandle {
782 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
783 f.debug_struct("TimerHandle")
784 .field("interval", &self.interval())
785 .field("count", &self.count())
786 .field("timestamp", &self.timestamp())
787 .field("handle", &self.0)
788 .field(
789 "state",
790 &if self.is_stopped() {
791 "is_stopped"
792 } else if self.is_paused() {
793 "is_paused"
794 } else {
795 "playing"
796 },
797 )
798 .finish()
799 }
800}
801
802/// Weak [`TimerHandle`].
803#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
804pub struct WeakTimerHandle(WeakHandle<TimerState>);
805impl WeakTimerHandle {
806 /// New weak handle that does not upgrade.
807 pub fn new() -> Self {
808 Self(WeakHandle::new())
809 }
810
811 /// Get the strong handle if the timer has not stopped.
812 pub fn upgrade(&self) -> Option<TimerHandle> {
813 self.0.upgrade().map(TimerHandle)
814 }
815}
816
817/// An [`interval`](TIMERS::interval) timer.
818///
819/// This is a variable of type [`Timer`], it will update every time the timer elapses.
820///
821/// Drop all clones of this variable to stop the timer, you can also control the timer
822/// with methods in the [`Timer`] value even though the variable is read-only.
823///
824/// ```
825/// # use zng_app::timer::*;
826/// # use zng_app::handler::*;
827/// # use zng_app::var::*;
828/// # use zng_txt::*;
829/// # use zng_layout::unit::*;
830/// # use std::time::Instant;
831/// # fn foo() {
832/// let timer: TimerVar = TIMERS.interval(1.secs(), false);
833///
834/// # let
835/// text = timer.map(|d| match 20 - d.count() {
836/// 0 => {
837/// d.stop();
838/// formatx!("Done!")
839/// },
840/// 1 => formatx!("1 second left"),
841/// s => formatx!("{s} seconds left")
842/// });
843/// # }
844/// ```
845///
846/// In the example above the variable updates every second and stops after 20 seconds have elapsed. The variable
847/// is mapped to a text and controls the timer from inside the mapping closure. See [`Var<T>`] for other things you
848/// can do with variables, including `.await` for updates. Also see [`Timer`] for more timer control methods.
849///
850/// [`Var<T>`]: zng_var::Var
851pub type TimerVar = ReadOnlyArcVar<Timer>;
852
853/// Represents a timer state in a [`TimerVar`] or interval handler.
854///
855/// This type uses interior mutability to communicate with the timer, the values provided by the methods
856/// can be changed anytime by the [`TimerVar`] owners without the variable updating.
857#[derive(Clone, PartialEq)]
858pub struct Timer(TimerHandle);
859impl fmt::Debug for Timer {
860 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
861 f.debug_struct("Timer")
862 .field("interval", &self.interval())
863 .field("count", &self.count())
864 .field("is_paused", &self.is_paused())
865 .field("is_stopped", &self.is_stopped())
866 .finish_non_exhaustive()
867 }
868}
869impl Timer {
870 /// Permanently stops the timer.
871 pub fn stop(&self) {
872 self.0.clone().stop();
873 }
874
875 /// If the timer was stopped.
876 ///
877 /// If `true` the timer var will not update again, this is permanent.
878 pub fn is_stopped(&self) -> bool {
879 self.0.is_stopped()
880 }
881
882 /// The timer interval. Enabled variables update every time this interval elapses.
883 pub fn interval(&self) -> Duration {
884 self.0.interval()
885 }
886
887 /// Sets the [`interval`](Self::interval).
888 ///
889 /// Note that this method does not awake the app, so if this is called from outside the app
890 /// thread it will only apply on the next app update.
891 pub fn set_interval(&self, new_interval: Duration) {
892 self.0.set_interval(new_interval)
893 }
894
895 /// Last update time, or the start time if the timer has not updated yet.
896 pub fn timestamp(&self) -> DInstant {
897 self.0.timestamp()
898 }
899
900 /// The next deadline.
901 ///
902 /// This is the [`timestamp`](Self::timestamp) plus the [`interval`](Self::interval).
903 pub fn deadline(&self) -> Deadline {
904 self.0.deadline()
905 }
906
907 /// If the timer is not ticking, but can be started again.
908 pub fn is_paused(&self) -> bool {
909 self.0.is_paused()
910 }
911
912 /// If the timer is ticking.
913 pub fn is_playing(&self) -> bool {
914 self.0.is_playing()
915 }
916
917 /// Disable the timer, this causes the timer to stop ticking until [`play`] is called.
918 ///
919 /// [`play`]: Self::play
920 pub fn pause(&self) {
921 self.0.pause();
922 }
923
924 /// Enable the timer, this causes it to start ticking again.
925 ///
926 /// If `reset` is `true` the last [`timestamp`] is set to now.
927 ///
928 /// [`timestamp`]: Self::timestamp
929 pub fn play(&self, reset: bool) {
930 self.0.play(reset);
931 }
932
933 /// Count incremented by one every time the timer elapses.
934 pub fn count(&self) -> usize {
935 self.0.count()
936 }
937
938 /// Resets the [`count`](Self::count).
939 pub fn set_count(&self, count: usize) {
940 self.0.set_count(count)
941 }
942}
943
944/// Arguments for an [`on_interval`](TIMERS::on_interval) handler.
945///
946/// Note the timer can be stopped using the handlers [`unsubscribe`](crate::handler::AppWeakHandle::unsubscribe),
947/// and *once* handlers stop the timer automatically.
948///
949/// The field values are about the specific call to handler that received the args, the methods on the other hand
950/// are **connected** with the timer by a weak reference and always show the up-to-date state of the timer.
951/// For synchronous handlers this does not matter, but for async handlers this means that the values can be
952/// different after each `.await`. This can be useful to for example, disable the timer until the async task finishes
953/// but it can also be surprising.
954#[derive(Clone)]
955pub struct TimerArgs {
956 /// When the handler was called.
957 pub timestamp: DInstant,
958
959 /// Expected deadline, is less-or-equal to the [`timestamp`](Self::timestamp).
960 pub deadline: Deadline,
961
962 wk_handle: WeakHandle<TimerState>,
963}
964
965impl TimerArgs {
966 fn handle(&self) -> Option<TimerHandle> {
967 self.wk_handle.upgrade().map(TimerHandle)
968 }
969
970 /// The timer interval. Enabled handlers are called every time this interval elapses.
971 pub fn interval(&self) -> Duration {
972 self.handle().map(|h| h.interval()).unwrap_or_default()
973 }
974
975 /// Set the [`interval`](Self::interval).
976 ///
977 /// Note that this method does not awake the app, so if this is called from outside the app
978 /// thread it will only apply on the next app update.
979 pub fn set_interval(&self, new_interval: Duration) {
980 if let Some(h) = self.handle() {
981 h.set_interval(new_interval)
982 }
983 }
984
985 /// If the timer is not ticking, but can be started again.
986 pub fn is_paused(&self) -> bool {
987 self.handle().map(|h| h.is_paused()).unwrap_or(true)
988 }
989
990 /// If the timer is ticking.
991 pub fn is_playing(&self) -> bool {
992 self.handle().map(|h| h.is_playing()).unwrap_or(false)
993 }
994
995 /// Disable the timer, this causes the timer to stop ticking until [`play`] is called.
996 ///
997 /// [`play`]: Self::play
998 pub fn pause(&self) {
999 if let Some(h) = self.handle() {
1000 h.pause();
1001 }
1002 }
1003
1004 /// Enable the timer, this causes it to start ticking again.
1005 ///
1006 /// If `reset` is `true` the last [`timestamp`] is set to now.
1007 ///
1008 /// [`timestamp`]: Self::timestamp
1009 pub fn play(&self, reset: bool) {
1010 if let Some(h) = self.handle() {
1011 h.play(reset);
1012 }
1013 }
1014
1015 /// Count incremented by one every time the timer elapses.
1016 pub fn count(&self) -> usize {
1017 self.handle().map(|h| h.count()).unwrap_or(0)
1018 }
1019
1020 /// Resets the [`count`](Self::count).
1021 pub fn set_count(&self, count: usize) {
1022 if let Some(h) = self.handle() {
1023 h.set_count(count)
1024 }
1025 }
1026
1027 /// The timestamp of the last update. This can be different from [`timestamp`](Self::timestamp)
1028 /// after the first `.await` in async handlers of if called from a different thread.
1029 pub fn last_timestamp(&self) -> DInstant {
1030 self.handle().map(|h| h.timestamp()).unwrap_or(self.timestamp)
1031 }
1032
1033 /// The next timer deadline.
1034 ///
1035 /// This is [`last_timestamp`](Self::last_timestamp) plus [`interval`](Self::interval).
1036 pub fn next_deadline(&self) -> Deadline {
1037 self.handle().map(|h| h.deadline()).unwrap_or(self.deadline)
1038 }
1039
1040 /// If the timer was stopped while the handler was running after it started handling.
1041 ///
1042 /// Note the timer can be stopped from the inside of the handler using the handlers
1043 /// [`unsubscribe`], and once handlers stop the timer automatically.
1044 ///
1045 /// Outside of the handler the [`TimerHandle`] can be used to stop the timer at any time, even from another thread.
1046 ///
1047 /// [`unsubscribe`]: crate::handler::AppWeakHandle::unsubscribe
1048 pub fn is_stopped(&self) -> bool {
1049 self.handle().is_none()
1050 }
1051}
1052
1053pub(crate) fn deadline_service(deadline: Deadline) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>> {
1054 Box::pin(TIMERS.wait_deadline(deadline))
1055}