119 lines
No EOL
3 KiB
Rust
119 lines
No EOL
3 KiB
Rust
use std::{any::{TypeId, type_name}, collections::HashMap, ops::Deref};
|
|
|
|
/// Storage for
|
|
#[derive(Default, Clone)]
|
|
pub struct TypeRegistry {
|
|
inner: HashMap<TypeId, RegisteredType>,
|
|
}
|
|
|
|
impl TypeRegistry {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
/// Get registered type from the registry.
|
|
pub fn get_type(&self, type_id: TypeId) -> Option<&RegisteredType> {
|
|
self.inner.get(&type_id)
|
|
}
|
|
|
|
/// Get a mutable borrow of a registered type from the registry.
|
|
pub fn get_type_mut(&mut self, type_id: TypeId) -> Option<&mut RegisteredType> {
|
|
self.inner.get_mut(&type_id)
|
|
}
|
|
|
|
/// Get a registered type, or register a new type and return it.
|
|
pub fn get_type_or_default(&mut self, type_id: TypeId) -> &mut RegisteredType {
|
|
self.inner.entry(type_id)
|
|
.or_insert(RegisteredType::default())
|
|
}
|
|
|
|
pub fn register_type<T>(&mut self)
|
|
where
|
|
T: AsRegisteredType + 'static
|
|
{
|
|
self.inner.insert(TypeId::of::<T>(), T::as_registered_type());
|
|
}
|
|
|
|
/// Check if the registry has a type.
|
|
pub fn has_type(&self, type_id: TypeId) -> bool {
|
|
self.inner.contains_key(&type_id)
|
|
}
|
|
|
|
pub fn add_registered_type(&mut self, type_id: TypeId, registered: RegisteredType) {
|
|
self.inner.insert(type_id, registered);
|
|
}
|
|
}
|
|
|
|
pub trait TypeData: std::any::Any {
|
|
fn as_any(&self) -> &dyn std::any::Any;
|
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
|
|
|
|
fn boxed_clone(&self) -> Box<dyn TypeData>;
|
|
}
|
|
|
|
impl<T: Clone + 'static> TypeData for T {
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
|
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
|
self
|
|
}
|
|
|
|
fn boxed_clone(&self) -> Box<dyn TypeData> {
|
|
Box::new(self.clone())
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct RegisteredType {
|
|
data: HashMap<TypeId, Box<dyn TypeData>>,
|
|
pub(crate) data_names: HashMap<TypeId, String>,
|
|
}
|
|
|
|
impl Clone for RegisteredType {
|
|
fn clone(&self) -> Self {
|
|
let cloned_data = self.data.iter()
|
|
.map(|(k, v)| (k.clone(), v.deref().boxed_clone()))
|
|
.collect();
|
|
|
|
Self {
|
|
data: cloned_data,
|
|
data_names: self.data_names.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl RegisteredType {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
pub fn get_data<D>(&self) -> Option<&D>
|
|
where
|
|
D: TypeData
|
|
{
|
|
self.data.get(&TypeId::of::<D>())
|
|
.and_then(|b| b.as_ref().as_any().downcast_ref())
|
|
}
|
|
|
|
pub fn get_data_mut<D>(&mut self) -> Option<&mut D>
|
|
where
|
|
D: TypeData
|
|
{
|
|
self.data.get_mut(&TypeId::of::<D>())
|
|
.and_then(|b| b.as_mut().as_any_mut().downcast_mut())
|
|
}
|
|
|
|
pub fn add_data<D>(&mut self, data: D)
|
|
where
|
|
D: TypeData
|
|
{
|
|
self.data.insert(TypeId::of::<D>(), Box::new(data));
|
|
self.data_names.insert(TypeId::of::<D>(), type_name::<D>().to_string());
|
|
}
|
|
}
|
|
|
|
pub trait AsRegisteredType {
|
|
fn as_registered_type() -> RegisteredType;
|
|
} |