Skip to main content

moonshine_object/
hierarchy.rs

1use bevy_ecs::prelude::*;
2use bevy_ecs::query::{QueryData, QueryFilter, QueryItem};
3use bevy_ecs::relationship::{Relationship, SourceIter};
4use moonshine_kind::{prelude::*, Any};
5use moonshine_util::hierarchy::{WorldDescendantsDeepIter, WorldDescendantsWideIter};
6
7use crate::{Object, ObjectName, ObjectRebind, ObjectRef, ObjectWorldRef, Objects};
8
9/// [`Object`] methods related to hierarchy traversal.
10///
11/// These methods are available to any [`Object<T>`] or [`ObjectRef<T>`] type.
12pub trait ObjectHierarchy<T: Kind, R: Relationship>: ObjectRebind<T, R> + ObjectName {
13    /// Returns the parent of this object, if it exists.
14    fn parent(&self) -> Option<Self::Rebind<Any, R>>;
15
16    /// Returns the root of this object's hierarchy.
17    fn root(&self) -> Self::Rebind<Any, R> {
18        self.ancestors()
19            .last()
20            // SAFE: If this object is valid, then so must be its root
21            .unwrap_or_else(|| unsafe { self.rebind_any(self.entity()) })
22    }
23
24    /// Returns true if this object is the root of its hierarchy.
25    fn is_root(&self) -> bool {
26        self.parent().is_none()
27    }
28
29    /// Returns true if this object has the same root as another.
30    fn is_related_to<U: Kind>(&self, other: &impl ObjectHierarchy<U, R>) -> bool {
31        self.root().entity() == other.root().entity()
32    }
33
34    /// Returns true if this object is a child of another.
35    fn is_child(&self) -> bool {
36        self.parent().is_some()
37    }
38
39    /// Returns true if this object is a child of the given [`Entity`].
40    fn is_child_of(&self, entity: Entity) -> bool {
41        self.parent()
42            .is_some_and(|object| object.entity() == entity)
43    }
44
45    /// Iterates over all children of this object.
46    fn children(&self) -> impl Iterator<Item = Self::Rebind<Any, R>>;
47
48    /// Returns true if this object has any children.
49    fn has_children(&self) -> bool {
50        self.children().next().is_some()
51    }
52
53    /// Iterates over all children of this object which match the given [`Query`].
54    fn query_children<'a, Q: QueryData, F: QueryFilter>(
55        &'a self,
56        query: &'a Query<Q, F>,
57    ) -> impl Iterator<Item = QueryItem<'a, 'a, Q::ReadOnly>> + 'a {
58        self.children()
59            .filter_map(move |object| query.get(object.entity()).ok())
60    }
61
62    /// Iterates over all children of this object which match the given [`Kind`].
63    fn children_of_kind<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
64        &'a self,
65        objects: &'a Objects<'w, 's, U, F2, R2>,
66    ) -> impl Iterator<Item = Object<'w, 's, 'a, U, R2>> + 'a {
67        self.children()
68            .filter_map(move |object| objects.get(object.entity()).ok())
69    }
70
71    /// Returns the first child of this object which matches the given kind, if it exists.
72    fn find_child_of_kind<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
73        &self,
74        objects: &'a Objects<'w, 's, U, F2, R2>,
75    ) -> Option<Object<'w, 's, 'a, U, R2>> {
76        self.children()
77            .find_map(|object| objects.get(object.entity()).ok())
78    }
79
80    /// Iterates over all ancestors of this object.
81    fn ancestors(&self) -> impl Iterator<Item = Self::Rebind<Any, R>>;
82
83    /// Iterates over this object, followed by all of its ancestors.
84    fn self_and_ancestors(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
85        std::iter::Iterator::chain(std::iter::once(self.as_any()), self.ancestors())
86    }
87
88    /// Returns true if this object is an ancestor of another.
89    fn is_ancestor_of<U: Kind>(&self, other: &impl ObjectHierarchy<U, R>) -> bool
90    where
91        Self::Rebind<Any, R>: ObjectHierarchy<Any, R>,
92    {
93        other
94            .ancestors()
95            .any(|ancestor| ancestor.entity() == self.entity())
96    }
97
98    /// Iterates over all ancestors of this object which match the given [`Query`].
99    fn query_ancestors<'a, Q: QueryData, F: QueryFilter>(
100        &'a self,
101        query: &'a Query<Q, F>,
102    ) -> impl Iterator<Item = QueryItem<'a, 'a, Q::ReadOnly>> + 'a {
103        self.ancestors().filter_map(move |object| {
104            let entity = object.entity();
105            query.get(entity).ok()
106        })
107    }
108
109    /// Iterates over this object, followed by all its ancestors which match the given [`Query`].
110    fn query_self_and_ancestors<'a, Q: QueryData, F: QueryFilter>(
111        &'a self,
112        query: &'a Query<Q, F>,
113    ) -> impl Iterator<Item = QueryItem<'a, 'a, Q::ReadOnly>> + 'a {
114        self.self_and_ancestors().filter_map(move |object| {
115            let entity = object.entity();
116            query.get(entity).ok()
117        })
118    }
119
120    /// Iterates over all ancestors of this object which match the given [`Kind`].
121    fn ancestors_of_kind<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
122        &'a self,
123        objects: &'a Objects<'w, 's, U, F2, R2>,
124    ) -> impl Iterator<Item = Object<'w, 's, 'a, U, R2>> {
125        self.ancestors()
126            .filter_map(move |object| objects.get(object.entity()).ok())
127    }
128
129    /// Iterates over this object, followed by all its ancestors which match the given [`Kind`].
130    fn self_and_ancestors_of_kind<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
131        &'a self,
132        objects: &'a Objects<'w, 's, U, F2, R2>,
133    ) -> impl Iterator<Item = Object<'w, 's, 'a, U, R2>> {
134        self.self_and_ancestors()
135            .filter_map(move |object| objects.get(object.entity()).ok())
136    }
137
138    /// Returns the first ancestor of this object which matches the given [`Kind`], if it exists.
139    fn find_ancestor_of_kind<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
140        &self,
141        objects: &'a Objects<'w, 's, U, F2, R2>,
142    ) -> Option<Object<'w, 's, 'a, U, R2>> {
143        self.ancestors()
144            .find_map(|object| objects.get(object.entity()).ok())
145    }
146
147    /// Iterates over all descendants of this object in breadth-first order.
148    fn descendants_wide(&self) -> impl Iterator<Item = Self::Rebind<Any, R>>;
149
150    /// Iterates over all descendants of this object in depth-first order.
151    fn descendants_deep(&self) -> impl Iterator<Item = Self::Rebind<Any, R>>
152    where
153        for<'i> SourceIter<'i, R::RelationshipTarget>: DoubleEndedIterator;
154
155    /// Iterates over this object and all its descendants in breadth-first order.
156    fn self_and_descendants_wide(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
157        std::iter::Iterator::chain(std::iter::once(self.as_any()), self.descendants_wide())
158    }
159
160    /// Iterates over this object and all its descendants in depth-first order.
161    fn self_and_descendants_deep(&self) -> impl Iterator<Item = Self::Rebind<Any, R>>
162    where
163        for<'i> SourceIter<'i, R::RelationshipTarget>: DoubleEndedIterator,
164    {
165        std::iter::Iterator::chain(std::iter::once(self.as_any()), self.descendants_deep())
166    }
167
168    /// Returns true if this object is a descendant of the given entity.
169    fn is_descendant_of(&self, entity: Entity) -> bool
170    where
171        Self::Rebind<Any, R>: ObjectHierarchy<Any, R>,
172    {
173        self.ancestors().any(|ancestor| ancestor.entity() == entity)
174    }
175
176    /// Iterates over all descendants of this object which match the given [`Kind`] in breadth-first order.
177    fn descendants_of_kind_wide<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
178        &'a self,
179        objects: &'a Objects<'w, 's, U, F2, R2>,
180    ) -> impl Iterator<Item = Object<'w, 's, 'a, U, R2>> {
181        self.descendants_wide()
182            .filter_map(move |object| objects.get(object.entity()).ok())
183    }
184
185    /// Iterates over all descendants of this object which match the given [`Kind`] in depth-first order.
186    fn descendants_of_kind_deep<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
187        &'a self,
188        objects: &'a Objects<'w, 's, U, F2, R2>,
189    ) -> impl Iterator<Item = Object<'w, 's, 'a, U, R2>>
190    where
191        for<'i> SourceIter<'i, R::RelationshipTarget>: DoubleEndedIterator,
192    {
193        self.descendants_deep()
194            .filter_map(move |object| objects.get(object.entity()).ok())
195    }
196
197    /// Iterates over this object, followed by all its descendants which match the given [`Kind`] in breadth-first order.
198    fn self_and_descendants_of_kind_wide<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
199        &'a self,
200        objects: &'a Objects<'w, 's, U, F2, R2>,
201    ) -> impl Iterator<Item = Object<'w, 's, 'a, U, R2>> {
202        self.self_and_descendants_wide()
203            .filter_map(move |object| objects.get(object.entity()).ok())
204    }
205
206    /// Iterates over this object, followed by all its descendants which match the given [`Kind`] in depth-first order.
207    fn self_and_descendants_of_kind_deep<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
208        &'a self,
209        objects: &'a Objects<'w, 's, U, F2, R2>,
210    ) -> impl Iterator<Item = Object<'w, 's, 'a, U, R2>>
211    where
212        for<'i> SourceIter<'i, R::RelationshipTarget>: DoubleEndedIterator,
213    {
214        self.self_and_descendants_deep()
215            .filter_map(move |object| objects.get(object.entity()).ok())
216    }
217
218    /// Iterates over all descendants of this object which match the given [`Query`] in breadth-first order.
219    fn query_descendants_wide<'a, Q: QueryData, F: QueryFilter>(
220        &'a self,
221        query: &'a Query<Q, F>,
222    ) -> impl Iterator<Item = QueryItem<'a, 'a, Q::ReadOnly>> + 'a {
223        self.descendants_wide().filter_map(move |object| {
224            let entity = object.entity();
225            query.get(entity).ok()
226        })
227    }
228
229    /// Iterates over all descendants of this object which match the given [`Kind`] in depth-first order.
230    fn query_descendants_deep<'a, Q: QueryData, F: QueryFilter>(
231        &'a self,
232        query: &'a Query<Q, F>,
233    ) -> impl Iterator<Item = QueryItem<'a, 'a, Q::ReadOnly>> + 'a
234    where
235        for<'i> SourceIter<'i, R::RelationshipTarget>: DoubleEndedIterator,
236    {
237        self.descendants_deep().filter_map(move |object| {
238            let entity = object.entity();
239            query.get(entity).ok()
240        })
241    }
242
243    /// Iterates over this object, followed by all its descendants which match the given [`Query`] in breadth-first order.
244    fn query_self_and_descendants_wide<'a, Q: QueryData, F: QueryFilter>(
245        &'a self,
246        query: &'a Query<Q, F>,
247    ) -> impl Iterator<Item = QueryItem<'a, 'a, Q::ReadOnly>> + 'a {
248        self.self_and_descendants_wide().filter_map(move |object| {
249            let entity = object.entity();
250            query.get(entity).ok()
251        })
252    }
253
254    /// Iterates over this object, followed by all its descendants which match the given [`Query`] in depth-first order.
255    fn query_self_and_descendants_deep<'a, Q: QueryData>(
256        &'a self,
257        query: &'a Query<Q>,
258    ) -> impl Iterator<Item = QueryItem<'a, 'a, Q::ReadOnly>> + 'a
259    where
260        for<'i> SourceIter<'i, R::RelationshipTarget>: DoubleEndedIterator,
261    {
262        self.self_and_descendants_deep().filter_map(move |object| {
263            let entity = object.entity();
264            query.get(entity).ok()
265        })
266    }
267
268    /// Returns the first descendant of this object (breadth-first order) which matches the given [`Kind`], if it exists.
269    fn find_descendant_of_kind_wide<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
270        &self,
271        objects: &'a Objects<'w, 's, U, F2, R2>,
272    ) -> Option<Object<'w, 's, 'a, U, R2>> {
273        self.descendants_wide()
274            .find_map(|object| objects.get(object.entity()).ok())
275    }
276
277    /// Returns the first descendant of this object (depth-first order) which matches the given [`Kind`], if it exists.
278    fn find_descendant_of_kind_deep<'w, 's, 'a, U: Kind, F2: QueryFilter, R2: Relationship>(
279        &self,
280        objects: &'a Objects<'w, 's, U, F2, R2>,
281    ) -> Option<Object<'w, 's, 'a, U, R2>>
282    where
283        for<'i> SourceIter<'i, R::RelationshipTarget>: DoubleEndedIterator,
284    {
285        self.descendants_deep()
286            .find_map(|object| objects.get(object.entity()).ok())
287    }
288
289    /// Returns the path to this object.
290    fn path(&self) -> String {
291        // TODO: Can this be optimized?
292        let mut tokens = self
293            .self_and_ancestors()
294            .map(|ancestor| ancestor.name().unwrap_or_default().to_string())
295            .collect::<Vec<_>>();
296        tokens.reverse();
297        tokens.join("/")
298    }
299
300    /// Attempts to find an object by its path, relative to this one.
301    ///
302    /// # Usage
303    ///
304    /// An **Object Path** is a string of object names separated by slashes which represents
305    /// the path to an object within a hierarchy.
306    ///
307    /// In additional to object names, the path may contain the following special characters:
308    ///   - `.` represents this object.
309    ///   - `..` represents the parent object.
310    ///   - `*` represents any child object.
311    ///
312    /// Note that this method of object search is relatively slow, and should be reserved for
313    /// when performance is not the top priority, such as during initialization or prototyping.
314    ///
315    /// Instead, prefer to use [`Component`] to tag your entities and [`Query`] them instead, if possible.
316    ///
317    /// # Safety
318    /// This method is somewhat experimental with plans for future expansion.
319    /// Please [report](https://github.com/Zeenobit/moonshine_object/issues) any bugs you encounter or features you'd like.
320    fn find_by_path(&self, path: impl AsRef<str>) -> Option<Self::Rebind<Any, R>>;
321}
322
323impl<T: Kind, R: Relationship> ObjectHierarchy<T, R> for Object<'_, '_, '_, T, R> {
324    fn parent(&self) -> Option<Self::Rebind<Any, R>> {
325        self.hierarchy
326            .parent(self.entity())
327            // SAFE: If this object is valid, then so must be its parent
328            .map(|entity| unsafe { self.rebind_any(entity) })
329    }
330
331    fn children(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
332        self.hierarchy
333            .children(self.entity())
334            // SAFE: We assume Bevy removes invalid children
335            .map(|entity| unsafe { self.rebind_any(entity) })
336    }
337
338    fn ancestors(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
339        self.hierarchy
340            .ancestors(self.entity())
341            // SAFE: If this object is valid, then so must be its ancestors
342            .map(|entity| unsafe { self.rebind_any(entity) })
343    }
344
345    fn descendants_wide(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
346        self.hierarchy
347            .descendants_wide(self.entity())
348            // SAFE: We assume Bevy removes invalid children
349            .map(|entity| unsafe { self.rebind_any(entity) })
350    }
351
352    fn descendants_deep(&self) -> impl Iterator<Item = Self::Rebind<Any, R>>
353    where
354        for<'i> SourceIter<'i, R::RelationshipTarget>: DoubleEndedIterator,
355    {
356        self.hierarchy
357            .descendants_deep(self.entity())
358            // SAFE: We assume Bevy removes invalid children
359            .map(|entity| unsafe { self.rebind_any(entity) })
360    }
361
362    fn find_by_path(&self, path: impl AsRef<str>) -> Option<Self::Rebind<Any, R>> {
363        let tail: Vec<&str> = path.as_ref().split('/').collect();
364        find_by_path(self.cast_into_any(), &tail)
365    }
366}
367
368impl<T: Kind, R: Relationship> ObjectHierarchy<T, R> for ObjectRef<'_, '_, '_, T, R> {
369    fn parent(&self) -> Option<Self::Rebind<Any, R>> {
370        self.1
371            .parent()
372            .map(|object| ObjectRef::<Any, R>(self.0, object))
373    }
374
375    fn children(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
376        self.1.children().map(|object| ObjectRef(self.0, object))
377    }
378
379    fn ancestors(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
380        self.1.ancestors().map(|object| ObjectRef(self.0, object))
381    }
382
383    fn descendants_wide(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
384        self.1
385            .descendants_wide()
386            .map(|object| ObjectRef(self.0, object))
387    }
388
389    fn descendants_deep(&self) -> impl Iterator<Item = Self::Rebind<Any, R>>
390    where
391        for<'i> SourceIter<'i, R::RelationshipTarget>: DoubleEndedIterator,
392    {
393        self.1
394            .descendants_deep()
395            .map(|object| ObjectRef(self.0, object))
396    }
397
398    fn find_by_path(&self, path: impl AsRef<str>) -> Option<Self::Rebind<Any, R>> {
399        self.1
400            .find_by_path(path)
401            .map(|object| ObjectRef(self.0, object))
402    }
403}
404
405impl<T: Kind, R: Relationship> ObjectHierarchy<T, R> for ObjectWorldRef<'_, T, R> {
406    fn parent(&self) -> Option<Self::Rebind<Any, R>> {
407        let parent = self.world.get::<R>(self.entity())?.get();
408        // SAFE: If this object is valid, then so must be its parent
409        Some(unsafe { self.rebind_any(parent) })
410    }
411
412    fn children(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
413        self.world
414            .get::<R::RelationshipTarget>(self.entity())
415            .into_iter()
416            .flat_map(|children| children.iter())
417            // SAFE: Assume Bevy removes invalid children
418            .map(|entity| unsafe { self.rebind_any(entity) })
419    }
420
421    fn ancestors(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
422        std::iter::successors(self.parent(), |current| current.parent())
423    }
424
425    fn descendants_wide(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
426        WorldDescendantsWideIter::<R>::new(self.world, self.entity())
427            // SAFE: Assume Bevy removes invalid descendants
428            .map(|entity| unsafe { self.rebind_any(entity) })
429    }
430
431    fn descendants_deep(&self) -> impl Iterator<Item = Self::Rebind<Any, R>> {
432        WorldDescendantsDeepIter::<R>::new(self.world, self.entity())
433            // SAFE: Assume Bevy removes invalid descendants
434            .map(|entity| unsafe { self.rebind_any(entity) })
435    }
436
437    fn find_by_path(&self, path: impl AsRef<str>) -> Option<Self::Rebind<Any, R>> {
438        let tail: Vec<&str> = path.as_ref().split('/').collect();
439        find_by_path(self.cast_into_any(), &tail)
440    }
441}
442
443fn find_by_path<R: Relationship, T: ObjectHierarchy<Any, R, Rebind<Any, R> = T>>(
444    curr: T,
445    tail: &[&str],
446) -> Option<T::Rebind<Any, R>> {
447    if tail.is_empty() {
448        return Some(curr);
449    }
450
451    let head = tail[0];
452    let tail = &tail[1..];
453
454    if head == "." || head.is_empty() {
455        find_by_path(curr, tail)
456    } else if head == ".." {
457        if let Some(parent) = curr.parent() {
458            find_by_path(parent, tail)
459        } else {
460            None
461        }
462    } else if head == "*" {
463        for child in curr.children() {
464            if let Some(result) = find_by_path(child, tail) {
465                return Some(result);
466            }
467        }
468        None
469    } else if let Some(child) = curr
470        .children()
471        .find(|part| part.name().is_some_and(|name| name == head))
472    {
473        find_by_path(child, tail)
474    } else {
475        None
476    }
477}