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#[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 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 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 pub fn instance(&self, instance: Instance<T>) -> Object<'w, 's, '_, T> {
89 self.get(instance.entity()).expect("instance must be valid")
90 }
91}
92
93pub 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 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 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 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 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}