use alloc::{vec, vec::Vec};
use core::{marker::PhantomData, mem::ManuallyDrop};
use crate::{
action::LocalActionEncoder,
component::{Component, ComponentBorrow},
entity::EntityId,
};
pub use edict_proc::Relation;
pub use self::{
child_of::ChildOf,
query::{
FetchFilterRelatedBy, FetchRelated, FetchRelatesExclusiveRead, FetchRelatesExclusiveWrite,
FetchRelatesRead, FetchRelatesToRead, FetchRelatesToWrite, FetchRelatesWrite,
FilterFetchRelatesTo, FilterRelated, FilterRelatedBy, FilterRelates, FilterRelatesTo,
Related, Relates, RelatesExclusive, RelatesReadIter, RelatesTo, RelatesWriteIter,
},
};
mod child_of;
mod query;
pub trait Relation: Copy + 'static {
const EXCLUSIVE: bool = false;
const SYMMETRIC: bool = false;
const OWNED: bool = false;
#[inline(always)]
#[must_use]
fn name() -> &'static str {
core::any::type_name::<Self>()
}
#[inline(always)]
fn on_drop(&mut self, origin: EntityId, target: EntityId, encoder: LocalActionEncoder) {
let _ = origin;
let _ = target;
let _ = encoder;
}
#[inline(always)]
fn on_replace(
&mut self,
value: &Self,
origin: EntityId,
target: EntityId,
new_target: EntityId,
encoder: LocalActionEncoder,
) -> bool {
let _ = value;
let _ = origin;
let _ = target;
let _ = new_target;
let _ = encoder;
true
}
#[inline(always)]
fn on_target_drop(origin: EntityId, target: EntityId, encoder: LocalActionEncoder) {
let _ = origin;
let _ = target;
let _ = encoder;
}
}
pub trait ExclusiveRelation: Relation {
#[doc(hidden)]
const ASSERT_EXCLUSIVE: () = assert!(Self::EXCLUSIVE);
}
pub(crate) struct RelationTarget<R> {
pub target: EntityId,
pub relation: R,
}
pub(crate) union OriginComponent<R: Relation> {
exclusive: ManuallyDrop<RelationTarget<R>>,
non_exclusive: ManuallyDrop<Vec<RelationTarget<R>>>,
}
impl<R> Drop for OriginComponent<R>
where
R: Relation,
{
fn drop(&mut self) {
match R::EXCLUSIVE {
false => unsafe { ManuallyDrop::drop(&mut self.non_exclusive) },
true => unsafe { ManuallyDrop::drop(&mut self.exclusive) },
}
}
}
impl<R> OriginComponent<R>
where
R: Relation,
{
#[must_use]
pub fn new_relation(target: EntityId, relation: R) -> Self {
match R::EXCLUSIVE {
false => OriginComponent {
non_exclusive: ManuallyDrop::new(vec![RelationTarget { target, relation }]),
},
true => OriginComponent {
exclusive: ManuallyDrop::new(RelationTarget { target, relation }),
},
}
}
pub fn add_relation(
&mut self,
origin: EntityId,
target: EntityId,
relation: R,
encoder: LocalActionEncoder,
) {
match R::EXCLUSIVE {
false => {
let relations = unsafe { &mut *self.non_exclusive };
for r in relations.iter_mut() {
if r.target == target {
Self::set_one(&mut r.relation, relation, origin, target, target, encoder);
return;
}
}
relations.push(RelationTarget { target, relation });
}
true => {
let r = unsafe { &mut *self.exclusive };
Self::set_one(&mut r.relation, relation, origin, r.target, target, encoder);
r.target = target;
}
}
}
pub fn remove_relation(
&mut self,
origin: EntityId,
target: EntityId,
mut encoder: LocalActionEncoder,
) -> Option<R> {
match R::EXCLUSIVE {
false => {
let relations = unsafe { &mut *self.non_exclusive };
for idx in 0..relations.len() {
if relations[idx].target == target {
let r = relations.swap_remove(idx);
if relations.is_empty() {
encoder.drop::<Self>(origin);
}
return Some(r.relation);
}
}
None
}
true => {
let r = unsafe { &mut *self.exclusive };
if r.target == target {
encoder.drop::<Self>(origin);
return Some(r.relation);
}
None
}
}
}
fn on_target_drop(origin: EntityId, target: EntityId, mut encoder: LocalActionEncoder) {
if R::EXCLUSIVE {
if R::OWNED {
encoder.despawn(origin);
} else {
encoder.drop::<Self>(origin);
}
} else {
encoder.closure(move |world| {
let Ok(mut origin) = world.entity(origin) else {
return;
};
let Some(comp) = origin.get_mut::<&mut Self>() else {
return;
};
let origins = unsafe { &mut *comp.non_exclusive };
for idx in 0..origins.len() {
if origins[idx].target == target {
origins.swap_remove(idx);
break;
}
}
if origins.is_empty() {
if R::OWNED {
origin.despawn();
} else {
origin.drop::<Self>();
}
}
});
}
}
#[must_use]
pub fn relations(&self) -> &[RelationTarget<R>] {
match R::EXCLUSIVE {
false => unsafe { &*self.non_exclusive },
true => core::slice::from_ref(unsafe { &*self.exclusive }),
}
}
#[must_use]
pub fn relations_mut(&mut self) -> &mut [RelationTarget<R>] {
match R::EXCLUSIVE {
false => unsafe { &mut *self.non_exclusive },
true => core::slice::from_mut(unsafe { &mut *self.exclusive }),
}
}
fn drop_one(
relation: &mut R,
origin: EntityId,
target: EntityId,
mut encoder: LocalActionEncoder,
) {
relation.on_drop(origin, target, encoder.reborrow());
if R::SYMMETRIC {
if target != origin {
Self::on_target_drop(target, origin, encoder);
}
} else {
TargetComponent::<R>::on_origin_drop(origin, target, encoder)
}
}
fn set_one(
relation: &mut R,
new_relation: R,
origin: EntityId,
target: EntityId,
new_target: EntityId,
mut encoder: LocalActionEncoder,
) {
let on_replace = relation.on_replace(
&new_relation,
origin,
target,
new_target,
encoder.reborrow(),
);
if on_replace {
relation.on_drop(origin, target, encoder.reborrow());
}
if new_target != target {
if R::SYMMETRIC {
if target != origin {
Self::on_target_drop(target, origin, encoder);
}
} else {
TargetComponent::<R>::on_origin_drop(origin, target, encoder)
}
}
*relation = new_relation;
}
}
impl<R> Component for OriginComponent<R>
where
R: Relation,
{
#[inline(always)]
fn on_drop(&mut self, origin: EntityId, mut encoder: LocalActionEncoder) {
for r in self.relations_mut() {
Self::drop_one(&mut r.relation, origin, r.target, encoder.reborrow());
}
}
#[inline(always)]
fn on_replace(
&mut self,
_value: &Self,
_origin: EntityId,
_encoder: LocalActionEncoder,
) -> bool {
unimplemented!("This method is not intended to be called");
}
#[inline(always)]
#[must_use]
fn borrows() -> Vec<ComponentBorrow> {
Vec::new()
}
}
pub(crate) struct TargetComponent<R> {
origins: Vec<EntityId>,
relation: PhantomData<fn() -> R>,
}
impl<R> TargetComponent<R>
where
R: Relation,
{
#[must_use]
pub(crate) fn new(origin: EntityId) -> Self {
debug_assert!(!R::SYMMETRIC);
TargetComponent {
origins: vec![origin],
relation: PhantomData,
}
}
pub(crate) fn add(&mut self, origin: EntityId) {
debug_assert!(!self.origins.contains(&origin));
self.origins.push(origin);
}
pub fn remove_relation(
&mut self,
origin: EntityId,
target: EntityId,
mut encoder: LocalActionEncoder,
) {
for idx in 0..self.origins.len() {
if self.origins[idx] == origin {
self.origins.swap_remove(idx);
if self.origins.is_empty() {
encoder.drop::<Self>(target);
}
}
}
}
fn on_origin_drop(origin: EntityId, target: EntityId, mut encoder: LocalActionEncoder) {
encoder.closure(move |world| {
let Ok(mut target) = world.entity(target) else {
return;
};
let Some(comp) = target.get_mut::<&mut Self>() else {
return;
};
for idx in 0..comp.origins.len() {
if comp.origins[idx] == origin {
comp.origins.swap_remove(idx);
break;
}
}
if comp.origins.is_empty() {
target.drop::<Self>();
}
})
}
}
impl<R> Component for TargetComponent<R>
where
R: Relation,
{
#[inline(always)]
fn on_drop(&mut self, target: EntityId, mut encoder: LocalActionEncoder) {
for &origin in &self.origins {
R::on_target_drop(origin, target, encoder.reborrow());
OriginComponent::<R>::on_target_drop(origin, target, encoder.reborrow());
}
}
#[inline(always)]
fn on_replace(
&mut self,
_value: &Self,
_entity: EntityId,
_encoder: LocalActionEncoder,
) -> bool {
unimplemented!("This method is not intended to be called");
}
#[inline(always)]
#[must_use]
fn borrows() -> Vec<ComponentBorrow> {
Vec::new()
}
}