Static reference to generic default value

⚓ Rust    📅 2025-08-09    👤 surdeus    👁️ 4      

surdeus

I am not good at English. Sorry if there are any funny expressions.


How can I get a static reference to generic default value?

I wrote the code described below and confirmed that it worked for now.
However, it has dozens of lines and includes unsafe.
I almost always fail with unsafe.

If this is possible, I can avoid using multiple memories for the same default values, as in the MyMap code below. (I believe this is a natural use. ...Right?)


Key part is DefaultMap::get::<T>().

use std::any::{Any, TypeId};
use std::collections::BTreeMap;
use std::sync::{LazyLock, Mutex, MutexGuard};

#[test]
fn usecase() {
    let mut map = MyMap::<i32>::default();
    map.insert(1, 1);
    map.insert(2, 2);
    assert_eq!(map.get(&0), &0);
    assert_eq!(map.get(&1), &1);
    assert_eq!(map.get(&2), &2);
    assert_eq!(map.get(&3), &0);

    #[derive(Default)]
    struct MyMap<T> {
        base: BTreeMap<usize, T>,
    }

    impl<T> MyMap<T>
    where
        T: Any + Default + Send + Sync,
    {
        pub fn get(&self, key: &usize) -> &T {
            self.base
                .get(key)
                .unwrap_or_else(|| DefaultMap::get::<T>())
        }

        pub fn insert(&mut self, key: usize, value: T) {
            self.base.insert(key, value);
        }
    }
}

static SINGLETON: LazyLock<Mutex<DefaultMap>> = LazyLock::new(|| Mutex::new(DefaultMap::new()));

pub struct DefaultMap(BTreeMap<TypeId, Box<dyn Any + Send + Sync>>);

impl DefaultMap {
    pub fn get<T>() -> &'static T
    where
        T: Any + Default + Send + Sync,
    {
        let mut instance = Self::instance();
        let ret = instance.get_or_insert::<T>();
        unsafe { &*(ret as *const _) }
    }

    fn new() -> Self {
        Self(BTreeMap::new())
    }

    fn instance() -> MutexGuard<'static, Self> {
        LazyLock::force(&SINGLETON).lock().unwrap()
    }

    fn get_or_insert<T>(&mut self) -> &T
    where
        T: Any + Default + Send + Sync,
    {
        self.0
            .entry(TypeId::of::<T>())
            .or_insert_with(|| Box::new(T::default()))
            .downcast_ref::<T>()
            .unwrap()
    }
}

3 posts - 2 participants

Read full topic

🏷️ Rust_feed