yew_stdweb/services/
interval.rs

1//! This module contains the implementation of a service for
2//! periodic sending messages to a loop.
3
4use super::Task;
5use crate::callback::Callback;
6use cfg_if::cfg_if;
7use cfg_match::cfg_match;
8use std::convert::TryInto;
9use std::fmt;
10use std::time::Duration;
11cfg_if! {
12    if #[cfg(feature = "std_web")] {
13        use stdweb::Value;
14        #[allow(unused_imports)]
15        use stdweb::{_js_impl, js};
16    } else if #[cfg(feature = "web_sys")] {
17        use gloo::timers::callback::Interval;
18    }
19}
20
21/// A handle which helps to cancel interval. Uses
22/// [clearInterval](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval).
23#[must_use = "the interval is only active until the handle is dropped"]
24pub struct IntervalTask(
25    #[cfg(feature = "std_web")] Value,
26    #[cfg(feature = "web_sys")] Interval,
27);
28
29impl fmt::Debug for IntervalTask {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.write_str("IntervalTask")
32    }
33}
34
35/// A service to send messages on every elapsed interval.
36#[derive(Default, Debug)]
37pub struct IntervalService {}
38
39impl IntervalService {
40    /// Sets interval which will call send a messages returned by a converter
41    /// on every interval expiration.
42    ///
43    /// # Panics
44    ///
45    /// Panics if `duration` in milliseconds exceeds `u32::MAX` (around 50 days).
46    pub fn spawn(duration: Duration, callback: Callback<()>) -> IntervalTask {
47        let callback = move || {
48            callback.emit(());
49        };
50        let ms: u32 = duration
51            .as_millis()
52            .try_into()
53            .expect("duration doesn't fit in u32");
54        let handle = cfg_match! {
55            feature = "std_web" => js! {
56                var callback = @{callback};
57                var action = function() {
58                    callback();
59                };
60                var delay = @{ms};
61                return {
62                    interval_id: setInterval(action, delay),
63                    callback: callback,
64                };
65            },
66            feature = "web_sys" => Interval::new(ms, callback),
67        };
68        IntervalTask(handle)
69    }
70}
71
72impl Task for IntervalTask {
73    fn is_active(&self) -> bool {
74        true
75    }
76}
77
78impl Drop for IntervalTask {
79    fn drop(&mut self) {
80        #[cfg(feature = "std_web")]
81        {
82            if self.is_active() {
83                let handle = &self.0;
84                js! { @(no_return)
85                    var handle = @{handle};
86                    clearInterval(handle.interval_id);
87                    handle.callback.drop();
88                }
89            }
90        }
91    }
92}