moonshine_object/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4pub mod prelude {
5    //! Prelude module to import all necessary traits and types for working with objects.
6
7    pub use super::{GetObject, ObjectHierarchy, ObjectName, ObjectRebind, ObjectTags};
8    pub use super::{Object, ObjectRef, ObjectWorldRef, Objects, RootObjects};
9}
10
11mod hierarchy;
12mod name;
13mod rebind;
14mod tags;
15
16use std::fmt;
17use std::ops::Deref;
18
19use bevy_ecs::entity::EntityDoesNotExistError;
20use bevy_ecs::prelude::*;
21use bevy_ecs::query::{QueryEntityError, QueryFilter, QuerySingleError};
22use bevy_ecs::system::SystemParam;
23use moonshine_kind::prelude::*;
24use moonshine_util::hierarchy::HierarchyQuery;
25
26pub use moonshine_kind::{Any, CastInto, Kind};
27pub use moonshine_tag::{Tag, TagFilter, Tags};
28
29pub use hierarchy::*;
30pub use name::*;
31pub use rebind::*;
32pub use tags::*;
33
34/// A [`SystemParam`] similar to [`Query`] which provides [`Object<T>`] access for its items.
35#[derive(SystemParam)]
36pub struct Objects<'w, 's, T = Any, F = ()>
37where
38    T: Kind,
39    F: 'static + QueryFilter,
40{
41    /// [`Query`] used to filter instances of the given [`Kind`] `T`.
42    pub instance: Query<'w, 's, Instance<T>, F>,
43    /// [`HierarchyQuery`] used to traverse the object hierarchy.
44    pub hierarchy: HierarchyQuery<'w, 's>,
45    /// [`Query`] to identify objects by name or tags, mainly used for for hierarchy traversal and searching.
46    pub nametags: Query<'w, 's, AnyOf<(&'static Name, &'static Tags)>>,
47}
48
49impl<'w, 's, T, F> Objects<'w, 's, T, F>
50where
51    T: Kind,
52    F: 'static + QueryFilter,
53{
54    /// Iterates over all [`Object`]s of [`Kind`] `T` which match the [`QueryFilter`] `F`.
55    pub fn iter(&self) -> impl Iterator<Item = Object<'w, 's, '_, T>> {
56        self.instance.iter().map(|instance| Object {
57            instance,
58            hierarchy: &self.hierarchy,
59            nametags: &self.nametags,
60        })
61    }
62
63    /// Returns true if the given [`Entity`] is a valid [`Object<T>`].
64    pub fn contains(&self, entity: Entity) -> bool {
65        self.instance.contains(entity)
66    }
67
68    /// Returns an iterator over all [`ObjectRef`] instances of [`Kind`] `T` which match the [`QueryFilter`] `F`.
69    pub fn iter_ref<'a>(
70        &'a self,
71        world: &'a World,
72    ) -> impl Iterator<Item = ObjectRef<'w, 's, 'a, T>> {
73        self.iter()
74            .map(|object: Object<T>| ObjectRef(world.entity(object.entity()), object))
75    }
76
77    /// Returns an [`Object<T>`] from an [`Entity`], if it matches [`QueryFilter`] `F`.
78    pub fn get(&self, entity: Entity) -> Result<Object<'w, 's, '_, T>, QueryEntityError> {
79        self.instance.get(entity).map(|instance| Object {
80            instance,
81            hierarchy: &self.hierarchy,
82            nametags: &self.nametags,
83        })
84    }
85
86    /// Returns an [`ObjectRef<T>`] from an [`EntityRef`], if it matches [`QueryFilter`] `F`.
87    pub fn get_ref<'a>(&'a self, entity: EntityRef<'a>) -> Option<ObjectRef<'w, 's, 'a, T>> {
88        Some(ObjectRef(entity, self.get(entity.id()).ok()?))
89    }
90
91    /// Returns an [`Object<T>`], if it exists as a single instance.
92    pub fn get_single(&self) -> Result<Object<'w, 's, '_, T>, QuerySingleError> {
93        self.instance.single().map(|instance| Object {
94            instance,
95            hierarchy: &self.hierarchy,
96            nametags: &self.nametags,
97        })
98    }
99
100    /// Returns an [`ObjectRef<T>`] from an [`EntityRef`], if it exists as a single instance.
101    pub fn get_single_ref<'a>(&'a self, entity: EntityRef<'a>) -> Option<ObjectRef<'w, 's, 'a, T>> {
102        Some(ObjectRef(entity, self.get_single().ok()?))
103    }
104
105    /// Return an [`Object`] of [`Kind`] `T` from an [`Instance`].
106    ///
107    /// # Safety
108    /// Assumes `instance` is a valid [`Instance`] of [`Kind`] `T`.
109    pub fn instance(&self, instance: Instance<T>) -> Object<'w, 's, '_, T> {
110        self.get(instance.entity()).expect("instance must be valid")
111    }
112
113    /// Return an [`Object`] of [`Kind`] `T` from an [`Instance`].
114    pub fn get_instance(
115        &self,
116        instance: Instance<T>,
117    ) -> Result<Object<'w, 's, '_, T>, QueryEntityError> {
118        self.get(instance.entity())
119    }
120}
121
122/// Ergonomic type alias for all [`Objects`] of [`Kind`] `T` without a parent.
123pub type RootObjects<'w, 's, T = Any, F = ()> = Objects<'w, 's, T, (F, Without<ChildOf>)>;
124
125/// Represents an [`Entity`] of [`Kind`] `T` with hierarchy and name information.
126pub struct Object<'w, 's, 'a, T: Kind = Any> {
127    instance: Instance<T>,
128    hierarchy: &'a HierarchyQuery<'w, 's>,
129    nametags: &'a Query<'w, 's, AnyOf<(&'static Name, &'static Tags)>>,
130}
131
132impl<'w, 's, 'a, T: Kind> Object<'w, 's, 'a, T> {
133    /// Creates a new [`Object<T>`] from an [`Object<Any>`].
134    ///
135    /// This is semantically equivalent to an unsafe downcast.
136    ///
137    /// # Safety
138    /// Assumes `base` is of [`Kind`] `T`.
139    pub unsafe fn from_any_unchecked(object: Object<'w, 's, 'a>) -> Self {
140        Self {
141            instance: object.instance.cast_into_unchecked(),
142            hierarchy: object.hierarchy,
143            nametags: object.nametags,
144        }
145    }
146
147    /// Returns the object as an [`Instance<T>`].
148    pub fn instance(&self) -> Instance<T> {
149        self.instance
150    }
151
152    /// Returns the object as an [`Entity`].
153    pub fn entity(&self) -> Entity {
154        self.instance.entity()
155    }
156}
157
158impl<'w, 's, 'a, T: Component> Object<'w, 's, 'a, T> {
159    /// Creates a new [`Object<T>`] from an [`Object<Any>`] if it is a valid instance of `T`.
160    pub fn from_any(world: &World, object: Object<'w, 's, 'a>) -> Option<Object<'w, 's, 'a, T>> {
161        let entity = world.entity(object.entity());
162        let instance = Instance::<T>::from_entity(entity)?;
163        // SAFE: Entity was just checked to a valid instance of T.
164        Some(unsafe { object.rebind_as(instance) })
165    }
166}
167
168impl<T: Kind> Clone for Object<'_, '_, '_, T> {
169    fn clone(&self) -> Self {
170        *self
171    }
172}
173
174impl<T: Kind> Copy for Object<'_, '_, '_, T> {}
175
176impl<T: Kind> From<Object<'_, '_, '_, T>> for Entity {
177    fn from(object: Object<'_, '_, '_, T>) -> Self {
178        object.entity()
179    }
180}
181
182impl<T: Kind> From<Object<'_, '_, '_, T>> for Instance<T> {
183    fn from(object: Object<'_, '_, '_, T>) -> Self {
184        object.instance()
185    }
186}
187
188impl<T: Kind, U: Kind> PartialEq<Object<'_, '_, '_, U>> for Object<'_, '_, '_, T> {
189    fn eq(&self, other: &Object<U>) -> bool {
190        self.instance == other.instance
191    }
192}
193
194impl<T: Kind> Eq for Object<'_, '_, '_, T> {}
195
196impl<T: Kind> PartialEq<Instance<T>> for Object<'_, '_, '_, T> {
197    fn eq(&self, other: &Instance<T>) -> bool {
198        self.instance() == *other
199    }
200}
201
202impl<T: Kind> PartialEq<Object<'_, '_, '_, T>> for Instance<T> {
203    fn eq(&self, other: &Object<T>) -> bool {
204        *self == other.instance()
205    }
206}
207
208impl<T: Kind> PartialEq<Entity> for Object<'_, '_, '_, T> {
209    fn eq(&self, other: &Entity) -> bool {
210        self.entity() == *other
211    }
212}
213
214impl<T: Kind> PartialEq<Object<'_, '_, '_, T>> for Entity {
215    fn eq(&self, other: &Object<T>) -> bool {
216        *self == other.entity()
217    }
218}
219
220impl<T: Kind> fmt::Debug for Object<'_, '_, '_, T> {
221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222        if let Some(name) = self.name() {
223            write!(f, "{}({:?}, \"{}\")", &T::debug_name(), self.entity(), name)
224        } else {
225            write!(f, "{}({:?})", &T::debug_name(), self.entity())
226        }
227    }
228}
229
230impl<T: Kind> fmt::Display for Object<'_, '_, '_, T> {
231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232        if let Some(name) = self.name() {
233            write!(f, "{}({}, \"{}\")", &T::debug_name(), self.entity(), name)
234        } else {
235            write!(f, "{}({})", &T::debug_name(), self.entity())
236        }
237    }
238}
239
240impl<T: Kind> ContainsInstance<T> for Object<'_, '_, '_, T> {
241    fn instance(&self) -> Instance<T> {
242        self.instance
243    }
244}
245
246/// Similar to [`EntityRef`] with the benefits of [`Object<T>`].
247pub struct ObjectRef<'w, 's, 'a, T: Kind = Any>(EntityRef<'a>, Object<'w, 's, 'a, T>);
248
249impl<'w, 's, 'a, T: Kind> ObjectRef<'w, 's, 'a, T> {
250    /// Creates a new [`ObjectRef<T>`] from an [`ObjectRef<Any>`].
251    ///
252    /// This is semantically equivalent to an unsafe downcast.
253    ///
254    /// # Safety
255    /// Assumes `base` is of [`Kind`] `T`.
256    pub unsafe fn from_any_unchecked(base: ObjectRef<'w, 's, 'a>) -> Self {
257        Self(base.0, Object::from_any_unchecked(base.1))
258    }
259
260    /// See [`EntityRef::get`].
261    pub fn get<U: Component>(&self) -> Option<&U> {
262        self.0.get::<U>()
263    }
264
265    /// See [`EntityRef::contains`].
266    pub fn contains<U: Component>(&self) -> bool {
267        self.0.contains::<U>()
268    }
269
270    /// Returns the object as an [`EntityRef`].
271    pub fn as_entity(&self) -> EntityRef<'a> {
272        self.0
273    }
274}
275
276impl<T: Kind> Clone for ObjectRef<'_, '_, '_, T> {
277    fn clone(&self) -> Self {
278        *self
279    }
280}
281
282impl<T: Kind> Copy for ObjectRef<'_, '_, '_, T> {}
283
284impl<T: Kind> From<ObjectRef<'_, '_, '_, T>> for Entity {
285    fn from(object: ObjectRef<'_, '_, '_, T>) -> Self {
286        object.entity()
287    }
288}
289
290impl<T: Kind> From<ObjectRef<'_, '_, '_, T>> for Instance<T> {
291    fn from(object: ObjectRef<'_, '_, '_, T>) -> Self {
292        object.instance()
293    }
294}
295
296impl<'w, 's, 'a, T: Kind> From<ObjectRef<'w, 's, 'a, T>> for Object<'w, 's, 'a, T> {
297    fn from(object: ObjectRef<'w, 's, 'a, T>) -> Self {
298        object.1
299    }
300}
301
302impl<'w, 's, 'a, T: Kind> From<&ObjectRef<'w, 's, 'a, T>> for Object<'w, 's, 'a, T> {
303    fn from(object: &ObjectRef<'w, 's, 'a, T>) -> Self {
304        object.1
305    }
306}
307
308impl<T: Kind> PartialEq for ObjectRef<'_, '_, '_, T> {
309    fn eq(&self, other: &Self) -> bool {
310        self.1 == other.1
311    }
312}
313
314impl<T: Kind> Eq for ObjectRef<'_, '_, '_, T> {}
315
316impl<T: Kind> ContainsInstance<T> for ObjectRef<'_, '_, '_, T> {
317    fn instance(&self) -> Instance<T> {
318        self.1.instance()
319    }
320}
321
322impl<T: Component> Deref for ObjectRef<'_, '_, '_, T> {
323    type Target = T;
324
325    fn deref(&self) -> &Self::Target {
326        self.0.get::<T>().unwrap()
327    }
328}
329
330impl<T: Kind> fmt::Debug for ObjectRef<'_, '_, '_, T> {
331    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332        if let Some(name) = self.name() {
333            write!(f, "{}({:?}, \"{}\")", &T::debug_name(), self.entity(), name)
334        } else {
335            write!(f, "{}({:?})", &T::debug_name(), self.entity())
336        }
337    }
338}
339
340impl<T: Kind> fmt::Display for ObjectRef<'_, '_, '_, T> {
341    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342        if let Some(name) = self.name() {
343            write!(f, "{}({}, \"{}\")", &T::debug_name(), self.entity(), name)
344        } else {
345            write!(f, "{}({})", &T::debug_name(), self.entity())
346        }
347    }
348}
349
350/// Similar to an [`ObjectRef`], but accessible via [`World`].
351pub struct ObjectWorldRef<'w, T: Kind = Any> {
352    instance: Instance<T>,
353    world: &'w World,
354}
355
356impl<'w, T: Kind> ObjectWorldRef<'w, T> {
357    /// Creates a new [`ObjectWorldRef<T>`] from an [`ObjectWorldRef<Any>`].
358    ///
359    /// This is semantically equivalent to an unsafe downcast.
360    ///
361    /// # Safety
362    /// Assumes `object` is of [`Kind`] `T`.
363    pub unsafe fn from_any_unchecked(object: ObjectWorldRef<'w>) -> Self {
364        Self {
365            instance: object.instance.cast_into_unchecked(),
366            world: object.world,
367        }
368    }
369
370    /// Creates a new [`ObjectWorldRef<T>`] from an [`ObjectWorldRef<Any>`] if the object
371    /// contains the given [`Component`] `T`.
372    ///
373    /// This is semantically equivalent to a safe downcast.
374    pub fn from_any(object: ObjectWorldRef<'w>) -> Option<Self>
375    where
376        T: Component,
377    {
378        Some(Self {
379            instance: Instance::from_entity(object.as_entity())?,
380            world: object.world,
381        })
382    }
383
384    /// See [`EntityRef::get`].
385    pub fn get<U: Component>(&self) -> Option<&U> {
386        self.world.get::<U>(self.entity())
387    }
388
389    /// See [`EntityRef::contains`].
390    pub fn contains<U: Component>(&self) -> bool {
391        self.world.entity(self.entity()).contains::<U>()
392    }
393
394    /// Returns the object as an [`Instance<T>`].
395    pub fn instance(&self) -> Instance<T> {
396        self.instance
397    }
398
399    /// Returns the object as an [`Entity`].
400    pub fn entity(&self) -> Entity {
401        self.instance.entity()
402    }
403
404    /// Returns the object as an [`EntityRef`].
405    pub fn as_entity(&self) -> EntityRef<'w> {
406        self.world.entity(self.entity())
407    }
408}
409
410impl<T: Kind> ContainsInstance<T> for ObjectWorldRef<'_, T> {
411    fn instance(&self) -> Instance<T> {
412        self.instance
413    }
414}
415
416impl<T: Kind> Clone for ObjectWorldRef<'_, T> {
417    fn clone(&self) -> Self {
418        *self
419    }
420}
421
422impl<T: Kind> Copy for ObjectWorldRef<'_, T> {}
423
424impl<T: Kind> From<ObjectWorldRef<'_, T>> for Entity {
425    fn from(object: ObjectWorldRef<'_, T>) -> Self {
426        object.entity()
427    }
428}
429
430impl<T: Kind> From<ObjectWorldRef<'_, T>> for Instance<T> {
431    fn from(object: ObjectWorldRef<'_, T>) -> Self {
432        object.instance()
433    }
434}
435
436impl<T: Kind, U: Kind> PartialEq<ObjectWorldRef<'_, U>> for ObjectWorldRef<'_, T> {
437    fn eq(&self, other: &ObjectWorldRef<U>) -> bool {
438        self.instance == other.instance
439    }
440}
441
442impl<T: Kind> Eq for ObjectWorldRef<'_, T> {}
443
444impl<T: Kind> PartialEq<Instance<T>> for ObjectWorldRef<'_, T> {
445    fn eq(&self, other: &Instance<T>) -> bool {
446        self.instance() == *other
447    }
448}
449
450impl<T: Kind> PartialEq<ObjectWorldRef<'_, T>> for Instance<T> {
451    fn eq(&self, other: &ObjectWorldRef<T>) -> bool {
452        *self == other.instance()
453    }
454}
455
456impl<T: Kind> PartialEq<Entity> for ObjectWorldRef<'_, T> {
457    fn eq(&self, other: &Entity) -> bool {
458        self.entity() == *other
459    }
460}
461
462impl<T: Kind> PartialEq<ObjectWorldRef<'_, T>> for Entity {
463    fn eq(&self, other: &ObjectWorldRef<T>) -> bool {
464        *self == other.entity()
465    }
466}
467
468impl<T: Kind> fmt::Debug for ObjectWorldRef<'_, T> {
469    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470        if let Some(name) = self.name() {
471            write!(f, "{}({:?}, \"{}\")", &T::debug_name(), self.entity(), name)
472        } else {
473            write!(f, "{}({:?})", &T::debug_name(), self.entity())
474        }
475    }
476}
477
478impl<T: Kind> fmt::Display for ObjectWorldRef<'_, T> {
479    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
480        if let Some(name) = self.name() {
481            write!(f, "{}({}, \"{}\")", &T::debug_name(), self.entity(), name)
482        } else {
483            write!(f, "{}({})", &T::debug_name(), self.entity())
484        }
485    }
486}
487
488impl<T: Component> Deref for ObjectWorldRef<'_, T> {
489    type Target = T;
490
491    fn deref(&self) -> &Self::Target {
492        self.world.get::<T>(self.entity()).unwrap()
493    }
494}
495
496/// Trait used to access an [`ObjectWorldRef`] from [`World`].
497pub trait GetObject {
498    /// Returns an [`ObjectWorldRef`] bounds to the given [`Entity`].
499    ///
500    /// # Safety
501    ///
502    /// This method will [`panic!`] if given entity is invalid.
503    /// See [`get_object`](GetObject::get_object) for a safer alternative.
504    fn object(&'_ self, entity: Entity) -> ObjectWorldRef<'_>;
505
506    /// Returns an [`ObjectWorldRef`] bounds to the given [`Entity`], if it exists.
507    fn get_object(&'_ self, entity: Entity) -> Result<ObjectWorldRef<'_>, EntityDoesNotExistError>;
508}
509
510impl GetObject for World {
511    fn object(&'_ self, entity: Entity) -> ObjectWorldRef<'_> {
512        ObjectWorldRef {
513            instance: self.entity(entity).id().into(),
514            world: self,
515        }
516    }
517
518    fn get_object(&'_ self, entity: Entity) -> Result<ObjectWorldRef<'_>, EntityDoesNotExistError> {
519        Ok(ObjectWorldRef {
520            instance: self.get_entity(entity)?.id().into(),
521            world: self,
522        })
523    }
524}
525
526#[cfg(test)]
527mod tests {
528    use super::*;
529
530    use bevy::ecs::system::RunSystemOnce;
531
532    #[test]
533    fn find_by_path() {
534        let mut w = World::new();
535
536        //     A
537        //    /
538        //   B
539        //  / \
540        // C   D
541
542        let (a, b, c, d) = w
543            .run_system_once(|mut commands: Commands| {
544                let a = commands.spawn(Name::new("A")).id();
545                let b = commands.spawn(Name::new("B")).id();
546                let c = commands.spawn(Name::new("C")).id();
547                let d = commands.spawn(Name::new("D")).id();
548
549                commands.entity(a).add_children(&[b]);
550                commands.entity(b).add_children(&[c, d]);
551
552                (a, b, c, d)
553            })
554            .unwrap();
555
556        w.run_system_once(move |objects: Objects| {
557            let x = objects.get(a).unwrap().find_by_path("").unwrap();
558            assert_eq!(a, x);
559            assert_eq!(x.path(), "A");
560        })
561        .unwrap();
562
563        w.run_system_once(move |objects: Objects| {
564            let x = objects.get(a).unwrap().find_by_path(".").unwrap();
565            assert_eq!(a, x);
566            assert_eq!(x.path(), "A");
567        })
568        .unwrap();
569
570        w.run_system_once(move |objects: Objects| {
571            let x = objects.get(a).unwrap().find_by_path("B").unwrap();
572            assert_eq!(b, x);
573            assert_eq!(x.path(), "A/B");
574        })
575        .unwrap();
576
577        w.run_system_once(move |objects: Objects| {
578            let x = objects.get(a).unwrap().find_by_path("B/C").unwrap();
579            assert_eq!(c, x);
580            assert_eq!(x.path(), "A/B/C");
581        })
582        .unwrap();
583
584        w.run_system_once(move |objects: Objects| {
585            let x = objects.get(a).unwrap().find_by_path("B/D").unwrap();
586            assert_eq!(d, x);
587            assert_eq!(x.path(), "A/B/D");
588        })
589        .unwrap();
590
591        w.run_system_once(move |objects: Objects| {
592            let x = objects.get(a).unwrap().find_by_path("B/*").unwrap();
593            assert_eq!(c, x);
594            assert_eq!(x.path(), "A/B/C");
595        })
596        .unwrap();
597
598        w.run_system_once(move |objects: Objects| {
599            let x = objects.get(a).unwrap().find_by_path("*/D").unwrap();
600            assert_eq!(d, x);
601            assert_eq!(x.path(), "A/B/D");
602        })
603        .unwrap();
604
605        w.run_system_once(move |objects: Objects| {
606            let x = objects.get(a).unwrap().find_by_path("*/*").unwrap();
607            assert_eq!(c, x);
608            assert_eq!(x.path(), "A/B/C");
609        })
610        .unwrap();
611
612        w.run_system_once(move |objects: Objects| {
613            let x = objects.get(b).unwrap().find_by_path("..").unwrap();
614            assert_eq!(a, x);
615            assert_eq!(x.path(), "A");
616        })
617        .unwrap();
618
619        w.run_system_once(move |objects: Objects| {
620            let x = objects.get(c).unwrap().find_by_path("..").unwrap();
621            assert_eq!(b, x);
622            assert_eq!(x.path(), "A/B");
623        })
624        .unwrap();
625
626        w.run_system_once(move |objects: Objects| {
627            let x = objects.get(c).unwrap().find_by_path("../D").unwrap();
628            assert_eq!(d, x);
629            assert_eq!(x.path(), "A/B/D");
630        })
631        .unwrap();
632
633        w.run_system_once(move |objects: Objects| {
634            let x = objects.get(c).unwrap().find_by_path("../C").unwrap();
635            assert_eq!(c, x);
636            assert_eq!(x.path(), "A/B/C");
637        })
638        .unwrap();
639    }
640
641    #[test]
642    fn object_ref() {
643        #[derive(Component)]
644        struct T;
645
646        let mut w = World::new();
647        let entity = w.spawn(T).id();
648
649        assert!(w
650            .run_system_once(move |world: &World, objects: Objects<T>| {
651                objects
652                    .get_single_ref(world.entity(entity))
653                    .unwrap()
654                    .contains::<T>()
655            })
656            .unwrap());
657    }
658
659    #[test]
660    fn world_object_ref() {
661        #[derive(Component)]
662        struct T;
663
664        let mut w = World::new();
665        let entity = w.spawn(T).id();
666
667        let object = ObjectWorldRef::<T>::from_any(w.object(entity)).unwrap();
668
669        assert_eq!(object, entity);
670    }
671
672    #[test]
673    fn root_objects() {
674        #[derive(Component)]
675        struct T;
676
677        //     A
678        //    /
679        //   B
680        //  / \
681        // C   D
682
683        let mut w = World::new();
684        let root = w
685            .spawn(T) /* A */
686            .with_children(|children| {
687                children.spawn(T /* B */).with_children(|children| {
688                    children.spawn(T /* C */);
689                    children.spawn(T /* D */);
690                });
691            })
692            .id();
693
694        assert!(w
695            .run_system_once(move |objects: RootObjects<T>| {
696                assert_eq!(objects.iter().count(), 1);
697                assert!(objects.contains(root));
698                assert!(objects.get_single().is_ok());
699                true
700            })
701            .unwrap());
702    }
703}