vertigo 0.11.3

Reactive Real-DOM library with SSR for Rust
Documentation
use std::rc::Rc;
use vertigo_macro::store;

use crate::{
    computed::{DropResource, struct_mut::ValueMut},
    dev::{CallbackId, command::TimerKind},
};

use super::{CallbackStore, api_browser_command};

#[store]
pub fn api_timers() -> Rc<ApiTimers> {
    ApiTimers::new()
}

#[cfg(test)]
type MockTimerHandler = crate::dev::ValueMut<Option<Rc<dyn Fn(u32, CallbackId, TimerKind)>>>;

pub struct ApiTimers {
    timers: CallbackStore<(), ()>,
    #[cfg(test)]
    mock_handler: MockTimerHandler,
}

impl ApiTimers {
    fn new() -> Rc<ApiTimers> {
        Rc::new(ApiTimers {
            timers: CallbackStore::new(),
            #[cfg(test)]
            mock_handler: crate::dev::ValueMut::new(None),
        })
    }

    #[cfg(test)]
    pub fn set_mock_handler(&self, handler: impl Fn(u32, CallbackId, TimerKind) + 'static) {
        self.mock_handler.set(Some(Rc::new(handler)));
    }

    fn set<F: Fn() + 'static>(&self, duration: u32, callback: F, kind: TimerKind) -> DropResource {
        let (callback_id, drop) = self.timers.register(move |_| {
            callback();
        });

        #[cfg(test)]
        if let Some(handler) = self.mock_handler.get() {
            handler(duration, callback_id, kind);
            return DropResource::new(move || {
                drop.off();
            });
        }

        api_browser_command().timer_set(callback_id, duration, kind);

        DropResource::new(move || {
            api_browser_command().timer_clear(callback_id);
            drop.off();
        })
    }

    pub fn timeout<F: Fn() + 'static>(&self, duration: u32, callback: F) -> DropResource {
        self.set(duration, callback, TimerKind::Timeout)
    }

    pub fn interval<F: Fn() + 'static>(&self, duration: u32, callback: F) -> DropResource {
        self.set(duration, callback, TimerKind::Interval)
    }

    pub fn callback_timeout(&self, callback: CallbackId) {
        self.timers.call(callback, ());
    }

    pub fn set_timeout_and_detach<F: Fn() + 'static>(&self, duration: u32, callback: F) {
        let drop_box: Rc<ValueMut<Option<DropResource>>> = Rc::new(ValueMut::new(None));

        let callback_with_drop = {
            let drop_box = drop_box.clone();

            move || {
                callback();
                drop_box.set(None);
            }
        };

        let drop = self.timeout(duration, callback_with_drop);
        drop_box.set(Some(drop));
    }
}