brood/query/
mod.rs

1//! Queries over [`World`]s.
2//!
3//! Entities within a `World` are difficult to interact with directly due to being made of
4//! heterogeneous lists of [`Component`]s. Therefore, queries can be executed to give [`Views`] of
5//! `Component`s within the entities stored in a `World`.
6//!
7//! Queries are made up of `Views`, giving access to `Component`s, and [`Filter`]s which can filter
8//! which entities are viewed. Query results are returned as heterogeneous lists, so the
9//! [`result!`] macro is provided to unpack the results.
10//!
11//! # Example
12//! The below example queries mutably for the component `Foo`, immutably for the component `Bar`,
13//! and filters out entities that do not have the component `Baz`.
14//!
15//! ``` rust
16//! use brood::{
17//!     entity,
18//!     query::{
19//!         filter,
20//!         result,
21//!         Views,
22//!     },
23//!     Query,
24//!     Registry,
25//!     World,
26//! };
27//!
28//! // Define components.
29//! struct Foo(u32);
30//! struct Bar(bool);
31//! struct Baz(f64);
32//!
33//! type Registry = Registry!(Foo, Bar, Baz);
34//!
35//! let mut world = World::<Registry>::new();
36//! world.insert(entity!(Foo(42), Bar(true), Baz(1.5)));
37//!
38//! for result!(foo, bar) in world
39//!     .query(Query::<Views!(&mut Foo, &Bar), filter::Has<Baz>>::new())
40//!     .iter
41//! {
42//!     // Do something.
43//! }
44//! ```
45//!
46//! [`Component`]: crate::component::Component
47//! [`Filter`]: crate::query::filter::Filter
48//! [`result!`]: crate::query::result!
49//! [`Views`]: trait@crate::query::view::Views
50//! [`World`]: crate::world::World
51
52pub mod entries;
53pub mod filter;
54pub mod result;
55pub mod view;
56
57#[doc(inline)]
58pub use entries::Entries;
59#[doc(inline)]
60pub use result::{
61    result,
62    Result,
63};
64#[doc(inline)]
65pub use view::inner::Views;
66
67use core::{
68    fmt,
69    marker::PhantomData,
70};
71
72/// Defines a query to be run over a world.
73///
74/// This defines either a regular or parallel query (parallel requires the `rayon` feature to be
75/// enabled). It is essentially a marker type, simply providing the types to the calls to
76/// [`query()`] to make the API as simple to use as possible.
77///
78/// # Example
79/// ``` rust
80/// use brood::{
81///     entity,
82///     query::{
83///         filter,
84///         result,
85///         Views,
86///     },
87///     Query,
88///     Registry,
89///     World,
90/// };
91///
92/// // Define components.
93/// struct Foo(u32);
94/// struct Bar(bool);
95/// struct Baz(f64);
96///
97/// type Registry = Registry!(Foo, Bar, Baz);
98///
99/// let mut world = World::<Registry>::new();
100/// world.insert(entity!(Foo(42), Bar(true), Baz(1.5)));
101///
102/// for result!(foo, bar) in world
103///     .query(Query::<Views!(&mut Foo, &Bar), filter::Has<Baz>>::new())
104///     .iter
105/// {
106///     // Do something.
107/// }
108/// ```
109///
110/// [`query()`]: crate::world::World::query()
111pub struct Query<Views, Filters = filter::None, ResourceViews = view::Null, EntryViews = view::Null>
112{
113    view: PhantomData<Views>,
114    filter: PhantomData<Filters>,
115    resource_views: PhantomData<ResourceViews>,
116    entry_views: PhantomData<EntryViews>,
117}
118
119impl<Views, Filters, ResourceViews, EntryViews> Query<Views, Filters, ResourceViews, EntryViews> {
120    /// Creates a new `Query`.
121    ///
122    /// When creating a query, you must specify the views type `V`, and can optionally specify the
123    /// filter type `F`. If no filter is specified, the default filter, [`filter::None`], will be
124    /// used.
125    #[must_use]
126    pub fn new() -> Self {
127        Self {
128            view: PhantomData,
129            filter: PhantomData,
130            resource_views: PhantomData,
131            entry_views: PhantomData,
132        }
133    }
134}
135
136impl<Views, Filters, ResourceViews, EntryViews> Default
137    for Query<Views, Filters, ResourceViews, EntryViews>
138{
139    fn default() -> Self {
140        Self::new()
141    }
142}
143
144impl<Views, Filters, ResourceViews, EntryViews> Clone
145    for Query<Views, Filters, ResourceViews, EntryViews>
146{
147    fn clone(&self) -> Self {
148        *self
149    }
150}
151
152impl<Views, Filters, ResourceViews, EntryViews> PartialEq
153    for Query<Views, Filters, ResourceViews, EntryViews>
154{
155    fn eq(&self, _other: &Self) -> bool {
156        true
157    }
158}
159
160impl<Views, Filters, ResourceViews, EntryViews> Eq
161    for Query<Views, Filters, ResourceViews, EntryViews>
162{
163}
164
165impl<Views, Filters, ResourceViews, EntryViews> Copy
166    for Query<Views, Filters, ResourceViews, EntryViews>
167{
168}
169
170impl<Views, Filters, ResourceViews, EntryViews> fmt::Debug
171    for Query<Views, Filters, ResourceViews, EntryViews>
172{
173    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
174        formatter.debug_struct("Query").finish()
175    }
176}
177
178#[cfg(test)]
179mod tests {
180    use super::Query;
181    use crate::query::Views;
182    use alloc::format;
183
184    #[test]
185    fn query_default() {
186        assert_eq!(Query::<Views!()>::default(), Query::<Views!()>::new());
187    }
188
189    #[test]
190    fn query_clone() {
191        let query = Query::<Views!()>::new();
192
193        assert_eq!(query.clone(), query);
194    }
195
196    #[test]
197    fn query_debug() {
198        assert_eq!(format!("{:?}", Query::<Views!()>::new()), "Query");
199    }
200}