use crate::archetype::{Column, EntityLocation};
use crate::component::Component;
use std::marker::PhantomData;
use std::sync::{RwLockReadGuard, RwLockWriteGuard};
pub struct StorageView<'w, T: Component> {
pub(crate) archetypes: Vec<(&'w [u32], RwLockReadGuard<'w, Column>)>,
pub(crate) arch_id_to_idx: Vec<Option<usize>>,
pub(crate) entity_locations: &'w [EntityLocation],
pub(crate) _marker: PhantomData<T>,
}
unsafe impl<'w, T: Component + Sync> Sync for StorageView<'w, T> {}
unsafe impl<'w, T: Component + Send> Send for StorageView<'w, T> {}
impl<'w, T: Component> StorageView<'w, T> {
pub fn is_empty(&self) -> bool {
self.archetypes
.iter()
.all(|(entities, _)| entities.is_empty())
}
pub fn entities(&self) -> impl Iterator<Item = u32> + '_ {
self.archetypes
.iter()
.flat_map(|(entities, _)| entities.iter().copied())
}
#[inline]
pub fn get(&self, entity_id: u32) -> Option<&T> {
let loc = self.entity_locations.get(entity_id as usize)?;
if !loc.is_valid() {
return None;
}
let arch_idx = self
.arch_id_to_idx
.get(loc.archetype_id as usize)?
.as_ref()?;
let (_, col) = &self.archetypes[*arch_idx];
unsafe {
let ptr = col.get_ptr(loc.row as usize) as *const T;
Some(&*ptr)
}
}
#[inline]
pub fn contains(&self, entity_id: u32) -> bool {
self.get(entity_id).is_some()
}
pub fn iter(&self) -> impl Iterator<Item = (u32, &T)> + '_ {
self.archetypes.iter().flat_map(|(entities, col)| {
entities
.iter()
.copied()
.zip(0..entities.len())
.map(move |(entity, row)| unsafe {
let ptr = col.get_ptr(row) as *const T;
(entity, &*ptr)
})
})
}
pub fn len(&self) -> usize {
self.archetypes
.iter()
.map(|(entities, _)| entities.len())
.sum()
}
}
impl<'w, T: Component> IntoIterator for StorageView<'w, T> {
type Item = (u32, &'w T);
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'w>;
fn into_iter(self) -> Self::IntoIter {
Box::new(self.archetypes.into_iter().flat_map(|(entities, col)| {
entities.iter().enumerate().map(move |(row, &id)| unsafe {
let ptr = col.get_ptr(row) as *const T;
(id, &*ptr)
})
}))
}
}
pub struct StorageViewMut<'w, T: Component> {
pub(crate) archetypes: Vec<(&'w [u32], RwLockWriteGuard<'w, Column>)>,
pub(crate) arch_id_to_idx: Vec<Option<usize>>,
pub(crate) entity_locations: &'w [EntityLocation],
pub(crate) _marker: PhantomData<T>,
}
unsafe impl<'w, T: Component + Sync> Sync for StorageViewMut<'w, T> {}
unsafe impl<'w, T: Component + Send> Send for StorageViewMut<'w, T> {}
impl<'w, T: Component> StorageViewMut<'w, T> {
pub fn is_empty(&self) -> bool {
self.archetypes
.iter()
.all(|(entities, _)| entities.is_empty())
}
pub fn entities(&self) -> impl Iterator<Item = u32> + '_ {
self.archetypes
.iter()
.flat_map(|(entities, _)| entities.iter().copied())
}
#[inline]
pub fn get(&self, entity_id: u32) -> Option<&T> {
let loc = self.entity_locations.get(entity_id as usize)?;
if !loc.is_valid() {
return None;
}
let arch_idx = self
.arch_id_to_idx
.get(loc.archetype_id as usize)?
.as_ref()?;
let (_, col) = &self.archetypes[*arch_idx];
unsafe {
let ptr = col.get_ptr(loc.row as usize) as *const T;
Some(&*ptr)
}
}
#[inline]
pub fn contains(&self, entity_id: u32) -> bool {
self.get(entity_id).is_some()
}
pub fn iter(&self) -> impl Iterator<Item = (u32, &T)> + '_ {
self.archetypes.iter().flat_map(|(entities, col)| {
entities
.iter()
.copied()
.zip(0..entities.len())
.map(move |(entity, row)| unsafe {
let ptr = col.get_ptr(row) as *const T;
(entity, &*ptr)
})
})
}
#[inline]
pub fn get_mut(&mut self, entity_id: u32) -> Option<&mut T> {
let loc = self.entity_locations.get(entity_id as usize)?;
if !loc.is_valid() {
return None;
}
let arch_idx = self
.arch_id_to_idx
.get(loc.archetype_id as usize)?
.as_ref()?;
let (_, col) = &mut self.archetypes[*arch_idx];
unsafe {
let ptr = col.get_ptr(loc.row as usize) as *mut T;
Some(&mut *ptr)
}
}
pub fn iter_mut(self) -> impl Iterator<Item = (u32, &'w mut T)> {
self.into_iter()
}
pub fn len(&self) -> usize {
self.archetypes
.iter()
.map(|(entities, _)| entities.len())
.sum()
}
}
impl<'w, T: Component> IntoIterator for StorageViewMut<'w, T> {
type Item = (u32, &'w mut T);
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'w>;
fn into_iter(self) -> Self::IntoIter {
Box::new(self.archetypes.into_iter().flat_map(|(entities, col)| {
entities.iter().enumerate().map(move |(row, &id)| unsafe {
let ptr = col.get_ptr(row) as *mut T;
(id, &mut *ptr)
})
}))
}
}