forked from libre-chip/fayalite
change TypeIdMap to not use any unsafe code
This commit is contained in:
parent
5967e812a2
commit
9a1b047d2f
1 changed files with 15 additions and 40 deletions
|
@ -1,10 +1,8 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use hashbrown::HashMap;
|
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
hash::{BuildHasher, Hasher},
|
hash::{BuildHasher, Hasher},
|
||||||
ptr::NonNull,
|
|
||||||
sync::RwLock,
|
sync::RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,59 +73,36 @@ impl BuildHasher for TypeIdBuildHasher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Value(NonNull<dyn Any + Send + Sync>);
|
pub(crate) struct TypeIdMap(
|
||||||
|
RwLock<hashbrown::HashMap<TypeId, &'static (dyn Any + Send + Sync), TypeIdBuildHasher>>,
|
||||||
impl Value {
|
);
|
||||||
unsafe fn get_transmute_lifetime<'b>(&self) -> &'b (dyn Any + Send + Sync) {
|
|
||||||
unsafe { &*self.0.as_ptr() }
|
|
||||||
}
|
|
||||||
fn new(v: Box<dyn Any + Send + Sync>) -> Self {
|
|
||||||
unsafe { Self(NonNull::new_unchecked(Box::into_raw(v))) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for Value {}
|
|
||||||
unsafe impl Sync for Value {}
|
|
||||||
|
|
||||||
impl Drop for Value {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe { std::ptr::drop_in_place(self.0.as_ptr()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TypeIdMap(RwLock<HashMap<TypeId, Value, TypeIdBuildHasher>>);
|
|
||||||
|
|
||||||
impl TypeIdMap {
|
impl TypeIdMap {
|
||||||
pub const fn new() -> Self {
|
pub(crate) const fn new() -> Self {
|
||||||
Self(RwLock::new(HashMap::with_hasher(TypeIdBuildHasher)))
|
Self(RwLock::new(hashbrown::HashMap::with_hasher(
|
||||||
|
TypeIdBuildHasher,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
#[cold]
|
#[cold]
|
||||||
unsafe fn insert_slow(
|
fn insert_slow(
|
||||||
&self,
|
&self,
|
||||||
type_id: TypeId,
|
type_id: TypeId,
|
||||||
make: fn() -> Box<dyn Any + Sync + Send>,
|
make: fn() -> Box<dyn Any + Sync + Send>,
|
||||||
) -> &(dyn Any + Sync + Send) {
|
) -> &'static (dyn Any + Sync + Send) {
|
||||||
let value = Value::new(make());
|
let value = Box::leak(make());
|
||||||
let mut write_guard = self.0.write().unwrap();
|
let mut write_guard = self.0.write().unwrap();
|
||||||
unsafe {
|
*write_guard.entry(type_id).or_insert(value)
|
||||||
write_guard
|
|
||||||
.entry(type_id)
|
|
||||||
.or_insert(value)
|
|
||||||
.get_transmute_lifetime()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn get_or_insert_default<T: Sized + Any + Send + Sync + Default>(&self) -> &T {
|
pub(crate) fn get_or_insert_default<T: Sized + Any + Send + Sync + Default>(&self) -> &T {
|
||||||
let type_id = TypeId::of::<T>();
|
let type_id = TypeId::of::<T>();
|
||||||
let read_guard = self.0.read().unwrap();
|
let read_guard = self.0.read().unwrap();
|
||||||
let retval = read_guard
|
let retval = read_guard.get(&type_id).map(|v| *v);
|
||||||
.get(&type_id)
|
|
||||||
.map(|v| unsafe { Value::get_transmute_lifetime(v) });
|
|
||||||
drop(read_guard);
|
drop(read_guard);
|
||||||
let retval = match retval {
|
let retval = match retval {
|
||||||
Some(retval) => retval,
|
Some(retval) => retval,
|
||||||
None => unsafe { self.insert_slow(type_id, move || Box::new(T::default())) },
|
None => self.insert_slow(type_id, move || Box::new(T::default())),
|
||||||
};
|
};
|
||||||
unsafe { &*(retval as *const dyn Any as *const T) }
|
retval.downcast_ref().expect("known to have correct TypeId")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue