| @@ -0,0 +1,47 @@ | |||
| use crate::{access::WriteStorage, component::Component, system::SystemData, world::World}; | |||
| use super::Entity; | |||
| pub struct Builder<'a> { | |||
| world: &'a World, | |||
| entity: Entity, | |||
| built: bool, | |||
| } | |||
| impl<'a> Builder<'a> { | |||
| pub fn new(world: &'a World) -> Self { | |||
| let entity = world.entities_mut().allocate(); | |||
| Self { | |||
| world, | |||
| entity, | |||
| built: false, | |||
| } | |||
| } | |||
| #[inline] | |||
| pub fn with<T: Component>(self, c: T) -> Self { | |||
| { | |||
| let mut storage = WriteStorage::<T>::fetch(&self.world); | |||
| storage.insert(self.entity, c).unwrap(); | |||
| } | |||
| self | |||
| } | |||
| #[inline] | |||
| pub fn build(mut self) -> Entity { | |||
| self.built = true; | |||
| self.entity | |||
| } | |||
| } | |||
| impl Drop for Builder<'_> { | |||
| fn drop(&mut self) { | |||
| if !self.built { | |||
| self.world.entities_mut().kill(self.entity); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,53 @@ | |||
| use hibitset::BitSet; | |||
| use super::Entity; | |||
| #[derive(Default)] | |||
| pub struct Entities { | |||
| alive: BitSet, | |||
| cache: Vec<u32>, | |||
| generations: Vec<u32>, | |||
| } | |||
| impl Entities { | |||
| pub fn is_alive(&self, entity: Entity) -> bool { | |||
| let i = entity.index(); | |||
| let g = entity.generation(); | |||
| self.alive.contains(i) && self.generations.get(i as usize) == Some(&g) | |||
| } | |||
| pub fn allocate(&mut self) -> Entity { | |||
| let i = match self.cache.pop() { | |||
| Some(i) => i, | |||
| None => { | |||
| let i = self.generations.len() as u32; | |||
| let c = i.checked_add(1).expect("No entity left to allocate"); | |||
| self.generations.resize(c as usize, 0); | |||
| i | |||
| } | |||
| }; | |||
| let g = self.generations[i as usize].wrapping_add(1); | |||
| self.generations[i as usize] = g; | |||
| self.alive.add(i); | |||
| Entity::from_parts(i, g) | |||
| } | |||
| pub fn kill(&mut self, entity: Entity) -> bool { | |||
| if self.is_alive(entity) { | |||
| let i = entity.index(); | |||
| self.alive.remove(i); | |||
| self.cache.push(i); | |||
| true | |||
| } else { | |||
| false | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,99 @@ | |||
| use std::cmp::Ordering; | |||
| use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; | |||
| use std::hash::{Hash, Hasher}; | |||
| #[derive(Clone, Copy)] | |||
| pub struct Entity(EntityRaw); | |||
| pub type Index = u32; | |||
| pub type Generation = u32; | |||
| #[repr(C, packed)] | |||
| #[derive(Clone, Copy)] | |||
| union EntityRaw { | |||
| id: u64, | |||
| data: EntityData, | |||
| } | |||
| #[repr(C, packed)] | |||
| #[derive(Clone, Copy)] | |||
| struct EntityData { | |||
| index: Index, | |||
| generation: Generation, | |||
| } | |||
| impl Entity { | |||
| pub fn from_id(id: u64) -> Self { | |||
| Self(EntityRaw { id }) | |||
| } | |||
| pub fn from_parts(index: Index, generation: Generation) -> Self { | |||
| Self(EntityRaw { | |||
| data: EntityData { index, generation }, | |||
| }) | |||
| } | |||
| #[inline] | |||
| pub fn id(&self) -> u64 { | |||
| unsafe { self.0.id } | |||
| } | |||
| #[inline] | |||
| pub fn index(&self) -> Index { | |||
| unsafe { self.0.data.index } | |||
| } | |||
| #[inline] | |||
| pub fn generation(&self) -> Generation { | |||
| unsafe { self.0.data.generation } | |||
| } | |||
| } | |||
| impl Display for Entity { | |||
| fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { | |||
| write!(f, "{:08X}", self.id()) | |||
| } | |||
| } | |||
| impl Debug for Entity { | |||
| fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { | |||
| write!(f, "{:08X}", self.id()) | |||
| } | |||
| } | |||
| impl Hash for Entity { | |||
| fn hash<H: Hasher>(&self, state: &mut H) { | |||
| self.index().hash(state); | |||
| self.generation().hash(state); | |||
| } | |||
| } | |||
| impl Eq for Entity {} | |||
| impl PartialEq<Entity> for Entity { | |||
| fn eq(&self, other: &Entity) -> bool { | |||
| self.id() == other.id() | |||
| } | |||
| } | |||
| impl Ord for Entity { | |||
| fn cmp(&self, other: &Self) -> Ordering { | |||
| if self.generation() < other.generation() { | |||
| Ordering::Less | |||
| } else if self.generation() > other.generation() { | |||
| Ordering::Greater | |||
| } else if self.index() < other.index() { | |||
| Ordering::Less | |||
| } else if self.index() > other.index() { | |||
| Ordering::Greater | |||
| } else { | |||
| Ordering::Equal | |||
| } | |||
| } | |||
| } | |||
| impl PartialOrd for Entity { | |||
| fn partial_cmp(&self, other: &Entity) -> Option<Ordering> { | |||
| Some(Ord::cmp(self, other)) | |||
| } | |||
| } | |||
| @@ -1,2 +1,8 @@ | |||
| #[derive(Default)] | |||
| pub struct Entities; | |||
| pub mod builder; | |||
| pub mod entities; | |||
| #[allow(clippy::module_inception)] | |||
| pub mod entity; | |||
| pub use builder::Builder; | |||
| pub use entities::Entities; | |||
| pub use entity::{Entity, Generation, Index}; | |||
| @@ -0,0 +1,9 @@ | |||
| use thiserror::Error; | |||
| use crate::entity::Entity; | |||
| #[derive(Error, Debug)] | |||
| pub enum Error { | |||
| #[error("Entity is not alive: {0}!")] | |||
| EntityIsNotAlive(Entity), | |||
| } | |||
| @@ -1,6 +1,7 @@ | |||
| pub mod access; | |||
| pub mod component; | |||
| pub mod entity; | |||
| pub mod error; | |||
| pub mod misc; | |||
| pub mod resource; | |||
| pub mod storage; | |||
| @@ -4,13 +4,6 @@ use async_ecs::{VecStorage, World}; | |||
| use async_ecs_derive::Component; | |||
| use rand::random; | |||
| /* | |||
| use std::time::{Duration, Instant}; | |||
| use async_ecs::Resources; | |||
| */ | |||
| fn main() { | |||
| env_logger::builder() | |||
| .filter_level(log::LevelFilter::Info) | |||
| @@ -24,7 +17,6 @@ fn main() { | |||
| world.register_component::<Velocity>(); | |||
| world.register_component::<Acceleration>(); | |||
| /* | |||
| for _ in 0..ENTITY_COUNT { | |||
| world | |||
| .create_entity() | |||
| @@ -36,6 +28,7 @@ fn main() { | |||
| info!("World initialized!"); | |||
| /* | |||
| let mut dispatcher = DispatcherBuilder::new() | |||
| .with(Move, "move", &[]) | |||
| .with(Accelerate, "accelerate", &["move"]) | |||
| @@ -65,7 +58,7 @@ fn main() { | |||
| */ | |||
| } | |||
| const ENTITY_COUNT: usize = 3_000_000; | |||
| const ENTITY_COUNT: usize = 100_000; | |||
| const REPEAT_COUNT: u32 = 100; | |||
| #[derive(Debug, Component)] | |||
| @@ -33,9 +33,6 @@ where | |||
| let inner = self.inner.or_insert_with(move || Cell::new(Box::new(f()))); | |||
| let inner = inner.borrow_mut().map(Box::as_mut); | |||
| RefMut { | |||
| inner, | |||
| phantom: PhantomData, | |||
| } | |||
| RefMut::new(inner) | |||
| } | |||
| } | |||
| @@ -1,137 +1,18 @@ | |||
| pub mod cell; | |||
| pub mod entry; | |||
| pub mod resources; | |||
| pub use resources::{Ref, RefMut, Resources}; | |||
| use std::any::TypeId; | |||
| use std::marker::PhantomData; | |||
| use std::ops::{Deref, DerefMut}; | |||
| use hashbrown::HashMap; | |||
| use mopa::Any; | |||
| use cell::{Cell, Ref as CellRef, RefMut as CellRefMut}; | |||
| use entry::Entry; | |||
| #[derive(Default)] | |||
| pub struct Resources { | |||
| resources: HashMap<ResourceId, Cell<Box<dyn Resource>>>, | |||
| } | |||
| pub trait Resource: Any + Send + Sync + 'static {} | |||
| #[derive(Debug, Hash, Eq, PartialEq)] | |||
| pub struct ResourceId(TypeId); | |||
| pub trait Resource: Any + Send + Sync + 'static {} | |||
| pub struct Ref<'a, R: 'a> { | |||
| inner: CellRef<'a, dyn Resource>, | |||
| phantom: PhantomData<&'a R>, | |||
| } | |||
| pub struct RefMut<'a, R: 'a> { | |||
| inner: CellRefMut<'a, dyn Resource>, | |||
| phantom: PhantomData<&'a R>, | |||
| } | |||
| macro_rules! fetch_panic { | |||
| () => {{ | |||
| panic!( | |||
| "\ | |||
| Tried to fetch resource from the resources map, but the resource does not exist.\n\ | |||
| \n\ | |||
| Resource: `{resource_name_full}`\n\ | |||
| \n\ | |||
| You may ensure the resource exists!\ | |||
| ", | |||
| resource_name_full = std::any::type_name::<R>(), | |||
| ) | |||
| }}; | |||
| } | |||
| /* Resources */ | |||
| impl Resources { | |||
| pub fn entry<R>(&mut self) -> Entry<R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| Entry::new(self.resources.entry(ResourceId::new::<R>())) | |||
| } | |||
| pub fn insert<R>(&mut self, r: R) | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources | |||
| .insert(ResourceId::new::<R>(), Cell::new(Box::new(r))); | |||
| } | |||
| pub fn remove<R>(&mut self) -> Option<R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources | |||
| .remove(&ResourceId::new::<R>()) | |||
| .map(Cell::into_inner) | |||
| .map(|x: Box<dyn Resource>| x.downcast()) | |||
| .map(|x: Result<Box<R>, _>| x.ok().unwrap()) | |||
| .map(|x| *x) | |||
| } | |||
| pub fn contains<R>(&self) -> bool | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources.contains_key(&ResourceId::new::<R>()) | |||
| } | |||
| pub fn borrow<R>(&self) -> Ref<R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.try_borrow().unwrap_or_else(|| fetch_panic!()) | |||
| } | |||
| pub fn try_borrow<R>(&self) -> Option<Ref<R>> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources.get(&ResourceId::new::<R>()).map(|r| Ref { | |||
| inner: CellRef::map(r.borrow(), Box::as_ref), | |||
| phantom: PhantomData, | |||
| }) | |||
| } | |||
| pub fn borrow_mut<R>(&self) -> RefMut<R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.try_borrow_mut().unwrap_or_else(|| fetch_panic!()) | |||
| } | |||
| pub fn try_borrow_mut<R>(&self) -> Option<RefMut<R>> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources.get(&ResourceId::new::<R>()).map(|r| RefMut { | |||
| inner: r.borrow_mut().map(Box::as_mut), | |||
| phantom: PhantomData, | |||
| }) | |||
| } | |||
| pub fn get_mut<R: Resource>(&mut self) -> Option<&mut R> { | |||
| self.get_resource_mut(ResourceId::new::<R>()) | |||
| .map(|res| res.downcast_mut().unwrap()) | |||
| } | |||
| pub fn get_resource_mut(&mut self, id: ResourceId) -> Option<&mut dyn Resource> { | |||
| self.resources | |||
| .get_mut(&id) | |||
| .map(Cell::get_mut) | |||
| .map(Box::as_mut) | |||
| } | |||
| } | |||
| /* ResourceId */ | |||
| impl ResourceId { | |||
| pub fn new<R>() -> Self | |||
| where | |||
| @@ -140,116 +21,3 @@ impl ResourceId { | |||
| Self(TypeId::of::<R>()) | |||
| } | |||
| } | |||
| /* Resource */ | |||
| impl<T> Resource for T where T: Any + Send + Sync {} | |||
| mod __resource_mopafy_scope { | |||
| #![allow(clippy::all)] | |||
| use mopa::mopafy; | |||
| use super::Resource; | |||
| mopafy!(Resource); | |||
| } | |||
| /* Ref */ | |||
| impl<'a, R> Deref for Ref<'a, R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| type Target = R; | |||
| fn deref(&self) -> &R { | |||
| unsafe { self.inner.downcast_ref_unchecked() } | |||
| } | |||
| } | |||
| impl<'a, R> Clone for Ref<'a, R> { | |||
| fn clone(&self) -> Self { | |||
| Ref { | |||
| inner: self.inner.clone(), | |||
| phantom: PhantomData, | |||
| } | |||
| } | |||
| } | |||
| /* RefMut */ | |||
| impl<'a, R> Deref for RefMut<'a, R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| type Target = R; | |||
| fn deref(&self) -> &R { | |||
| unsafe { self.inner.downcast_ref_unchecked() } | |||
| } | |||
| } | |||
| impl<'a, R> DerefMut for RefMut<'a, R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| fn deref_mut(&mut self) -> &mut R { | |||
| unsafe { self.inner.downcast_mut_unchecked() } | |||
| } | |||
| } | |||
| #[cfg(test)] | |||
| mod tests { | |||
| use super::*; | |||
| #[derive(Default)] | |||
| struct Res; | |||
| #[test] | |||
| fn insert() { | |||
| struct Foo; | |||
| let mut resources = Resources::default(); | |||
| resources.insert(Res); | |||
| assert!(resources.contains::<Res>()); | |||
| assert!(!resources.contains::<Foo>()); | |||
| } | |||
| #[test] | |||
| #[should_panic(expected = "but it was already borrowed")] | |||
| fn read_write_fails() { | |||
| let mut resources = Resources::default(); | |||
| resources.insert(Res); | |||
| let _read = resources.borrow::<Res>(); | |||
| let _write = resources.borrow_mut::<Res>(); | |||
| } | |||
| #[test] | |||
| #[should_panic(expected = "but it was already borrowed mutably")] | |||
| fn write_read_fails() { | |||
| let mut resources = Resources::default(); | |||
| resources.insert(Res); | |||
| let _write = resources.borrow_mut::<Res>(); | |||
| let _read = resources.borrow::<Res>(); | |||
| } | |||
| #[test] | |||
| fn remove_insert() { | |||
| let mut resources = Resources::default(); | |||
| resources.insert(Res); | |||
| assert!(resources.contains::<Res>()); | |||
| resources.remove::<Res>().unwrap(); | |||
| assert!(!resources.contains::<Res>()); | |||
| resources.insert(Res); | |||
| assert!(resources.contains::<Res>()); | |||
| } | |||
| } | |||
| @@ -0,0 +1,256 @@ | |||
| use std::marker::PhantomData; | |||
| use std::ops::{Deref, DerefMut}; | |||
| use hashbrown::HashMap; | |||
| use mopa::Any; | |||
| use super::{ | |||
| cell::{Cell, Ref as CellRef, RefMut as CellRefMut}, | |||
| entry::Entry, | |||
| Resource, ResourceId, | |||
| }; | |||
| #[derive(Default)] | |||
| pub struct Resources { | |||
| resources: HashMap<ResourceId, Cell<Box<dyn Resource>>>, | |||
| } | |||
| pub struct Ref<'a, R: 'a> { | |||
| inner: CellRef<'a, dyn Resource>, | |||
| phantom: PhantomData<&'a R>, | |||
| } | |||
| pub struct RefMut<'a, R: 'a> { | |||
| inner: CellRefMut<'a, dyn Resource>, | |||
| phantom: PhantomData<&'a R>, | |||
| } | |||
| macro_rules! fetch_panic { | |||
| () => {{ | |||
| panic!( | |||
| "\ | |||
| Tried to fetch resource from the resources map, but the resource does not exist.\n\ | |||
| \n\ | |||
| Resource: `{resource_name_full}`\n\ | |||
| \n\ | |||
| You may ensure the resource exists!\ | |||
| ", | |||
| resource_name_full = std::any::type_name::<R>(), | |||
| ) | |||
| }}; | |||
| } | |||
| /* Resources */ | |||
| impl Resources { | |||
| pub fn entry<R>(&mut self) -> Entry<R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| Entry::new(self.resources.entry(ResourceId::new::<R>())) | |||
| } | |||
| pub fn insert<R>(&mut self, r: R) | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources | |||
| .insert(ResourceId::new::<R>(), Cell::new(Box::new(r))); | |||
| } | |||
| pub fn remove<R>(&mut self) -> Option<R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources | |||
| .remove(&ResourceId::new::<R>()) | |||
| .map(Cell::into_inner) | |||
| .map(|x: Box<dyn Resource>| x.downcast()) | |||
| .map(|x: Result<Box<R>, _>| x.ok().unwrap()) | |||
| .map(|x| *x) | |||
| } | |||
| pub fn contains<R>(&self) -> bool | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources.contains_key(&ResourceId::new::<R>()) | |||
| } | |||
| pub fn borrow<R>(&self) -> Ref<R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.try_borrow().unwrap_or_else(|| fetch_panic!()) | |||
| } | |||
| pub fn try_borrow<R>(&self) -> Option<Ref<R>> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources.get(&ResourceId::new::<R>()).map(|r| Ref { | |||
| inner: CellRef::map(r.borrow(), Box::as_ref), | |||
| phantom: PhantomData, | |||
| }) | |||
| } | |||
| pub fn borrow_mut<R>(&self) -> RefMut<R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.try_borrow_mut().unwrap_or_else(|| fetch_panic!()) | |||
| } | |||
| pub fn try_borrow_mut<R>(&self) -> Option<RefMut<R>> | |||
| where | |||
| R: Resource, | |||
| { | |||
| self.resources.get(&ResourceId::new::<R>()).map(|r| RefMut { | |||
| inner: r.borrow_mut().map(Box::as_mut), | |||
| phantom: PhantomData, | |||
| }) | |||
| } | |||
| pub fn get_mut<R: Resource>(&mut self) -> Option<&mut R> { | |||
| self.get_resource_mut(ResourceId::new::<R>()) | |||
| .map(|res| res.downcast_mut().unwrap()) | |||
| } | |||
| pub fn get_resource_mut(&mut self, id: ResourceId) -> Option<&mut dyn Resource> { | |||
| self.resources | |||
| .get_mut(&id) | |||
| .map(Cell::get_mut) | |||
| .map(Box::as_mut) | |||
| } | |||
| } | |||
| /* Resource */ | |||
| impl<T> Resource for T where T: Any + Send + Sync {} | |||
| mod __resource_mopafy_scope { | |||
| #![allow(clippy::all)] | |||
| use mopa::mopafy; | |||
| use super::super::Resource; | |||
| mopafy!(Resource); | |||
| } | |||
| /* Ref */ | |||
| impl<'a, R> Ref<'a, R> { | |||
| pub fn new(inner: CellRef<'a, dyn Resource>) -> Self { | |||
| Self { | |||
| inner, | |||
| phantom: PhantomData, | |||
| } | |||
| } | |||
| } | |||
| impl<'a, R> Deref for Ref<'a, R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| type Target = R; | |||
| fn deref(&self) -> &R { | |||
| unsafe { self.inner.downcast_ref_unchecked() } | |||
| } | |||
| } | |||
| impl<'a, R> Clone for Ref<'a, R> { | |||
| fn clone(&self) -> Self { | |||
| Ref { | |||
| inner: self.inner.clone(), | |||
| phantom: PhantomData, | |||
| } | |||
| } | |||
| } | |||
| /* RefMut */ | |||
| impl<'a, R> RefMut<'a, R> { | |||
| pub fn new(inner: CellRefMut<'a, dyn Resource>) -> Self { | |||
| Self { | |||
| inner, | |||
| phantom: PhantomData, | |||
| } | |||
| } | |||
| } | |||
| impl<'a, R> Deref for RefMut<'a, R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| type Target = R; | |||
| fn deref(&self) -> &R { | |||
| unsafe { self.inner.downcast_ref_unchecked() } | |||
| } | |||
| } | |||
| impl<'a, R> DerefMut for RefMut<'a, R> | |||
| where | |||
| R: Resource, | |||
| { | |||
| fn deref_mut(&mut self) -> &mut R { | |||
| unsafe { self.inner.downcast_mut_unchecked() } | |||
| } | |||
| } | |||
| #[cfg(test)] | |||
| mod tests { | |||
| use super::*; | |||
| #[derive(Default)] | |||
| struct Res; | |||
| #[test] | |||
| fn insert() { | |||
| struct Foo; | |||
| let mut resources = Resources::default(); | |||
| resources.insert(Res); | |||
| assert!(resources.contains::<Res>()); | |||
| assert!(!resources.contains::<Foo>()); | |||
| } | |||
| #[test] | |||
| #[should_panic(expected = "but it was already borrowed")] | |||
| fn read_write_fails() { | |||
| let mut resources = Resources::default(); | |||
| resources.insert(Res); | |||
| let _read = resources.borrow::<Res>(); | |||
| let _write = resources.borrow_mut::<Res>(); | |||
| } | |||
| #[test] | |||
| #[should_panic(expected = "but it was already borrowed mutably")] | |||
| fn write_read_fails() { | |||
| let mut resources = Resources::default(); | |||
| resources.insert(Res); | |||
| let _write = resources.borrow_mut::<Res>(); | |||
| let _read = resources.borrow::<Res>(); | |||
| } | |||
| #[test] | |||
| fn remove_insert() { | |||
| let mut resources = Resources::default(); | |||
| resources.insert(Res); | |||
| assert!(resources.contains::<Res>()); | |||
| resources.remove::<Res>().unwrap(); | |||
| assert!(!resources.contains::<Res>()); | |||
| resources.insert(Res); | |||
| assert!(resources.contains::<Res>()); | |||
| } | |||
| } | |||
| @@ -1,6 +1,8 @@ | |||
| use std::mem::swap; | |||
| use hibitset::BitSet; | |||
| use crate::component::Component; | |||
| use crate::{component::Component, entity::Entity, storage::Storage}; | |||
| pub struct MaskedStorage<T: Component> { | |||
| mask: BitSet, | |||
| @@ -14,4 +16,19 @@ impl<T: Component> MaskedStorage<T> { | |||
| inner, | |||
| } | |||
| } | |||
| pub fn insert(&mut self, entity: Entity, mut component: T) -> Option<T> { | |||
| let index = entity.index(); | |||
| if self.mask.contains(index) { | |||
| swap(&mut component, self.inner.get_mut(index)); | |||
| Some(component) | |||
| } else { | |||
| self.mask.add(index); | |||
| self.inner.insert(index, component); | |||
| None | |||
| } | |||
| } | |||
| } | |||
| @@ -6,6 +6,10 @@ pub use masked_storage::MaskedStorage; | |||
| pub use storage_wrapper::StorageWrapper; | |||
| pub use vec_storage::VecStorage; | |||
| use crate::misc::TryDefault; | |||
| use crate::{entity::Index, misc::TryDefault}; | |||
| pub trait Storage<T>: TryDefault {} | |||
| pub trait Storage<T>: TryDefault { | |||
| fn get(&self, index: Index) -> &T; | |||
| fn get_mut(&mut self, index: Index) -> &mut T; | |||
| fn insert(&mut self, index: Index, value: T); | |||
| } | |||
| @@ -1,6 +1,13 @@ | |||
| use std::marker::PhantomData; | |||
| use std::ops::DerefMut; | |||
| use crate::{entity::Entities, resource::Ref}; | |||
| use crate::{ | |||
| component::Component, | |||
| entity::{Entities, Entity}, | |||
| error::Error, | |||
| resource::Ref, | |||
| storage::MaskedStorage, | |||
| }; | |||
| pub struct StorageWrapper<'a, T, D> { | |||
| data: D, | |||
| @@ -17,3 +24,17 @@ impl<'a, T, D> StorageWrapper<'a, T, D> { | |||
| } | |||
| } | |||
| } | |||
| impl<'a, T, D> StorageWrapper<'a, T, D> | |||
| where | |||
| T: Component, | |||
| D: DerefMut<Target = MaskedStorage<T>>, | |||
| { | |||
| pub fn insert(&mut self, entity: Entity, component: T) -> Result<Option<T>, Error> { | |||
| if !self.entities.is_alive(entity) { | |||
| return Err(Error::EntityIsNotAlive(entity)); | |||
| } | |||
| Ok(self.data.insert(entity, component)) | |||
| } | |||
| } | |||
| @@ -1,10 +1,38 @@ | |||
| use std::mem::MaybeUninit; | |||
| use crate::entity::Index; | |||
| use super::Storage; | |||
| pub struct VecStorage<T>(Vec<MaybeUninit<T>>); | |||
| impl<T> Storage<T> for VecStorage<T> {} | |||
| impl<T> Storage<T> for VecStorage<T> { | |||
| fn get(&self, index: Index) -> &T { | |||
| unsafe { &*self.0.get_unchecked(index as usize).as_ptr() } | |||
| } | |||
| fn get_mut(&mut self, index: Index) -> &mut T { | |||
| unsafe { &mut *self.0.get_unchecked_mut(index as usize).as_mut_ptr() } | |||
| } | |||
| fn insert(&mut self, index: Index, value: T) { | |||
| let index = index as usize; | |||
| if self.0.len() <= index { | |||
| let delta = index + 1 - self.0.len(); | |||
| self.0.reserve(delta); | |||
| unsafe { | |||
| self.0.set_len(index + 1); | |||
| } | |||
| } | |||
| unsafe { | |||
| *self.0.get_unchecked_mut(index) = MaybeUninit::new(value); | |||
| } | |||
| } | |||
| } | |||
| impl<T> Default for VecStorage<T> { | |||
| fn default() -> Self { | |||
| @@ -7,7 +7,7 @@ use std::ops::{Deref, DerefMut}; | |||
| use crate::{ | |||
| access::{Read, ReadStorage, WriteStorage}, | |||
| component::Component, | |||
| entity::Entities, | |||
| entity::{Builder, Entities}, | |||
| resource::{Ref, RefMut, Resource, Resources}, | |||
| storage::MaskedStorage, | |||
| system::SystemData, | |||
| @@ -59,6 +59,10 @@ impl World { | |||
| pub fn component_mut<T: Component>(&self) -> WriteStorage<T> { | |||
| WriteStorage::fetch(&self) | |||
| } | |||
| pub fn create_entity(&mut self) -> Builder { | |||
| Builder::new(self) | |||
| } | |||
| } | |||
| impl Default for World { | |||