1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use crate::{State, TickerFactory};
use std::rc::Rc;
use wasm_bindgen::__rt::WasmRefCell;
use wasm_bindgen::prelude::*;

macro_rules! timer_ticker_factory_impl {
    {
        Ticker = $T:ty,
        TickerFactory = $TFactory:ident,
        Timer = $FTimer:path,
    } => {
    #[derive(Clone, Copy)]
    pub struct $TFactory;

    impl TickerFactory for $TFactory {
        type Output = $T;

        fn new(mut task: impl FnMut() + 'static) -> Result<Self::Output, JsValue> {
            let state = Rc::new(WasmRefCell::new(State::Stopped));
            let token = Rc::new(WasmRefCell::new(None));

            let state_ = state.clone();
            let token_ = token.clone();
            let cb = Rc::new_cyclic(move |weak| {
                let weak = weak.clone();
                Closure::new(move || {
                    if state_.borrow().eq(&State::Started) {
                        task();
                        if let Some(cb) = weak.upgrade() {
                            match $FTimer(AsRef::<Closure<dyn FnMut()>>::as_ref(&cb).as_ref().unchecked_ref()) {
                                Ok(token) => {
                                    token_.borrow_mut().replace(token);
                                },
                                Err(e) => {
                                    *state_.borrow_mut() = State::Error(e);
                                }
                            }
                        }
                    }
                })
            });
            Ok(Self::Output {
                token,
                state,
                cb,
            })
        }
    }
    };
}

timer_ticker_factory_impl! {
    Ticker = crate::ticker::ImmediateTicker,
    TickerFactory = ImmediateTickerFactory,
    Timer = crate::bindings::__wasm_ticker_binding_set_immediate,
}

timer_ticker_factory_impl! {
    Ticker = crate::ticker::TimeoutTicker,
    TickerFactory = TimeoutTickerFactory,
    Timer = crate::bindings::__wasm_ticker_binding_set_timeout,
}

timer_ticker_factory_impl! {
    Ticker = crate::ticker::AnimationFrameTicker,
    TickerFactory = AnimationFrameTickerFactory,
    Timer = crate::bindings::__wasm_ticker_binding_request_animation_frame,
}