vertigo 0.1.1

Reactive Real-DOM library for Rust
Documentation
use std::rc::Rc;

use crate::{struct_mut::{HashMapMut, ValueMut}, JsValue, DropResource};

#[derive(PartialEq, Eq, Hash, Clone, Debug, Copy)]
pub struct CallbackId(u64);

fn get_unique_id() -> u64 {
    use std::sync::atomic::{AtomicU64, Ordering};
    static COUNTER: AtomicU64 = AtomicU64::new(1);
    COUNTER.fetch_add(1, Ordering::Relaxed)
}

impl CallbackId {
    #[allow(clippy::new_without_default)]
    pub fn new() -> CallbackId {
        CallbackId(get_unique_id())
    }

    pub fn as_u64(&self) -> u64 {
        self.0
    }

    pub fn from_u64(id: u64) -> Self {
        Self(id)
    }
}

type CallBackFn = dyn Fn(JsValue) -> JsValue + 'static;

#[derive(Clone)]
pub struct CallbackStore {
    data: Rc<HashMapMut<CallbackId, Rc<CallBackFn>>>,
}

impl CallbackStore {
    pub fn new() -> CallbackStore {
        CallbackStore {
            data: Rc::new(HashMapMut::new()),
        }
    }

    pub fn register<C: Fn(JsValue) -> JsValue + 'static>(&self, callback: C) -> (CallbackId, DropResource) {
        let callback = Rc::new(callback);
        let id = CallbackId::new();

        self.data.insert(id, callback);

        let drop = DropResource::new({
            let data = self.data.clone();
            move || {
                data.remove(&id);
            }
        });

        (id, drop)
    }

    pub fn register_with_id<C: Fn(CallbackId, JsValue) -> JsValue + 'static>(&self, callback: C) -> (CallbackId, DropResource) {
        let id = CallbackId::new();
        let callback = Rc::new(callback);

        self.data.insert(id, Rc::new(move |data| {
            callback(id, data)
        }));

        let drop = DropResource::new({
            let data = self.data.clone();
            move || {
                data.remove(&id);
            }
        });

        (id, drop)
    }

    pub fn call(&self, callback_id: CallbackId, value: JsValue) -> JsValue {
        let callback = self.data.get(&callback_id);

        match callback {
            Some(callback) => {
                callback(value)
            },
            None => {
                log::error!("callback id not found = {callback_id:?}");
                JsValue::Undefined
            }
        }
    }

    pub fn register_once<C: Fn(JsValue) -> JsValue + 'static>(&self, callback: C) -> CallbackId {
        let drop_value = Rc::new(ValueMut::new(None));

        let (callback_id, drop) = self.register({
            let drop_value = drop_value.clone();

            move |node| {
                let result = callback(node);
                drop_value.set(None);
                result
            }
        });

        drop_value.set(Some(drop));

        callback_id
    }
}