use std::any::TypeId;
use std::sync::atomic::{AtomicU32, Ordering};
pub trait Component: Send + Sync + 'static {}
#[derive(Clone, Copy)]
pub struct ComponentMeta {
pub size: usize,
pub align: usize,
pub drop_fn: Option<unsafe fn(*mut u8)>,
}
impl ComponentMeta {
pub fn of<T: 'static>() -> Self {
let drop_fn: Option<unsafe fn(*mut u8)> = if std::mem::needs_drop::<T>() {
Some(|ptr: *mut u8| unsafe { std::ptr::drop_in_place(ptr as *mut T) })
} else {
None
};
Self {
size: std::mem::size_of::<T>(),
align: std::mem::align_of::<T>(),
drop_fn,
}
}
}
pub struct ComponentIdRegistry {
next: AtomicU32,
mapping: std::sync::RwLock<std::collections::HashMap<TypeId, u32>>,
metas: std::sync::RwLock<Vec<ComponentMeta>>,
}
impl ComponentIdRegistry {
pub fn new() -> Self {
Self {
next: AtomicU32::new(0),
mapping: std::sync::RwLock::new(std::collections::HashMap::new()),
metas: std::sync::RwLock::new(Vec::new()),
}
}
pub fn id_for<T: Component>(&self) -> ComponentId {
let tid = TypeId::of::<T>();
{
let map = self.mapping.read().expect("component registry lock");
if let Some(&id) = map.get(&tid) {
return ComponentId(id);
}
}
let id = self.next.fetch_add(1, Ordering::Relaxed);
self.mapping
.write()
.expect("component registry lock")
.insert(tid, id);
let meta = ComponentMeta::of::<T>();
let mut metas = self.metas.write().expect("component metas lock");
if (id as usize) >= metas.len() {
metas.resize(id as usize + 1, ComponentMeta { size: 0, align: 1, drop_fn: None });
}
metas[id as usize] = meta;
ComponentId(id)
}
pub fn get_by_type_id(&self, type_id: TypeId) -> Option<ComponentId> {
self.mapping
.read()
.expect("component registry lock")
.get(&type_id)
.map(|&id| ComponentId(id))
}
pub fn get<T: Component>(&self) -> Option<ComponentId> {
self.get_by_type_id(TypeId::of::<T>())
}
pub fn meta(&self, id: ComponentId) -> Option<ComponentMeta> {
self.metas
.read()
.expect("component metas lock")
.get(id.0 as usize)
.copied()
}
}
impl Default for ComponentIdRegistry {
fn default() -> Self {
Self::new()
}
}
unsafe impl Send for ComponentIdRegistry {}
unsafe impl Sync for ComponentIdRegistry {}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct ComponentId(pub u32);
impl std::fmt::Debug for ComponentId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ComponentId({})", self.0)
}
}