use crate::services::{Services, with_services};

impl Services {
    fn kv_set<T: 'static + Send + Sync>(&self, key: &str, value: T) {
        self.kv.insert(key.to_string(), Box::new(value));
    }
    fn kv_get<T: 'static + Clone + Send + Sync>(&self, key: &str) -> T {
        self.kv
            .get(key)
            .expect("no key")
            .downcast_ref::<T>()
            .cloned()
            .expect("wrong type cast")
    }
    fn kv_modify<T: 'static + Send + Sync>(&self, key: &str, f: impl FnOnce(&mut T)) {
        let mut entry = self.kv.get_mut(key).expect("no key");
        f(entry.downcast_mut::<T>().expect("wrong type cast"));
    }
}

/// Stores a value under the given key, replacing any previous value.
pub fn set<T: 'static + Send + Sync>(key: &str, value: T) {
    with_services(|services| services.kv_set(key, value))
}

/// Retrieves a clone of the value stored under the given key.
/// Panics if the key is missing or the type does not match.
pub fn get<T: 'static + Clone + Send + Sync>(key: &str) -> T {
    with_services(|services| services.kv_get(key))
}

/// Mutates the value stored under the given key in place.
/// Panics if the key is missing or the type does not match.
pub fn modify<T: 'static + Send + Sync>(key: &str, f: impl FnOnce(&mut T)) {
    with_services(|services| services.kv_modify(key, f))
}
