use crate::alloc::{vec, vec::Vec};
use core::any::TypeId;
use core::borrow::Borrow;
use core::convert::TryFrom;
use core::hash::{BuildHasherDefault, Hasher};
use core::marker::PhantomData;
use spin::Mutex;
use core::{fmt, ptr};
#[cfg(feature = "std")]
use std::error::Error;
use hashbrown::{HashMap, HashSet};
use crate::alloc::boxed::Box;
use crate::archetype::{Archetype, TypeIdMap, TypeInfo};
use crate::entities::{Entities, EntityMeta, Location, ReserveEntitiesIterator};
use crate::{
Bundle, Column, ColumnBatch, ColumnMut, DynamicBundle, Entity, EntityRef, Fetch,
MissingComponent, NoSuchEntity, Query, QueryBorrow, QueryItem, QueryMut, QueryOne, Ref, RefMut,
};
pub struct World {
entities: Entities,
archetypes: ArchetypeSet,
bundle_to_archetype: TypeIdMap<u32>,
insert_edges: IndexTypeIdMap<InsertTarget>,
remove_edges: IndexTypeIdMap<u32>,
id: u64,
}
impl World {
pub fn new() -> Self {
static ID: Mutex<u64> = Mutex::new(1);
let id = {
let mut id = ID.lock();
let next = id.checked_add(1).unwrap();
*id = next;
next
};
Self {
entities: Entities::default(),
archetypes: ArchetypeSet::new(),
bundle_to_archetype: HashMap::default(),
insert_edges: HashMap::default(),
remove_edges: HashMap::default(),
id,
}
}
pub fn spawn(&mut self, components: impl DynamicBundle) -> Entity {
self.flush();
let entity = self.entities.alloc();
self.spawn_inner(entity, components);
entity
}
pub fn spawn_at(&mut self, handle: Entity, components: impl DynamicBundle) {
self.flush();
let loc = self.entities.alloc_at(handle);
if let Some(loc) = loc {
if let Some(moved) = unsafe {
self.archetypes.archetypes[loc.archetype as usize].remove(loc.index, true)
} {
self.entities.meta[moved as usize].location.index = loc.index;
}
}
self.spawn_inner(handle, components);
}
fn spawn_inner(&mut self, entity: Entity, components: impl DynamicBundle) {
let archetype_id = match components.key() {
Some(k) => {
let archetypes = &mut self.archetypes;
*self.bundle_to_archetype.entry(k).or_insert_with(|| {
components.with_ids(|ids| archetypes.get(ids, &|| components.type_info()))
})
}
None => components.with_ids(|ids| self.archetypes.get(ids, &|| components.type_info())),
};
let archetype = &mut self.archetypes.archetypes[archetype_id as usize];
unsafe {
let index = archetype.allocate(entity.id);
components.put(|ptr, ty| {
archetype.put_dynamic(ptr, ty.id(), ty.layout().size(), index);
});
self.entities.meta[entity.id as usize].location = Location {
archetype: archetype_id,
index,
};
}
}
pub fn spawn_batch<I>(&mut self, iter: I) -> SpawnBatchIter<'_, I::IntoIter>
where
I: IntoIterator,
I::Item: Bundle + 'static,
{
self.flush();
let iter = iter.into_iter();
let (lower, upper) = iter.size_hint();
let archetype_id = self.reserve_inner::<I::Item>(
u32::try_from(upper.unwrap_or(lower)).expect("iterator too large"),
);
SpawnBatchIter {
inner: iter,
entities: &mut self.entities,
archetype_id,
archetype: &mut self.archetypes.archetypes[archetype_id as usize],
}
}
pub fn spawn_column_batch(&mut self, batch: ColumnBatch) -> SpawnColumnBatchIter<'_> {
self.flush();
let archetype = batch.0;
let entity_count = archetype.len();
let (archetype_id, base) = self.archetypes.insert_batch(archetype);
let archetype = &mut self.archetypes.archetypes[archetype_id as usize];
let id_alloc = self.entities.alloc_many(entity_count, archetype_id, base);
let mut id_alloc_clone = id_alloc.clone();
let mut index = base as usize;
while let Some(id) = id_alloc_clone.next(&self.entities) {
archetype.set_entity_id(index, id);
index += 1;
}
SpawnColumnBatchIter {
pending_end: id_alloc.pending_end,
id_alloc,
entities: &mut self.entities,
}
}
pub fn spawn_column_batch_at(&mut self, handles: &[Entity], batch: ColumnBatch) {
let archetype = batch.0;
assert_eq!(
handles.len(),
archetype.len() as usize,
"number of entity IDs {} must match number of entities {}",
handles.len(),
archetype.len()
);
for &handle in handles {
let loc = self.entities.alloc_at(handle);
if let Some(loc) = loc {
if let Some(moved) = unsafe {
self.archetypes.archetypes[loc.archetype as usize].remove(loc.index, true)
} {
self.entities.meta[moved as usize].location.index = loc.index;
}
}
}
let (archetype_id, base) = self.archetypes.insert_batch(archetype);
let archetype = &mut self.archetypes.archetypes[archetype_id as usize];
for (&handle, index) in handles.iter().zip(base as usize..) {
archetype.set_entity_id(index, handle.id());
self.entities.meta[handle.id() as usize].location = Location {
archetype: archetype_id,
index: index as u32,
};
}
}
pub fn reserve_entities(&self, count: u32) -> ReserveEntitiesIterator {
self.entities.reserve_entities(count)
}
pub fn reserve_entity(&self) -> Entity {
self.entities.reserve_entity()
}
pub fn despawn(&mut self, entity: Entity) -> Result<(), NoSuchEntity> {
self.flush();
let loc = self.entities.free(entity)?;
if let Some(moved) =
unsafe { self.archetypes.archetypes[loc.archetype as usize].remove(loc.index, true) }
{
self.entities.meta[moved as usize].location.index = loc.index;
}
Ok(())
}
pub fn reserve<T: Bundle + 'static>(&mut self, additional: u32) {
self.reserve_inner::<T>(additional);
}
fn reserve_inner<T: Bundle + 'static>(&mut self, additional: u32) -> u32 {
self.flush();
self.entities.reserve(additional);
let archetypes = &mut self.archetypes;
let archetype_id = *self
.bundle_to_archetype
.entry(TypeId::of::<T>())
.or_insert_with(|| {
T::with_static_ids(|ids| archetypes.get(ids, &|| T::static_type_info()))
});
self.archetypes.archetypes[archetype_id as usize].reserve(additional);
archetype_id
}
pub fn clear(&mut self) {
for x in &mut self.archetypes.archetypes {
x.clear();
}
self.entities.clear();
}
pub fn contains(&self, entity: Entity) -> bool {
self.entities.contains(entity)
}
pub fn query<Q: Query>(&self) -> QueryBorrow<'_, Q> {
QueryBorrow::new(&self.entities.meta, &self.archetypes.archetypes)
}
pub fn query_mut<Q: Query>(&mut self) -> QueryMut<'_, Q> {
QueryMut::new(&self.entities.meta, &mut self.archetypes.archetypes)
}
pub(crate) fn memo(&self) -> (u64, u64) {
(self.id, self.archetypes.generation)
}
pub(crate) fn entities_meta(&self) -> &[EntityMeta] {
&self.entities.meta
}
pub(crate) fn archetypes_inner(&self) -> &[Archetype] {
&self.archetypes.archetypes
}
pub fn query_one<Q: Query>(&self, entity: Entity) -> Result<QueryOne<'_, Q>, NoSuchEntity> {
let loc = self.entities.get(entity)?;
Ok(unsafe {
QueryOne::new(
&self.archetypes.archetypes[loc.archetype as usize],
loc.index,
)
})
}
pub fn query_one_mut<Q: Query>(
&mut self,
entity: Entity,
) -> Result<QueryItem<'_, Q>, QueryOneError> {
let loc = self.entities.get(entity)?;
unsafe {
let archetype = &self.archetypes.archetypes[loc.archetype as usize];
let state = Q::Fetch::prepare(archetype).ok_or(QueryOneError::Unsatisfied)?;
let fetch = Q::Fetch::execute(archetype, state);
Ok(fetch.get(loc.index as usize))
}
}
pub fn get<T: Component>(&self, entity: Entity) -> Result<Ref<'_, T>, ComponentError> {
Ok(self
.entity(entity)?
.get()
.ok_or_else(MissingComponent::new::<T>)?)
}
pub fn get_mut<T: Component>(&self, entity: Entity) -> Result<RefMut<'_, T>, ComponentError> {
Ok(self
.entity(entity)?
.get_mut()
.ok_or_else(MissingComponent::new::<T>)?)
}
pub fn entity(&self, entity: Entity) -> Result<EntityRef<'_>, NoSuchEntity> {
let loc = self.entities.get(entity)?;
unsafe {
Ok(EntityRef::new(
&self.archetypes.archetypes[loc.archetype as usize],
entity,
loc.index,
))
}
}
pub unsafe fn find_entity_from_id(&self, id: u32) -> Entity {
self.entities.resolve_unknown_gen(id)
}
pub fn iter(&self) -> Iter<'_> {
Iter::new(&self.archetypes.archetypes, &self.entities)
}
pub fn insert(
&mut self,
entity: Entity,
components: impl DynamicBundle,
) -> Result<(), NoSuchEntity> {
self.flush();
let loc = self.entities.get(entity)?;
self.insert_inner(entity, components, loc.archetype, loc)
}
fn insert_inner(
&mut self,
entity: Entity,
components: impl DynamicBundle,
graph_origin: u32,
loc: Location,
) -> Result<(), NoSuchEntity> {
let target_storage;
let target = match components.key() {
None => {
target_storage = self.archetypes.get_insert_target(graph_origin, &components);
&target_storage
}
Some(key) => match self.insert_edges.get(&(graph_origin, key)) {
Some(x) => x,
None => {
let t = self.archetypes.get_insert_target(graph_origin, &components);
self.insert_edges.entry((graph_origin, key)).or_insert(t)
}
},
};
unsafe {
let source_arch = &mut self.archetypes.archetypes[loc.archetype as usize];
for &ty in &target.replaced {
let ptr = source_arch
.get_dynamic(ty.id(), ty.layout().size(), loc.index)
.unwrap();
ty.drop(ptr.as_ptr());
}
if target.index == loc.archetype {
let arch = &mut self.archetypes.archetypes[loc.archetype as usize];
components.put(|ptr, ty| {
arch.put_dynamic(ptr, ty.id(), ty.layout().size(), loc.index);
});
return Ok(());
}
let (source_arch, target_arch) = index2(
&mut self.archetypes.archetypes,
loc.archetype as usize,
target.index as usize,
);
let target_index = target_arch.allocate(entity.id);
let meta = &mut self.entities.meta[entity.id as usize];
meta.location.archetype = target.index;
meta.location.index = target_index;
components.put(|ptr, ty| {
target_arch.put_dynamic(ptr, ty.id(), ty.layout().size(), target_index);
});
for &ty in &target.retained {
let src = source_arch
.get_dynamic(ty.id(), ty.layout().size(), loc.index)
.unwrap();
target_arch.put_dynamic(src.as_ptr(), ty.id(), ty.layout().size(), target_index)
}
if let Some(moved) = source_arch.remove(loc.index, false) {
self.entities.meta[moved as usize].location.index = loc.index;
}
}
Ok(())
}
pub fn insert_one(
&mut self,
entity: Entity,
component: impl Component,
) -> Result<(), NoSuchEntity> {
self.insert(entity, (component,))
}
pub fn remove<T: Bundle + 'static>(&mut self, entity: Entity) -> Result<T, ComponentError> {
self.flush();
let loc = self.entities.get_mut(entity)?;
let old_index = loc.index;
let source_arch = &self.archetypes.archetypes[loc.archetype as usize];
let bundle = unsafe {
T::get(|ty| source_arch.get_dynamic(ty.id(), ty.layout().size(), old_index))?
};
let target =
Self::remove_target::<T>(&mut self.archetypes, &mut self.remove_edges, loc.archetype);
if loc.archetype != target {
unsafe {
let (source_arch, target_arch) = index2(
&mut self.archetypes.archetypes,
loc.archetype as usize,
target as usize,
);
let target_index = target_arch.allocate(entity.id);
loc.archetype = target;
loc.index = target_index;
if let Some(moved) = source_arch.move_to(old_index, |src, ty, size| {
if let Some(dst) = target_arch.get_dynamic(ty, size, target_index) {
ptr::copy_nonoverlapping(src, dst.as_ptr(), size);
}
}) {
self.entities.meta[moved as usize].location.index = old_index;
}
}
}
Ok(bundle)
}
fn remove_target<T: Bundle + 'static>(
archetypes: &mut ArchetypeSet,
remove_edges: &mut IndexTypeIdMap<u32>,
old_archetype: u32,
) -> u32 {
match remove_edges.get(&(old_archetype, TypeId::of::<T>())) {
Some(&x) => x,
None => {
let removed = T::with_static_ids(|ids| ids.iter().copied().collect::<HashSet<_>>());
let info = archetypes.archetypes[old_archetype as usize]
.types()
.iter()
.cloned()
.filter(|x| !removed.contains(&x.id()))
.collect::<Vec<_>>();
let elements = info.iter().map(|x| x.id()).collect::<Box<_>>();
let index = archetypes.get(&*elements, move || info);
remove_edges.insert((old_archetype, TypeId::of::<T>()), index);
index
}
}
}
pub fn remove_one<T: Component>(&mut self, entity: Entity) -> Result<T, ComponentError> {
self.remove::<(T,)>(entity).map(|(x,)| x)
}
pub fn exchange<S: Bundle + 'static, T: DynamicBundle>(
&mut self,
entity: Entity,
components: T,
) -> Result<S, ComponentError> {
self.flush();
let loc = self.entities.get(entity)?;
let source_arch = &self.archetypes.archetypes[loc.archetype as usize];
let bundle = unsafe {
S::get(|ty| source_arch.get_dynamic(ty.id(), ty.layout().size(), loc.index))?
};
let intermediate =
Self::remove_target::<S>(&mut self.archetypes, &mut self.remove_edges, loc.archetype);
self.insert_inner(entity, components, intermediate, loc)?;
Ok(bundle)
}
pub fn exchange_one<S: Component, T: Component>(
&mut self,
entity: Entity,
component: T,
) -> Result<S, ComponentError> {
self.exchange::<(S,), (T,)>(entity, (component,))
.map(|(x,)| x)
}
pub unsafe fn get_unchecked<T: Component>(&self, entity: Entity) -> Result<&T, ComponentError> {
let loc = self.entities.get(entity)?;
let archetype = &self.archetypes.archetypes[loc.archetype as usize];
let state = archetype
.get_state::<T>()
.ok_or_else(MissingComponent::new::<T>)?;
Ok(&*archetype
.get_base::<T>(state)
.as_ptr()
.add(loc.index as usize))
}
pub unsafe fn get_unchecked_mut<T: Component>(
&self,
entity: Entity,
) -> Result<&mut T, ComponentError> {
let loc = self.entities.get(entity)?;
let archetype = &self.archetypes.archetypes[loc.archetype as usize];
let state = archetype
.get_state::<T>()
.ok_or_else(MissingComponent::new::<T>)?;
Ok(&mut *archetype
.get_base::<T>(state)
.as_ptr()
.add(loc.index as usize))
}
pub fn flush(&mut self) {
let arch = &mut self.archetypes.archetypes[0];
self.entities
.flush(|id, location| location.index = unsafe { arch.allocate(id) });
}
pub fn archetypes(&self) -> impl ExactSizeIterator<Item = &'_ Archetype> + '_ {
self.archetypes_inner().iter()
}
#[deprecated(since = "0.7.2", note = "use the more general QueryBorrow::view")]
pub fn column<T: Component>(&self) -> Column<'_, T> {
let archetypes = self.archetypes.archetypes.as_slice();
let entities = self.entities.meta.as_slice();
Column::new(entities, archetypes, PhantomData)
}
#[deprecated(since = "0.7.2", note = "use the more general QueryBorrow::view")]
pub fn column_mut<T: Component>(&self) -> ColumnMut<'_, T> {
let archetypes = self.archetypes.archetypes.as_slice();
let entities = self.entities.meta.as_slice();
ColumnMut::new(entities, archetypes, PhantomData)
}
pub fn archetypes_generation(&self) -> ArchetypesGeneration {
ArchetypesGeneration(self.archetypes.generation)
}
#[inline]
pub fn len(&self) -> u32 {
self.entities.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
unsafe impl Send for World {}
unsafe impl Sync for World {}
impl Default for World {
fn default() -> Self {
Self::new()
}
}
impl<'a> IntoIterator for &'a World {
type IntoIter = Iter<'a>;
type Item = EntityRef<'a>;
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
fn index2<T>(x: &mut [T], i: usize, j: usize) -> (&mut T, &mut T) {
assert!(i != j);
assert!(i < x.len());
assert!(j < x.len());
let ptr = x.as_mut_ptr();
unsafe { (&mut *ptr.add(i), &mut *ptr.add(j)) }
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum ComponentError {
NoSuchEntity,
MissingComponent(MissingComponent),
}
#[cfg(feature = "std")]
impl Error for ComponentError {}
impl fmt::Display for ComponentError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ComponentError::*;
match *self {
NoSuchEntity => f.write_str("no such entity"),
MissingComponent(ref x) => x.fmt(f),
}
}
}
impl From<NoSuchEntity> for ComponentError {
fn from(NoSuchEntity: NoSuchEntity) -> Self {
ComponentError::NoSuchEntity
}
}
impl From<MissingComponent> for ComponentError {
fn from(x: MissingComponent) -> Self {
ComponentError::MissingComponent(x)
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum QueryOneError {
NoSuchEntity,
Unsatisfied,
}
#[cfg(feature = "std")]
impl Error for QueryOneError {}
impl fmt::Display for QueryOneError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use QueryOneError::*;
match *self {
NoSuchEntity => f.write_str("no such entity"),
Unsatisfied => f.write_str("unsatisfied"),
}
}
}
impl From<NoSuchEntity> for QueryOneError {
fn from(NoSuchEntity: NoSuchEntity) -> Self {
QueryOneError::NoSuchEntity
}
}
pub trait Component: Send + Sync + 'static {}
impl<T: Send + Sync + 'static> Component for T {}
pub struct Iter<'a> {
archetypes: core::slice::Iter<'a, Archetype>,
entities: &'a Entities,
current: Option<&'a Archetype>,
index: u32,
}
impl<'a> Iter<'a> {
fn new(archetypes: &'a [Archetype], entities: &'a Entities) -> Self {
Self {
archetypes: archetypes.iter(),
entities,
current: None,
index: 0,
}
}
}
unsafe impl Send for Iter<'_> {}
unsafe impl Sync for Iter<'_> {}
impl<'a> Iterator for Iter<'a> {
type Item = EntityRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.current {
None => {
self.current = Some(self.archetypes.next()?);
self.index = 0;
}
Some(current) => {
if self.index == current.len() as u32 {
self.current = None;
continue;
}
let index = self.index;
self.index += 1;
let id = current.entity_id(index);
return Some(unsafe {
EntityRef::new(
current,
Entity {
id,
generation: self.entities.meta[id as usize].generation,
},
index,
)
});
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
}
impl ExactSizeIterator for Iter<'_> {
#[inline]
fn len(&self) -> usize {
self.entities.len() as usize
}
}
impl<A: DynamicBundle> Extend<A> for World {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = A>,
{
for x in iter {
self.spawn(x);
}
}
}
impl<A: DynamicBundle> core::iter::FromIterator<A> for World {
fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
let mut world = World::new();
world.extend(iter);
world
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ArchetypesGeneration(u64);
pub struct SpawnBatchIter<'a, I>
where
I: Iterator,
I::Item: Bundle,
{
inner: I,
entities: &'a mut Entities,
archetype_id: u32,
archetype: &'a mut Archetype,
}
impl<I> Drop for SpawnBatchIter<'_, I>
where
I: Iterator,
I::Item: Bundle,
{
fn drop(&mut self) {
for _ in self {}
}
}
impl<I> Iterator for SpawnBatchIter<'_, I>
where
I: Iterator,
I::Item: Bundle,
{
type Item = Entity;
fn next(&mut self) -> Option<Entity> {
let components = self.inner.next()?;
let entity = self.entities.alloc();
unsafe {
let index = self.archetype.allocate(entity.id);
components.put(|ptr, ty| {
self.archetype
.put_dynamic(ptr, ty.id(), ty.layout().size(), index);
});
self.entities.meta[entity.id as usize].location = Location {
archetype: self.archetype_id,
index,
};
}
Some(entity)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<I, T> ExactSizeIterator for SpawnBatchIter<'_, I>
where
I: ExactSizeIterator<Item = T>,
T: Bundle,
{
fn len(&self) -> usize {
self.inner.len()
}
}
pub struct SpawnColumnBatchIter<'a> {
pending_end: usize,
id_alloc: crate::entities::AllocManyState,
entities: &'a mut Entities,
}
impl Iterator for SpawnColumnBatchIter<'_> {
type Item = Entity;
fn next(&mut self) -> Option<Entity> {
let id = self.id_alloc.next(self.entities)?;
Some(unsafe { self.entities.resolve_unknown_gen(id) })
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
}
impl ExactSizeIterator for SpawnColumnBatchIter<'_> {
fn len(&self) -> usize {
self.id_alloc.len(self.entities)
}
}
impl Drop for SpawnColumnBatchIter<'_> {
fn drop(&mut self) {
self.entities.finish_alloc_many(self.pending_end);
}
}
struct ArchetypeSet {
index: HashMap<Box<[TypeId]>, u32>,
archetypes: Vec<Archetype>,
generation: u64,
}
impl ArchetypeSet {
fn new() -> Self {
Self {
index: Some((Box::default(), 0)).into_iter().collect(),
archetypes: vec![Archetype::new(Vec::new())],
generation: 0,
}
}
fn get<T: Borrow<[TypeId]> + Into<Box<[TypeId]>>>(
&mut self,
components: T,
info: impl FnOnce() -> Vec<TypeInfo>,
) -> u32 {
self.index
.get(components.borrow())
.copied()
.unwrap_or_else(|| self.insert(components.into(), info()))
}
fn insert(&mut self, components: Box<[TypeId]>, info: Vec<TypeInfo>) -> u32 {
let x = self.archetypes.len() as u32;
self.archetypes.push(Archetype::new(info));
let old = self.index.insert(components, x);
debug_assert!(old.is_none(), "inserted duplicate archetype");
self.post_insert();
x
}
fn insert_batch(&mut self, archetype: Archetype) -> (u32, u32) {
use hashbrown::hash_map::Entry;
let ids = archetype
.types()
.iter()
.map(|info| info.id())
.collect::<Box<_>>();
match self.index.entry(ids) {
Entry::Occupied(x) => {
let existing = &mut self.archetypes[*x.get() as usize];
let base = existing.len();
unsafe {
existing.merge(archetype);
}
(*x.get(), base)
}
Entry::Vacant(x) => {
let id = self.archetypes.len() as u32;
self.archetypes.push(archetype);
x.insert(id);
self.post_insert();
(id, 0)
}
}
}
fn post_insert(&mut self) {
self.generation += 1;
}
fn get_insert_target(&mut self, src: u32, components: &impl DynamicBundle) -> InsertTarget {
let arch = &mut self.archetypes[src as usize];
let mut info = arch.types().to_vec();
let mut replaced = Vec::new(); let mut retained = Vec::new();
let mut src_ty = 0;
for ty in components.type_info() {
while src_ty < arch.types().len() && arch.types()[src_ty] <= ty {
if arch.types()[src_ty] != ty {
retained.push(arch.types()[src_ty]);
}
src_ty += 1;
}
if arch.has_dynamic(ty.id()) {
replaced.push(ty);
} else {
info.push(ty);
}
}
info.sort_unstable();
retained.extend_from_slice(&arch.types()[src_ty..]);
let elements = info.iter().map(|x| x.id()).collect::<Box<_>>();
let index = self.get(elements, move || info);
InsertTarget {
replaced,
retained,
index,
}
}
}
struct InsertTarget {
replaced: Vec<TypeInfo>,
retained: Vec<TypeInfo>,
index: u32,
}
type IndexTypeIdMap<V> = HashMap<(u32, TypeId), V, BuildHasherDefault<IndexTypeIdHasher>>;
#[derive(Default)]
struct IndexTypeIdHasher(u64);
impl Hasher for IndexTypeIdHasher {
fn write_u32(&mut self, index: u32) {
self.0 ^= u64::from(index);
}
fn write_u64(&mut self, type_id: u64) {
self.0 ^= type_id;
}
fn write(&mut self, _bytes: &[u8]) {
unreachable!()
}
fn finish(&self) -> u64 {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reuse_empty() {
let mut world = World::new();
let a = world.spawn(());
world.despawn(a).unwrap();
let b = world.spawn(());
assert_eq!(a.id, b.id);
assert_ne!(a.generation, b.generation);
}
#[test]
fn spawn_at() {
let mut world = World::new();
let a = world.spawn(());
world.despawn(a).unwrap();
let b = world.spawn(());
assert!(world.contains(b));
assert_eq!(a.id, b.id);
assert_ne!(a.generation, b.generation);
world.spawn_at(a, ());
assert!(!world.contains(b));
assert_eq!(b.id, a.id);
assert_ne!(b.generation, a.generation);
}
#[test]
fn reuse_populated() {
let mut world = World::new();
let a = world.spawn((42,));
assert_eq!(*world.get::<i32>(a).unwrap(), 42);
world.despawn(a).unwrap();
let b = world.spawn((true,));
assert_eq!(a.id, b.id);
assert_ne!(a.generation, b.generation);
assert!(world.get::<i32>(b).is_err());
assert!(*world.get::<bool>(b).unwrap());
}
#[test]
fn remove_nothing() {
let mut world = World::new();
let a = world.spawn(("abc", 123));
world.remove::<()>(a).unwrap();
}
}