use crate::entity::{hash_set::EntityHashSet, Entity};
use alloc::vec::Vec;
use smallvec::SmallVec;
pub trait RelationshipSourceCollection {
type SourceIter<'a>: Iterator<Item = Entity>
where
Self: 'a;
fn new() -> Self;
fn with_capacity(capacity: usize) -> Self;
fn reserve(&mut self, additional: usize);
fn add(&mut self, entity: Entity) -> bool;
fn remove(&mut self, entity: Entity) -> bool;
fn iter(&self) -> Self::SourceIter<'_>;
fn len(&self) -> usize;
fn clear(&mut self);
fn shrink_to_fit(&mut self);
#[inline]
fn is_empty(&self) -> bool {
self.len() == 0
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
for entity in entities {
self.add(entity);
}
}
}
pub trait OrderedRelationshipSourceCollection: RelationshipSourceCollection {
fn insert(&mut self, index: usize, entity: Entity);
fn remove_at(&mut self, index: usize) -> Option<Entity>;
fn insert_stable(&mut self, index: usize, entity: Entity);
fn remove_at_stable(&mut self, index: usize) -> Option<Entity>;
fn sort(&mut self);
fn insert_sorted(&mut self, entity: Entity);
fn place_most_recent(&mut self, index: usize);
fn place(&mut self, entity: Entity, index: usize);
fn push_front(&mut self, entity: Entity) {
self.insert(0, entity);
}
fn push_back(&mut self, entity: Entity) {
self.insert(usize::MAX, entity);
}
fn pop_front(&mut self) -> Option<Entity> {
self.remove_at(0)
}
fn pop_back(&mut self) -> Option<Entity> {
if self.is_empty() {
None
} else {
self.remove_at(self.len() - 1)
}
}
}
impl RelationshipSourceCollection for Vec<Entity> {
type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;
fn new() -> Self {
Vec::new()
}
fn reserve(&mut self, additional: usize) {
Vec::reserve(self, additional);
}
fn with_capacity(capacity: usize) -> Self {
Vec::with_capacity(capacity)
}
fn add(&mut self, entity: Entity) -> bool {
Vec::push(self, entity);
true
}
fn remove(&mut self, entity: Entity) -> bool {
if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) {
Vec::remove(self, index);
return true;
}
false
}
fn iter(&self) -> Self::SourceIter<'_> {
<[Entity]>::iter(self).copied()
}
fn len(&self) -> usize {
Vec::len(self)
}
fn clear(&mut self) {
self.clear();
}
fn shrink_to_fit(&mut self) {
Vec::shrink_to_fit(self);
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
self.extend(entities);
}
}
impl OrderedRelationshipSourceCollection for Vec<Entity> {
fn insert(&mut self, index: usize, entity: Entity) {
self.push(entity);
let len = self.len();
if index < len {
self.swap(index, len - 1);
}
}
fn remove_at(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.swap_remove(index))
}
fn insert_stable(&mut self, index: usize, entity: Entity) {
if index < self.len() {
Vec::insert(self, index, entity);
} else {
self.push(entity);
}
}
fn remove_at_stable(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.remove(index))
}
fn sort(&mut self) {
self.sort_unstable();
}
fn insert_sorted(&mut self, entity: Entity) {
let index = self.partition_point(|e| e <= &entity);
self.insert_stable(index, entity);
}
fn place_most_recent(&mut self, index: usize) {
if let Some(entity) = self.pop() {
let index = index.min(self.len().saturating_sub(1));
self.insert(index, entity);
}
}
fn place(&mut self, entity: Entity, index: usize) {
if let Some(current) = <[Entity]>::iter(self).position(|e| *e == entity) {
let index = index.min(self.len().saturating_sub(1));
Vec::remove(self, current);
self.insert(index, entity);
};
}
}
impl RelationshipSourceCollection for EntityHashSet {
type SourceIter<'a> = core::iter::Copied<crate::entity::hash_set::Iter<'a>>;
fn new() -> Self {
EntityHashSet::new()
}
fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
fn with_capacity(capacity: usize) -> Self {
EntityHashSet::with_capacity(capacity)
}
fn add(&mut self, entity: Entity) -> bool {
self.insert(entity)
}
fn remove(&mut self, entity: Entity) -> bool {
self.0.remove(&entity)
}
fn iter(&self) -> Self::SourceIter<'_> {
self.iter().copied()
}
fn len(&self) -> usize {
self.len()
}
fn clear(&mut self) {
self.0.clear();
}
fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
self.extend(entities);
}
}
impl<const N: usize> RelationshipSourceCollection for SmallVec<[Entity; N]> {
type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;
fn new() -> Self {
SmallVec::new()
}
fn reserve(&mut self, additional: usize) {
SmallVec::reserve(self, additional);
}
fn with_capacity(capacity: usize) -> Self {
SmallVec::with_capacity(capacity)
}
fn add(&mut self, entity: Entity) -> bool {
SmallVec::push(self, entity);
true
}
fn remove(&mut self, entity: Entity) -> bool {
if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) {
SmallVec::remove(self, index);
return true;
}
false
}
fn iter(&self) -> Self::SourceIter<'_> {
<[Entity]>::iter(self).copied()
}
fn len(&self) -> usize {
SmallVec::len(self)
}
fn clear(&mut self) {
self.clear();
}
fn shrink_to_fit(&mut self) {
SmallVec::shrink_to_fit(self);
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
self.extend(entities);
}
}
impl RelationshipSourceCollection for Entity {
type SourceIter<'a> = core::option::IntoIter<Entity>;
fn new() -> Self {
Entity::PLACEHOLDER
}
fn reserve(&mut self, _: usize) {}
fn with_capacity(_capacity: usize) -> Self {
Self::new()
}
fn add(&mut self, entity: Entity) -> bool {
assert_eq!(
*self,
Entity::PLACEHOLDER,
"Entity {entity} attempted to target an entity with a one-to-one relationship, but it is already targeted by {}. You must remove the original relationship first.",
*self
);
*self = entity;
true
}
fn remove(&mut self, entity: Entity) -> bool {
if *self == entity {
*self = Entity::PLACEHOLDER;
return true;
}
false
}
fn iter(&self) -> Self::SourceIter<'_> {
if *self == Entity::PLACEHOLDER {
None.into_iter()
} else {
Some(*self).into_iter()
}
}
fn len(&self) -> usize {
if *self == Entity::PLACEHOLDER {
return 0;
}
1
}
fn clear(&mut self) {
*self = Entity::PLACEHOLDER;
}
fn shrink_to_fit(&mut self) {}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
for entity in entities {
assert_eq!(
*self,
Entity::PLACEHOLDER,
"Entity {entity} attempted to target an entity with a one-to-one relationship, but it is already targeted by {}. You must remove the original relationship first.",
*self
);
*self = entity;
}
}
}
impl<const N: usize> OrderedRelationshipSourceCollection for SmallVec<[Entity; N]> {
fn insert(&mut self, index: usize, entity: Entity) {
self.push(entity);
let len = self.len();
if index < len {
self.swap(index, len - 1);
}
}
fn remove_at(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.swap_remove(index))
}
fn insert_stable(&mut self, index: usize, entity: Entity) {
if index < self.len() {
SmallVec::<[Entity; N]>::insert(self, index, entity);
} else {
self.push(entity);
}
}
fn remove_at_stable(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.remove(index))
}
fn sort(&mut self) {
self.sort_unstable();
}
fn insert_sorted(&mut self, entity: Entity) {
let index = self.partition_point(|e| e <= &entity);
self.insert_stable(index, entity);
}
fn place_most_recent(&mut self, index: usize) {
if let Some(entity) = self.pop() {
let index = index.min(self.len() - 1);
self.insert(index, entity);
}
}
fn place(&mut self, entity: Entity, index: usize) {
if let Some(current) = <[Entity]>::iter(self).position(|e| *e == entity) {
let index = index.min(self.len() - 1);
SmallVec::<[Entity; N]>::remove(self, current);
self.insert(index, entity);
};
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::{Component, World};
use crate::relationship::RelationshipTarget;
#[test]
fn vec_relationship_source_collection() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel, linked_spawn)]
struct RelTarget(Vec<Entity>);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(b));
let rel_target = world.get::<RelTarget>(b).unwrap();
let collection = rel_target.collection();
assert_eq!(collection, &alloc::vec!(a));
}
#[test]
fn smallvec_relationship_source_collection() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel, linked_spawn)]
struct RelTarget(SmallVec<[Entity; 4]>);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(b));
let rel_target = world.get::<RelTarget>(b).unwrap();
let collection = rel_target.collection();
assert_eq!(collection, &SmallVec::from_buf([a]));
}
#[test]
fn entity_relationship_source_collection() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel)]
struct RelTarget(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(b));
let rel_target = world.get::<RelTarget>(b).unwrap();
let collection = rel_target.collection();
assert_eq!(collection, &a);
}
#[test]
fn one_to_one_relationships() {
#[derive(Component)]
#[relationship(relationship_target = Below)]
struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
struct Below(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Above(b));
assert_eq!(a, world.get::<Below>(b).unwrap().0);
world.entity_mut(b).remove::<Below>();
assert!(world.get::<Above>(a).is_none());
world.entity_mut(a).insert(Above(b));
world.entity_mut(a).remove::<Above>();
assert!(world.get::<Below>(b).is_none());
let c = world.spawn_empty().id();
world.entity_mut(a).insert(Above(c));
assert!(world.get::<Below>(b).is_none());
assert_eq!(a, world.get::<Below>(c).unwrap().0);
}
#[test]
#[should_panic]
fn one_to_one_relationship_shared_target() {
#[derive(Component)]
#[relationship(relationship_target = Below)]
struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
struct Below(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
let c = world.spawn_empty().id();
world.entity_mut(a).insert(Above(c));
world.entity_mut(b).insert(Above(c));
}
#[test]
fn one_to_one_relationship_reinsert() {
#[derive(Component)]
#[relationship(relationship_target = Below)]
struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
struct Below(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Above(b));
world.entity_mut(a).insert(Above(b));
}
}