mod type_info; pub use type_info::*; use crate::storage::SparseSetIndex; use bitflags::bitflags; use std::{ alloc::Layout, any::{Any, TypeId}, collections::hash_map::Entry, }; use thiserror::Error; pub trait Component: Send + Sync + 'static {} impl Component for T {} #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum StorageType { Table, SparseSet, } impl Default for StorageType { fn default() -> Self { StorageType::Table } } #[derive(Debug)] pub struct ComponentInfo { name: String, id: ComponentId, type_id: Option, // SAFETY: This must remain private. It must only be set to "true" if this component is // actually Send + Sync is_send_and_sync: bool, layout: Layout, drop: unsafe fn(*mut u8), storage_type: StorageType, } impl ComponentInfo { #[inline] pub fn id(&self) -> ComponentId { self.id } #[inline] pub fn name(&self) -> &str { &self.name } #[inline] pub fn type_id(&self) -> Option { self.type_id } #[inline] pub fn layout(&self) -> Layout { self.layout } #[inline] pub fn drop(&self) -> unsafe fn(*mut u8) { self.drop } #[inline] pub fn storage_type(&self) -> StorageType { self.storage_type } #[inline] pub fn is_send_and_sync(&self) -> bool { self.is_send_and_sync } fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self { ComponentInfo { id, name: descriptor.name, storage_type: descriptor.storage_type, type_id: descriptor.type_id, is_send_and_sync: descriptor.is_send_and_sync, drop: descriptor.drop, layout: descriptor.layout, } } } #[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] pub struct ComponentId(usize); impl ComponentId { #[inline] pub const fn new(index: usize) -> ComponentId { ComponentId(index) } #[inline] pub fn index(self) -> usize { self.0 } } impl SparseSetIndex for ComponentId { #[inline] fn sparse_set_index(&self) -> usize { self.index() } fn get_sparse_set_index(value: usize) -> Self { Self(value) } } pub struct ComponentDescriptor { name: String, storage_type: StorageType, // SAFETY: This must remain private. It must only be set to "true" if this component is // actually Send + Sync is_send_and_sync: bool, type_id: Option, layout: Layout, drop: unsafe fn(*mut u8), } impl ComponentDescriptor { pub fn new(storage_type: StorageType) -> Self { Self { name: std::any::type_name::().to_string(), storage_type, is_send_and_sync: true, type_id: Some(TypeId::of::()), layout: Layout::new::(), drop: TypeInfo::drop_ptr::, } } #[inline] pub fn storage_type(&self) -> StorageType { self.storage_type } #[inline] pub fn type_id(&self) -> Option { self.type_id } #[inline] pub fn name(&self) -> &str { &self.name } } impl From for ComponentDescriptor { fn from(type_info: TypeInfo) -> Self { Self { name: type_info.type_name().to_string(), storage_type: StorageType::default(), is_send_and_sync: type_info.is_send_and_sync(), type_id: Some(type_info.type_id()), drop: type_info.drop(), layout: type_info.layout(), } } } #[derive(Debug, Default)] pub struct Components { components: Vec, indices: std::collections::HashMap, resource_indices: std::collections::HashMap, } #[derive(Debug, Error)] pub enum ComponentsError { #[error("A component of type {0:?} already exists")] ComponentAlreadyExists(TypeId), } impl Components { pub(crate) fn add( &mut self, descriptor: ComponentDescriptor, ) -> Result { let index = self.components.len(); if let Some(type_id) = descriptor.type_id { let index_entry = self.indices.entry(type_id); if let Entry::Occupied(_) = index_entry { return Err(ComponentsError::ComponentAlreadyExists(type_id)); } self.indices.insert(type_id, index); } self.components .push(ComponentInfo::new(ComponentId(index), descriptor)); Ok(ComponentId(index)) } #[inline] pub fn get_or_insert_id(&mut self) -> ComponentId { self.get_or_insert_with(TypeId::of::(), TypeInfo::of::) } #[inline] pub fn get_or_insert_info(&mut self) -> &ComponentInfo { let id = self.get_or_insert_id::(); // SAFE: component_info with the given `id` initialized above unsafe { self.get_info_unchecked(id) } } #[inline] pub fn len(&self) -> usize { self.components.len() } #[inline] pub fn is_empty(&self) -> bool { self.components.len() == 0 } #[inline] pub fn get_info(&self, id: ComponentId) -> Option<&ComponentInfo> { self.components.get(id.0) } /// # Safety /// `id` must be a valid [ComponentId] #[inline] pub unsafe fn get_info_unchecked(&self, id: ComponentId) -> &ComponentInfo { debug_assert!(id.index() < self.components.len()); self.components.get_unchecked(id.0) } #[inline] pub fn get_id(&self, type_id: TypeId) -> Option { self.indices.get(&type_id).map(|index| ComponentId(*index)) } #[inline] pub fn get_resource_id(&self, type_id: TypeId) -> Option { self.resource_indices .get(&type_id) .map(|index| ComponentId(*index)) } #[inline] pub fn get_or_insert_resource_id(&mut self) -> ComponentId { self.get_or_insert_resource_with(TypeId::of::(), TypeInfo::of::) } #[inline] pub fn get_or_insert_non_send_resource_id(&mut self) -> ComponentId { self.get_or_insert_resource_with(TypeId::of::(), TypeInfo::of_non_send_and_sync::) } #[inline] fn get_or_insert_resource_with( &mut self, type_id: TypeId, func: impl FnOnce() -> TypeInfo, ) -> ComponentId { let components = &mut self.components; let index = self.resource_indices.entry(type_id).or_insert_with(|| { let type_info = func(); let index = components.len(); components.push(ComponentInfo::new(ComponentId(index), type_info.into())); index }); ComponentId(*index) } #[inline] pub(crate) fn get_or_insert_with( &mut self, type_id: TypeId, func: impl FnOnce() -> TypeInfo, ) -> ComponentId { let components = &mut self.components; let index = self.indices.entry(type_id).or_insert_with(|| { let type_info = func(); let index = components.len(); components.push(ComponentInfo::new(ComponentId(index), type_info.into())); index }); ComponentId(*index) } } bitflags! { pub struct ComponentFlags: u8 { const ADDED = 1; const MUTATED = 2; } }