Info
This post is auto-generated from RSS feed The Rust Programming Language Forum - Latest topics. Source: Static reference to generic default value
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
🏷️ Rust_feed