hobo/
query.rs

1//! Queries allow finding entities across the hierarchy
2//! # Examples
3//!
4//! ```
5//! struct Foo {
6//!     // some fields
7//! }
8//!
9//! // find the first (presumably only) entity with some component Foo
10//! let (entity, _) = hobo::find_one::<(Entity, With<Foo>)>();
11//! let element = SomeElement(entity);
12//! element.set_text("This entity has Foo");
13//! ```
14//!
15//! ```
16//! struct Frobnicator {
17//!     num_fraculations: u32,
18//!     // other fields
19//! }
20//!
21//! // find all entities with a Frobnicator component and mutate it
22//! // perhaps as a result of some combined transformation
23//! for frobnicator in hobo::find::<&mut Frobnicator>() {
24//!     frobnicator.num_fraculations += 1;
25//! }
26//! ```
27
28#![allow(unused_variables)]
29
30use crate::{prelude::*, StorageRef, StorageRefMut};
31use owning_ref::{OwningRef, OwningRefMut};
32use std::collections::BTreeSet;
33
34pub trait Query {
35	type Fetch;
36
37	// either populate `entities` if it's None or filter out all entities not satisfying the predicate (like having a particular component)
38	fn filter(world: &World, entities: &mut Option<BTreeSet<Entity>>) {}
39	fn fetch(world: &World, entity: Entity) -> Self::Fetch;
40}
41
42impl Query for Entity {
43	type Fetch = Entity;
44
45	fn fetch(world: &World, entity: Entity) -> Self::Fetch { entity }
46}
47
48impl Query for Element {
49	type Fetch = Element;
50
51	fn filter(world: &World, entities: &mut Option<BTreeSet<Entity>>) { <&web_sys::Element as Query>::filter(world, entities); }
52	fn fetch(world: &World, entity: Entity) -> Self::Fetch { Element(entity) }
53}
54
55// same search as &Component, but fetch is a noop
56pub struct With<Component: 'static>(std::marker::PhantomData<Component>);
57impl<Component: 'static> Query for With<Component> {
58	type Fetch = ();
59
60	fn filter(world: &World, entities: &mut Option<BTreeSet<Entity>>) { <&Component as Query>::filter(world, entities); }
61
62	fn fetch(world: &World, entity: Entity) -> Self::Fetch {}
63}
64
65impl<Component: 'static> Query for &Component {
66	type Fetch = OwningRef<Box<dyn owning_ref::Erased>, Component>;
67
68	fn filter(world: &World, entities: &mut Option<BTreeSet<Entity>>) {
69		let storage = world.storage::<Component>();
70		if let Some(entities) = entities {
71			entities.retain(|entity| storage.has(entity));
72		} else {
73			*entities = Some(storage.data.keys().copied().collect());
74		}
75	}
76
77	fn fetch(world: &World, entity: Entity) -> Self::Fetch {
78		let storage: StorageRef<Component> = OwningRef::new(world.dyn_storage::<Component>())
79			.map(|x| x.as_any().downcast_ref().unwrap());
80
81		storage
82			.map(|x| x.get(entity).unwrap())
83			.map_owner_box().erase_owner()
84	}
85}
86
87impl<Component: 'static> Query for &mut Component {
88	type Fetch = OwningRefMut<Box<dyn owning_ref::Erased>, Component>;
89
90	fn filter(world: &World, entities: &mut Option<BTreeSet<Entity>>) { <&Component as Query>::filter(world, entities); }
91
92	fn fetch(world: &World, entity: Entity) -> Self::Fetch {
93		let storage: StorageRefMut<Component> = OwningRefMut::new(world.dyn_storage_mut::<Component>())
94			.map_mut(|x| x.as_any_mut().downcast_mut().unwrap());
95
96		storage
97			.map_mut(|x| x.get_mut(entity).unwrap())
98			.map_owner_box().erase_owner()
99	}
100}
101
102macro_rules! impl_for_tuples {
103	(($($_:ident),*)) => {};
104	(($($old:ident),*) $curr:ident $($rest:tt)*) => {
105		impl<$($old: Query,)* $curr: Query> Query for ($($old,)* $curr) {
106			type Fetch = ($($old::Fetch,)* $curr::Fetch);
107
108			fn filter(world: &World, entities: &mut Option<BTreeSet<Entity>>) {
109				$($old::filter(world, entities);)*
110				$curr::filter(world, entities);
111			}
112			fn fetch(world: &World, entity: Entity) -> Self::Fetch {
113				($($old::fetch(world, entity),)* $curr::fetch(world, entity))
114			}
115		}
116
117		impl_for_tuples![($($old,)* $curr) $($rest)*];
118	};
119	($first:ident $($rest:tt)*) => {
120		impl_for_tuples![($first) $($rest)*];
121	};
122}
123
124impl_for_tuples![A B C D E F G H I J K L M N O P Q R S T U V W X Y Z];