moonshine_object/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::{fmt, ops::Deref};
4
5use bevy_core::Name;
6use bevy_ecs::{
7    prelude::*,
8    query::{QueryEntityError, QueryFilter, QuerySingleError},
9    system::SystemParam,
10};
11use moonshine_kind::prelude::*;
12use moonshine_util::hierarchy::HierarchyQuery;
13
14pub mod prelude {
15    pub use super::{Object, ObjectRef, Objects};
16    pub use super::{ObjectHierarchy, ObjectInstance, ObjectName, ObjectRebind};
17}
18
19pub use moonshine_kind::{Any, CastInto, Kind};
20
21/// A [`SystemParam`] similar to [`Query`] which provides [`Object<T>`] access for its items.
22#[derive(SystemParam)]
23pub struct Objects<'w, 's, T = Any, F = ()>
24where
25    T: Kind,
26    F: 'static + QueryFilter,
27{
28    pub instance: Query<'w, 's, Instance<T>, F>,
29    pub hierarchy: HierarchyQuery<'w, 's>,
30    pub name: Query<'w, 's, &'static Name>,
31}
32
33impl<'w, 's, T, F> Objects<'w, 's, T, F>
34where
35    T: Kind,
36    F: 'static + QueryFilter,
37{
38    /// Iterates over all [`Object`]s of [`Kind`] `T` which match the [`QueryFilter`] `F`.
39    pub fn iter(&self) -> impl Iterator<Item = Object<'w, 's, '_, T>> {
40        self.instance.iter().map(|instance| Object {
41            instance,
42            hierarchy: &self.hierarchy,
43            name: &self.name,
44        })
45    }
46
47    pub fn contains(&self, entity: Entity) -> bool {
48        self.instance.contains(entity)
49    }
50
51    pub fn iter_ref<'a>(
52        &'a self,
53        world: &'a World,
54    ) -> impl Iterator<Item = ObjectRef<'w, 's, 'a, T>> {
55        self.iter()
56            .map(|object| ObjectRef(world.entity(object.entity()), object))
57    }
58
59    /// Gets the [`Object`] of [`Kind`] `T` from an [`Entity`], if it matches.
60    pub fn get(&self, entity: Entity) -> Result<Object<'w, 's, '_, T>, QueryEntityError> {
61        self.instance.get(entity).map(|instance| Object {
62            instance,
63            hierarchy: &self.hierarchy,
64            name: &self.name,
65        })
66    }
67
68    pub fn get_ref<'a>(&'a self, entity: EntityRef<'a>) -> Option<ObjectRef<'w, 's, 'a, T>> {
69        Some(ObjectRef(entity, self.get(entity.id()).ok()?))
70    }
71
72    pub fn get_single(&self) -> Result<Object<'w, 's, '_, T>, QuerySingleError> {
73        self.instance.get_single().map(|instance| Object {
74            instance,
75            hierarchy: &self.hierarchy,
76            name: &self.name,
77        })
78    }
79
80    pub fn get_single_ref<'a>(&'a self, entity: EntityRef<'a>) -> Option<ObjectRef<'w, 's, 'a, T>> {
81        Some(ObjectRef(entity, self.get_single().ok()?))
82    }
83
84    /// Gets the [`Object`] of [`Kind`] `T` from an [`Instance`].
85    ///
86    /// # Safety
87    /// Assumes `instance` is a valid [`Instance`] of [`Kind`] `T`.
88    pub fn instance(&self, instance: Instance<T>) -> Object<'w, 's, '_, T> {
89        self.get(instance.entity()).expect("instance must be valid")
90    }
91}
92
93/// Represents an [`Entity`] of [`Kind`] `T` with hierarchy and name information.
94pub struct Object<'w, 's, 'a, T: Kind = Any> {
95    instance: Instance<T>,
96    hierarchy: &'a HierarchyQuery<'w, 's>,
97    name: &'a Query<'w, 's, &'static Name>,
98}
99
100impl<'w, 's, 'a, T: Kind> Object<'w, 's, 'a, T> {
101    /// Creates a new [`Object<T>`] from an [`Object<Any>`].
102    ///
103    /// This is semantically equivalent to an unsafe downcast.
104    ///
105    /// # Safety
106    /// Assumes `base` is of [`Kind`] `T`.
107    pub unsafe fn from_base_unchecked(base: Object<'w, 's, 'a>) -> Self {
108        Self {
109            instance: base.instance.cast_into_unchecked(),
110            hierarchy: base.hierarchy,
111            name: base.name,
112        }
113    }
114}
115
116impl<'w, 's, 'a, T: Component> Object<'w, 's, 'a, T> {
117    pub fn from_base(world: &World, object: Object<'w, 's, 'a>) -> Option<Object<'w, 's, 'a, T>> {
118        let entity = world.entity(object.entity());
119        let instance = Instance::<T>::from_entity(entity)?;
120        // SAFE: Entity was just checked to a valid instance of T.
121        Some(object.rebind_as(instance))
122    }
123}
124
125impl<T: Kind> Clone for Object<'_, '_, '_, T> {
126    fn clone(&self) -> Self {
127        *self
128    }
129}
130
131impl<T: Kind> Copy for Object<'_, '_, '_, T> {}
132
133impl<T: Kind> From<Object<'_, '_, '_, T>> for Entity {
134    fn from(object: Object<'_, '_, '_, T>) -> Self {
135        object.entity()
136    }
137}
138
139impl<T: Kind> From<Object<'_, '_, '_, T>> for Instance<T> {
140    fn from(object: Object<'_, '_, '_, T>) -> Self {
141        object.instance()
142    }
143}
144
145impl<T: Kind> PartialEq for Object<'_, '_, '_, T> {
146    fn eq(&self, other: &Self) -> bool {
147        self.instance == other.instance
148    }
149}
150
151impl<T: Kind> Eq for Object<'_, '_, '_, T> {}
152
153impl<T: Kind> fmt::Debug for Object<'_, '_, '_, T> {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        let mut out = f.debug_tuple(&T::debug_name());
156        out.field(&self.entity());
157        if let Some(name) = self.name() {
158            out.field(&name);
159        }
160        out.finish()
161    }
162}
163
164pub struct ObjectRef<'w, 's, 'a, T: Kind = Any>(EntityRef<'a>, Object<'w, 's, 'a, T>);
165
166impl<T: Component> Deref for ObjectRef<'_, '_, '_, T> {
167    type Target = T;
168
169    fn deref(&self) -> &Self::Target {
170        self.0.get::<T>().unwrap()
171    }
172}
173
174impl<'w, 's, 'a, T: Kind> ObjectRef<'w, 's, 'a, T> {
175    pub fn get<U: Component>(&self) -> Option<&U> {
176        self.0.get::<U>()
177    }
178
179    pub fn contains<U: Component>(&self) -> bool {
180        self.0.contains::<U>()
181    }
182
183    /// Creates a new [`ObjectRef<T>`] from an [`ObjectRef<Any>`].
184    ///
185    /// This is semantically equivalent to an unsafe downcast.
186    ///
187    /// # Safety
188    /// Assumes `base` is of [`Kind`] `T`.
189    pub unsafe fn from_base_unchecked(base: ObjectRef<'w, 's, 'a>) -> Self {
190        Self(base.0, Object::from_base_unchecked(base.1))
191    }
192}
193
194impl<T: Kind> Clone for ObjectRef<'_, '_, '_, T> {
195    fn clone(&self) -> Self {
196        *self
197    }
198}
199
200impl<T: Kind> Copy for ObjectRef<'_, '_, '_, T> {}
201
202impl<T: Kind> From<ObjectRef<'_, '_, '_, T>> for Entity {
203    fn from(object: ObjectRef<'_, '_, '_, T>) -> Self {
204        object.entity()
205    }
206}
207
208impl<T: Kind> From<ObjectRef<'_, '_, '_, T>> for Instance<T> {
209    fn from(object: ObjectRef<'_, '_, '_, T>) -> Self {
210        object.instance()
211    }
212}
213
214impl<'w, 's, 'a, T: Kind> From<ObjectRef<'w, 's, 'a, T>> for Object<'w, 's, 'a, T> {
215    fn from(object: ObjectRef<'w, 's, 'a, T>) -> Self {
216        object.1
217    }
218}
219
220impl<'w, 's, 'a, T: Kind> From<&ObjectRef<'w, 's, 'a, T>> for Object<'w, 's, 'a, T> {
221    fn from(object: &ObjectRef<'w, 's, 'a, T>) -> Self {
222        object.1
223    }
224}
225
226impl<T: Kind> PartialEq for ObjectRef<'_, '_, '_, T> {
227    fn eq(&self, other: &Self) -> bool {
228        self.1 == other.1
229    }
230}
231
232impl<T: Kind> Eq for ObjectRef<'_, '_, '_, T> {}
233
234impl<T: Kind> fmt::Debug for ObjectRef<'_, '_, '_, T> {
235    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236        self.1.fmt(f)
237    }
238}
239
240mod hierarchy;
241mod instance;
242mod name;
243mod rebind;
244
245pub use hierarchy::*;
246pub use instance::*;
247pub use name::*;
248pub use rebind::*;
249
250#[cfg(test)]
251mod tests {
252    use super::*;
253
254    use bevy::{ecs::system::RunSystemOnce, prelude::*};
255
256    #[test]
257    fn find_by_path() {
258        let mut w = World::new();
259
260        //     A
261        //    /
262        //   B
263        //  / \
264        // C   D
265
266        let (a, b, c, d) = w
267            .run_system_once(|mut commands: Commands| {
268                let a = commands.spawn(Name::new("A")).id();
269                let b = commands.spawn(Name::new("B")).id();
270                let c = commands.spawn(Name::new("C")).id();
271                let d = commands.spawn(Name::new("D")).id();
272
273                commands.entity(a).add_children(&[b]);
274                commands.entity(b).add_children(&[c, d]);
275
276                (a, b, c, d)
277            })
278            .unwrap();
279
280        w.run_system_once(move |objects: Objects| {
281            let x = objects.get(a).unwrap().find_by_path("").unwrap().entity();
282            assert_eq!(a, x);
283        })
284        .unwrap();
285
286        w.run_system_once(move |objects: Objects| {
287            let x = objects.get(a).unwrap().find_by_path(".").unwrap().entity();
288            assert_eq!(a, x);
289        })
290        .unwrap();
291
292        w.run_system_once(move |objects: Objects| {
293            let x = objects.get(a).unwrap().find_by_path("B").unwrap().entity();
294            assert_eq!(b, x);
295        })
296        .unwrap();
297
298        w.run_system_once(move |objects: Objects| {
299            let x = objects
300                .get(a)
301                .unwrap()
302                .find_by_path("B/C")
303                .unwrap()
304                .entity();
305            assert_eq!(c, x);
306        })
307        .unwrap();
308
309        w.run_system_once(move |objects: Objects| {
310            let x = objects
311                .get(a)
312                .unwrap()
313                .find_by_path("B/D")
314                .unwrap()
315                .entity();
316            assert_eq!(d, x);
317        })
318        .unwrap();
319
320        w.run_system_once(move |objects: Objects| {
321            let x = objects
322                .get(a)
323                .unwrap()
324                .find_by_path("B/*")
325                .unwrap()
326                .entity();
327            assert_eq!(c, x);
328        })
329        .unwrap();
330
331        w.run_system_once(move |objects: Objects| {
332            let x = objects
333                .get(a)
334                .unwrap()
335                .find_by_path("*/D")
336                .unwrap()
337                .entity();
338            assert_eq!(d, x);
339        })
340        .unwrap();
341
342        w.run_system_once(move |objects: Objects| {
343            let x = objects
344                .get(a)
345                .unwrap()
346                .find_by_path("*/*")
347                .unwrap()
348                .entity();
349            assert_eq!(c, x);
350        })
351        .unwrap();
352
353        w.run_system_once(move |objects: Objects| {
354            let x = objects.get(b).unwrap().find_by_path("..").unwrap().entity();
355            assert_eq!(a, x);
356        })
357        .unwrap();
358
359        w.run_system_once(move |objects: Objects| {
360            let x = objects.get(c).unwrap().find_by_path("..").unwrap().entity();
361            assert_eq!(b, x);
362        })
363        .unwrap();
364
365        w.run_system_once(move |objects: Objects| {
366            let x = objects
367                .get(c)
368                .unwrap()
369                .find_by_path("../D")
370                .unwrap()
371                .entity();
372            assert_eq!(d, x);
373        })
374        .unwrap();
375
376        w.run_system_once(move |objects: Objects| {
377            let x = objects
378                .get(c)
379                .unwrap()
380                .find_by_path("../C")
381                .unwrap()
382                .entity();
383            assert_eq!(c, x);
384        })
385        .unwrap();
386    }
387
388    #[test]
389    fn object_ref() {
390        #[derive(Component)]
391        struct T;
392
393        let mut w = World::new();
394        let entity = w.spawn(T).id();
395
396        assert!(w
397            .run_system_once(move |world: &World, objects: Objects<T>| {
398                objects
399                    .get_single_ref(world.entity(entity))
400                    .unwrap()
401                    .contains::<T>()
402            })
403            .unwrap());
404    }
405}