yew_stdweb/services/
timeout.rs

1//! This module contains Yew's implementation of a service to
2//! send messages when a timeout has elapsed.
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::Timeout;
18    }
19}
20
21/// A handle to cancel a timeout task.
22#[must_use = "the timeout will be cleared when the task is dropped"]
23pub struct TimeoutTask(
24    #[cfg(feature = "std_web")] Option<Value>,
25    #[cfg(feature = "web_sys")] Option<Timeout>,
26);
27
28impl fmt::Debug for TimeoutTask {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        f.write_str("TimeoutTask")
31    }
32}
33
34/// An service to set a timeout.
35#[derive(Default, Debug)]
36pub struct TimeoutService {}
37
38impl TimeoutService {
39    /// Sets timeout which sends messages from a `converter` after `duration`.
40    ///
41    /// # Panics
42    ///
43    /// Panics if `duration` in milliseconds exceeds `u32::MAX` (around 50 days).
44    pub fn spawn(duration: Duration, callback: Callback<()>) -> TimeoutTask {
45        let callback = move || {
46            callback.emit(());
47        };
48        let ms: u32 = duration
49            .as_millis()
50            .try_into()
51            .expect("duration doesn't fit in u32");
52        let handle = cfg_match! {
53            feature = "std_web" => js! {
54                var callback = @{callback};
55                var action = function() {
56                    callback();
57                    callback.drop();
58                };
59                var delay = @{ms};
60                return {
61                    timeout_id: setTimeout(action, delay),
62                    callback: callback,
63                };
64            },
65            feature = "web_sys" => Timeout::new(ms, callback),
66        };
67        TimeoutTask(Some(handle))
68    }
69}
70
71impl Task for TimeoutTask {
72    fn is_active(&self) -> bool {
73        self.0.is_some()
74    }
75}
76
77impl Drop for TimeoutTask {
78    fn drop(&mut self) {
79        #[cfg(feature = "std_web")]
80        {
81            if self.is_active() {
82                let handle = &self.0;
83                js! { @(no_return)
84                    var handle = @{handle};
85                    clearTimeout(handle.timeout_id);
86                    handle.callback.drop();
87                }
88            }
89        }
90    }
91}