edict/relation/
mod.rs

1//! [`Relation`] is a concept that is similar to [`Component`].
2//! The main difference is that they are not components, but rather relations.
3//!
4//! [`Component`] is data that can be attached to individual entity
5//! and [`Relation`] is data that connects two entities together.
6//!
7//! [`Component`]: ../component/trait.Component.html
8
9use alloc::{vec, vec::Vec};
10use core::{marker::PhantomData, mem::ManuallyDrop};
11
12use crate::{
13    action::LocalActionEncoder,
14    component::{Component, ComponentBorrow},
15    entity::EntityId,
16};
17
18pub use edict_proc::Relation;
19
20pub use self::{
21    child_of::ChildOf,
22    query::{
23        FetchFilterRelatedBy, FetchRelated, FetchRelatesExclusiveRead, FetchRelatesExclusiveWrite,
24        FetchRelatesRead, FetchRelatesToRead, FetchRelatesToWrite, FetchRelatesWrite,
25        FilterFetchRelatesTo, FilterRelated, FilterRelatedBy, FilterRelates, FilterRelatesTo,
26        Related, Relates, RelatesExclusive, RelatesReadIter, RelatesTo, RelatesWriteIter,
27    },
28};
29
30mod child_of;
31mod query;
32
33/// Trait that must be implemented for types to be
34/// used as relation components.
35///
36/// Relation components are special in a way that they are bound to
37/// a pair of entities, not just one.
38/// One entity is called "origin" and the other is called "target".
39///
40/// Relation components are used to connect two entities together.
41/// For example [`ChildOf`] relation component is used to connect
42/// child entity ("origin") to parent entity ("target").
43///
44/// Relation components are dropped when either of the "origin" or "target"
45/// is dropped. Appropriate hook method is called when this happens.
46/// `on_drop` is called when relation is dropped from "origin" entity.
47/// `on_target_drop` is called when "target" entity is dropped.
48pub trait Relation: Copy + 'static {
49    /// If `true` then relation can be added only once to an entity.
50    /// If another exclusive relation is added to the same entity,
51    /// then the old one is removed.
52    /// `on_replace` is called when this happens.
53    ///
54    /// Non-exclusive relations is replaced only if re-added
55    /// with same target.
56    const EXCLUSIVE: bool = false;
57
58    /// If `true` then when relation is added to an entity
59    /// it is also added to the target in reverse direction.
60    const SYMMETRIC: bool = false;
61
62    /// If `true` then origin entity in relation is "owned" by the target.
63    /// This means that when last target is dropped, entity is despawned.
64    const OWNED: bool = false;
65
66    /// Returns name of the relation type.
67    ///
68    /// Can be overriden to provide custom name.
69    #[inline(always)]
70    #[must_use]
71    fn name() -> &'static str {
72        core::any::type_name::<Self>()
73    }
74
75    /// Method that is called when relation is dropped on origin entity.
76    /// Does nothing by default.
77    #[inline(always)]
78    fn on_drop(&mut self, origin: EntityId, target: EntityId, encoder: LocalActionEncoder) {
79        let _ = origin;
80        let _ = target;
81        let _ = encoder;
82    }
83
84    /// Method that is called when relation is re-inserted.
85    /// For non-exclusive relations this happens when relation is re-inserted with the same
86    /// origin-target entity pair.
87    /// For exclusive relations this happens when relation is re-inserted with
88    /// origin that has relation of this type with any target.
89    ///
90    /// If returns `true`, `on_drop` will be called.
91    ///
92    /// Does nothing by default and returns `true`, causing `on_drop` to be called.
93    #[inline(always)]
94    fn on_replace(
95        &mut self,
96        value: &Self,
97        origin: EntityId,
98        target: EntityId,
99        new_target: EntityId,
100        encoder: LocalActionEncoder,
101    ) -> bool {
102        let _ = value;
103        let _ = origin;
104        let _ = target;
105        let _ = new_target;
106        let _ = encoder;
107
108        true
109    }
110
111    /// Method that is called when target entity of the relation is dropped.
112    ///
113    /// Does nothing by default.
114    #[inline(always)]
115    fn on_target_drop(origin: EntityId, target: EntityId, encoder: LocalActionEncoder) {
116        let _ = origin;
117        let _ = target;
118        let _ = encoder;
119    }
120}
121
122/// Sub-trait for exclusive relations.
123/// It should be implemented for relations that specify `EXCLUSIVE = true`,
124/// to enable use of `RelatesExclusive` query.
125/// Implementing it for relation with `EXCLUSIVE = false` will cause
126/// compilation error or runtime panic.
127///
128/// `Relation` derive macro implements this trait automatically.
129pub trait ExclusiveRelation: Relation {
130    #[doc(hidden)]
131    const ASSERT_EXCLUSIVE: () = assert!(Self::EXCLUSIVE);
132}
133
134pub(crate) struct RelationTarget<R> {
135    pub target: EntityId,
136    pub relation: R,
137}
138
139pub(crate) union OriginComponent<R: Relation> {
140    exclusive: ManuallyDrop<RelationTarget<R>>,
141    non_exclusive: ManuallyDrop<Vec<RelationTarget<R>>>,
142}
143
144impl<R> Drop for OriginComponent<R>
145where
146    R: Relation,
147{
148    fn drop(&mut self) {
149        match R::EXCLUSIVE {
150            false => unsafe { ManuallyDrop::drop(&mut self.non_exclusive) },
151            true => unsafe { ManuallyDrop::drop(&mut self.exclusive) },
152        }
153    }
154}
155
156impl<R> OriginComponent<R>
157where
158    R: Relation,
159{
160    /// Called when new relation is added to an entity.
161    #[must_use]
162    pub fn new_relation(target: EntityId, relation: R) -> Self {
163        match R::EXCLUSIVE {
164            false => OriginComponent {
165                non_exclusive: ManuallyDrop::new(vec![RelationTarget { target, relation }]),
166            },
167            true => OriginComponent {
168                exclusive: ManuallyDrop::new(RelationTarget { target, relation }),
169            },
170        }
171    }
172
173    /// Called when new relation is added to an entity that already has relation of this type.
174    pub fn add_relation(
175        &mut self,
176        origin: EntityId,
177        target: EntityId,
178        relation: R,
179        encoder: LocalActionEncoder,
180    ) {
181        match R::EXCLUSIVE {
182            false => {
183                let relations = unsafe { &mut *self.non_exclusive };
184                for r in relations.iter_mut() {
185                    if r.target == target {
186                        Self::set_one(&mut r.relation, relation, origin, target, target, encoder);
187                        return;
188                    }
189                }
190                relations.push(RelationTarget { target, relation });
191            }
192            true => {
193                let r = unsafe { &mut *self.exclusive };
194                Self::set_one(&mut r.relation, relation, origin, r.target, target, encoder);
195                r.target = target;
196            }
197        }
198    }
199
200    /// Called when relation is removed from an entity.
201    /// This won't trigger any hooks.
202    pub fn remove_relation(
203        &mut self,
204        origin: EntityId,
205        target: EntityId,
206        mut encoder: LocalActionEncoder,
207    ) -> Option<R> {
208        match R::EXCLUSIVE {
209            false => {
210                let relations = unsafe { &mut *self.non_exclusive };
211                for idx in 0..relations.len() {
212                    if relations[idx].target == target {
213                        let r = relations.swap_remove(idx);
214                        if relations.is_empty() {
215                            encoder.drop::<Self>(origin);
216                        }
217                        return Some(r.relation);
218                    }
219                }
220                None
221            }
222            true => {
223                let r = unsafe { &mut *self.exclusive };
224                if r.target == target {
225                    encoder.drop::<Self>(origin);
226                    return Some(r.relation);
227                }
228                None
229            }
230        }
231    }
232
233    /// Called by target relation component when it is dropped or replaced.
234    fn on_target_drop(origin: EntityId, target: EntityId, mut encoder: LocalActionEncoder) {
235        if R::EXCLUSIVE {
236            if R::OWNED {
237                encoder.despawn(origin);
238            } else {
239                encoder.drop::<Self>(origin);
240            }
241        } else {
242            encoder.closure(move |world| {
243                let Ok(mut origin) = world.entity(origin) else {
244                    return;
245                };
246
247                let Some(comp) = origin.get_mut::<&mut Self>() else {
248                    return;
249                };
250
251                let origins = unsafe { &mut *comp.non_exclusive };
252
253                for idx in 0..origins.len() {
254                    if origins[idx].target == target {
255                        origins.swap_remove(idx);
256                        break;
257                    }
258                }
259
260                if origins.is_empty() {
261                    if R::OWNED {
262                        origin.despawn();
263                    } else {
264                        origin.drop::<Self>();
265                    }
266                }
267            });
268        }
269    }
270
271    #[must_use]
272    pub fn relations(&self) -> &[RelationTarget<R>] {
273        match R::EXCLUSIVE {
274            false => unsafe { &*self.non_exclusive },
275            true => core::slice::from_ref(unsafe { &*self.exclusive }),
276        }
277    }
278
279    #[must_use]
280    pub fn relations_mut(&mut self) -> &mut [RelationTarget<R>] {
281        match R::EXCLUSIVE {
282            false => unsafe { &mut *self.non_exclusive },
283            true => core::slice::from_mut(unsafe { &mut *self.exclusive }),
284        }
285    }
286
287    fn drop_one(
288        relation: &mut R,
289        origin: EntityId,
290        target: EntityId,
291        mut encoder: LocalActionEncoder,
292    ) {
293        relation.on_drop(origin, target, encoder.reborrow());
294        if R::SYMMETRIC {
295            if target != origin {
296                Self::on_target_drop(target, origin, encoder);
297            }
298        } else {
299            TargetComponent::<R>::on_origin_drop(origin, target, encoder)
300        }
301    }
302
303    fn set_one(
304        relation: &mut R,
305        new_relation: R,
306        origin: EntityId,
307        target: EntityId,
308        new_target: EntityId,
309        mut encoder: LocalActionEncoder,
310    ) {
311        let on_replace = relation.on_replace(
312            &new_relation,
313            origin,
314            target,
315            new_target,
316            encoder.reborrow(),
317        );
318        if on_replace {
319            relation.on_drop(origin, target, encoder.reborrow());
320        }
321        if new_target != target {
322            if R::SYMMETRIC {
323                if target != origin {
324                    Self::on_target_drop(target, origin, encoder);
325                }
326            } else {
327                TargetComponent::<R>::on_origin_drop(origin, target, encoder)
328            }
329        }
330        *relation = new_relation;
331    }
332}
333
334impl<R> Component for OriginComponent<R>
335where
336    R: Relation,
337{
338    #[inline(always)]
339    fn on_drop(&mut self, origin: EntityId, mut encoder: LocalActionEncoder) {
340        for r in self.relations_mut() {
341            Self::drop_one(&mut r.relation, origin, r.target, encoder.reborrow());
342        }
343    }
344
345    #[inline(always)]
346    fn on_replace(
347        &mut self,
348        _value: &Self,
349        _origin: EntityId,
350        _encoder: LocalActionEncoder,
351    ) -> bool {
352        unimplemented!("This method is not intended to be called");
353    }
354
355    #[inline(always)]
356    #[must_use]
357    fn borrows() -> Vec<ComponentBorrow> {
358        Vec::new()
359    }
360}
361
362/// Component that is added to target entity of the non-symmetric relation.
363pub(crate) struct TargetComponent<R> {
364    origins: Vec<EntityId>,
365    relation: PhantomData<fn() -> R>,
366}
367
368impl<R> TargetComponent<R>
369where
370    R: Relation,
371{
372    #[must_use]
373    pub(crate) fn new(origin: EntityId) -> Self {
374        debug_assert!(!R::SYMMETRIC);
375
376        TargetComponent {
377            origins: vec![origin],
378            relation: PhantomData,
379        }
380    }
381
382    pub(crate) fn add(&mut self, origin: EntityId) {
383        debug_assert!(!self.origins.contains(&origin));
384        self.origins.push(origin);
385    }
386
387    /// Called when relation is removed from an entity.
388    /// This won't trigger any hooks.
389    pub fn remove_relation(
390        &mut self,
391        origin: EntityId,
392        target: EntityId,
393        mut encoder: LocalActionEncoder,
394    ) {
395        for idx in 0..self.origins.len() {
396            if self.origins[idx] == origin {
397                self.origins.swap_remove(idx);
398                if self.origins.is_empty() {
399                    encoder.drop::<Self>(target);
400                }
401            }
402        }
403    }
404
405    /// Called when relation is removed from origin entity.
406    /// Or origin entity is dropped.
407    fn on_origin_drop(origin: EntityId, target: EntityId, mut encoder: LocalActionEncoder) {
408        encoder.closure(move |world| {
409            let Ok(mut target) = world.entity(target) else {
410                return;
411            };
412            let Some(comp) = target.get_mut::<&mut Self>() else {
413                return;
414            };
415
416            for idx in 0..comp.origins.len() {
417                if comp.origins[idx] == origin {
418                    comp.origins.swap_remove(idx);
419                    break;
420                }
421            }
422
423            if comp.origins.is_empty() {
424                target.drop::<Self>();
425            }
426        })
427    }
428}
429
430impl<R> Component for TargetComponent<R>
431where
432    R: Relation,
433{
434    #[inline(always)]
435    fn on_drop(&mut self, target: EntityId, mut encoder: LocalActionEncoder) {
436        for &origin in &self.origins {
437            R::on_target_drop(origin, target, encoder.reborrow());
438            OriginComponent::<R>::on_target_drop(origin, target, encoder.reborrow());
439        }
440    }
441
442    #[inline(always)]
443    fn on_replace(
444        &mut self,
445        _value: &Self,
446        _entity: EntityId,
447        _encoder: LocalActionEncoder,
448    ) -> bool {
449        unimplemented!("This method is not intended to be called");
450    }
451
452    #[inline(always)]
453    #[must_use]
454    fn borrows() -> Vec<ComponentBorrow> {
455        Vec::new()
456    }
457}