deft 0.15.0

Cross platform ui framework
use crate as deft;
use crate::js::JsError;
use crate::timer::{set_interval, set_timeout, TimerHandle};
use deft_macros::js_func;
use log::error;
use quick_js::JsValue;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;

thread_local! {
    pub static NEXT_TIMER_ID: Cell<i32> = Cell::new(1);
    pub static TIMERS: RefCell<HashMap<i32, TimerHandle>> = RefCell::new(HashMap::new());
}

#[js_func]
pub fn timer_set_timeout(callback: JsValue, timeout: Option<i32>) -> Result<i32, JsError> {
    let id = NEXT_TIMER_ID.get();
    NEXT_TIMER_ID.set(id + 1);

    let handle = set_timeout(
        move || {
            let r = callback.call_as_function(vec![]);
            match r {
                Ok(_) => {}
                Err(err) => {
                    error!("timeout callback error:{:?}", err);
                }
            }
            TIMERS.with_borrow_mut(|m| m.remove(&id));
        },
        timeout.unwrap_or(0) as u64,
    );
    TIMERS.with_borrow_mut(move |m| {
        assert!(m.insert(id, handle).is_none());
    });
    Ok(id)
}

#[js_func]
pub fn timer_clear_timeout(id: i32) {
    TIMERS.with_borrow_mut(|m| m.remove(&id));
}

#[js_func]
pub fn timer_set_interval(callback: JsValue, interval: i32) -> Result<i32, JsError> {
    let id = NEXT_TIMER_ID.get();
    NEXT_TIMER_ID.set(id + 1);

    let handle = set_interval(
        move || {
            let _ = callback.call_as_function(vec![]);
        },
        interval as u64,
    );

    TIMERS.with_borrow_mut(|m| m.insert(id, handle));
    Ok(id)
}

#[js_func]
pub fn timer_clear_interval(id: i32) {
    TIMERS.with_borrow_mut(|m| m.remove(&id));
}