Skip to content

Commit 0d1dbe3

Browse files
committed
Update naming and the docs
1 parent 02000e5 commit 0d1dbe3

File tree

3 files changed

+141
-44
lines changed

3 files changed

+141
-44
lines changed

crates/bevy_ecs/macros/src/fetch.rs

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ pub fn derive_fetch_impl(input: TokenStream) -> TokenStream {
2323
impl_generics,
2424
ty_generics,
2525
where_clause,
26-
struct_has_world_lt,
27-
world_lt,
28-
state_lt,
26+
struct_has_world_lifetime,
27+
world_lifetime,
28+
state_lifetime,
2929
} = fetch_impl_tokens(&ast);
3030

3131
// Fetch's HRTBs require this hack to make the implementation compile. I don't fully understand
@@ -34,9 +34,9 @@ pub fn derive_fetch_impl(input: TokenStream) -> TokenStream {
3434
// - https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=da5e260a5c2f3e774142d60a199e854a (this fails)
3535
// - https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=802517bb3d8f83c45ee8c0be360bb250 (this compiles)
3636
let mut fetch_generics = ast.generics.clone();
37-
fetch_generics.params.insert(0, state_lt);
38-
if !struct_has_world_lt {
39-
fetch_generics.params.insert(0, world_lt);
37+
fetch_generics.params.insert(0, state_lifetime);
38+
if !struct_has_world_lifetime {
39+
fetch_generics.params.insert(0, world_lifetime);
4040
}
4141
fetch_generics
4242
.params
@@ -46,7 +46,7 @@ pub fn derive_fetch_impl(input: TokenStream) -> TokenStream {
4646
))));
4747
let (fetch_impl_generics, _, _) = fetch_generics.split_for_impl();
4848
let mut fetch_generics = ast.generics.clone();
49-
if struct_has_world_lt {
49+
if struct_has_world_lifetime {
5050
*fetch_generics.params.first_mut().unwrap() =
5151
GenericParam::Lifetime(LifetimeDef::new(Lifetime::new("'fetch", Span::call_site())));
5252
}
@@ -142,9 +142,9 @@ pub fn derive_fetch_impl(input: TokenStream) -> TokenStream {
142142
/// SAFETY: each item in the struct is read only
143143
unsafe impl #impl_generics #path::query::ReadOnlyFetch for #fetch_struct_name #ty_generics #where_clause {}
144144

145-
// Statically checks that the safety guarantee holds true indeed. We need this to make
146-
// sure that we don't compile ReadOnlyFetch if our struct contains nested WorldQuery
147-
// that don't implement it.
145+
// Statically checks that the safety guarantee actually holds true. We need this to make
146+
// sure that we don't compile `ReadOnlyFetch` if our struct contains nested `WorldQuery`
147+
// members that don't implement it.
148148
#[allow(dead_code)]
149149
const _: () = {
150150
fn assert_readonly<T: #path::query::ReadOnlyFetch>() {}
@@ -183,16 +183,20 @@ pub fn derive_fetch_impl(input: TokenStream) -> TokenStream {
183183
true #(&& self.#field_idents.is_dense())*
184184
}
185185

186+
/// SAFETY: we call `set_archetype` for each member that implements `Fetch`
186187
#[inline]
187188
unsafe fn set_archetype(&mut self, _state: &Self::State, _archetype: &#path::archetype::Archetype, _tables: &#path::storage::Tables) {
188189
#(self.#field_idents.set_archetype(&_state.#field_idents, _archetype, _tables);)*
189190
}
190191

192+
/// SAFETY: we call `set_table` for each member that implements `Fetch`
191193
#[inline]
192194
unsafe fn set_table(&mut self, _state: &Self::State, _table: &#path::storage::Table) {
193195
#(self.#field_idents.set_table(&_state.#field_idents, _table);)*
194196
}
195197

198+
/// SAFETY: we call `table_fetch` for each member that implements `Fetch` or
199+
/// `table_filter_fetch` if it also implements `FilterFetch`.
196200
#[inline]
197201
unsafe fn table_fetch(&mut self, _table_row: usize) -> Self::Item {
198202
use #path::query::FilterFetch;
@@ -203,6 +207,8 @@ pub fn derive_fetch_impl(input: TokenStream) -> TokenStream {
203207
}
204208
}
205209

210+
/// SAFETY: we call `archetype_fetch` for each member that implements `Fetch` or
211+
/// `archetype_filter_fetch` if it also implements `FilterFetch`.
206212
#[inline]
207213
unsafe fn archetype_fetch(&mut self, _archetype_index: usize) -> Self::Item {
208214
use #path::query::FilterFetch;
@@ -214,7 +220,7 @@ pub fn derive_fetch_impl(input: TokenStream) -> TokenStream {
214220
}
215221
}
216222

217-
// SAFETY: update_component_access and update_archetype_component_access are called for each item in the struct
223+
// SAFETY: `update_component_access` and `update_archetype_component_access` are called for each item in the struct
218224
unsafe impl #impl_generics #path::query::FetchState for #state_struct_name #ty_generics #where_clause {
219225
fn init(world: &mut #path::world::World) -> Self {
220226
#state_struct_name {
@@ -260,9 +266,9 @@ pub fn derive_filter_fetch_impl(input: TokenStream) -> TokenStream {
260266
impl_generics,
261267
ty_generics,
262268
where_clause,
263-
struct_has_world_lt,
264-
world_lt,
265-
state_lt,
269+
struct_has_world_lifetime,
270+
world_lifetime,
271+
state_lifetime,
266272
} = fetch_impl_tokens(&ast);
267273

268274
// Fetch's HRTBs require this hack to make the implementation compile. I don't fully understand
@@ -271,9 +277,9 @@ pub fn derive_filter_fetch_impl(input: TokenStream) -> TokenStream {
271277
// - https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=da5e260a5c2f3e774142d60a199e854a (this fails)
272278
// - https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=802517bb3d8f83c45ee8c0be360bb250 (this compiles)
273279
let mut fetch_generics = ast.generics.clone();
274-
fetch_generics.params.insert(0, state_lt);
275-
if !struct_has_world_lt {
276-
fetch_generics.params.insert(0, world_lt);
280+
fetch_generics.params.insert(0, state_lifetime);
281+
if !struct_has_world_lifetime {
282+
fetch_generics.params.insert(0, world_lifetime);
277283
}
278284
fetch_generics
279285
.params
@@ -283,7 +289,7 @@ pub fn derive_filter_fetch_impl(input: TokenStream) -> TokenStream {
283289
))));
284290
let (fetch_impl_generics, _, _) = fetch_generics.split_for_impl();
285291
let mut fetch_generics = ast.generics.clone();
286-
if struct_has_world_lt {
292+
if struct_has_world_lifetime {
287293
*fetch_generics.params.first_mut().unwrap() =
288294
GenericParam::Lifetime(LifetimeDef::new(Lifetime::new("'fetch", Span::call_site())));
289295
}
@@ -410,6 +416,7 @@ pub fn derive_filter_fetch_impl(input: TokenStream) -> TokenStream {
410416
tokens
411417
}
412418

419+
// This struct is used to share common tokens between `Fetch` and `FilterFetch` implementations.
413420
struct FetchImplTokens<'a> {
414421
struct_name: Ident,
415422
fetch_struct_name: Ident,
@@ -418,26 +425,26 @@ struct FetchImplTokens<'a> {
418425
impl_generics: ImplGenerics<'a>,
419426
ty_generics: TypeGenerics<'a>,
420427
where_clause: Option<&'a WhereClause>,
421-
struct_has_world_lt: bool,
422-
world_lt: GenericParam,
423-
state_lt: GenericParam,
428+
struct_has_world_lifetime: bool,
429+
world_lifetime: GenericParam,
430+
state_lifetime: GenericParam,
424431
}
425432

426433
fn fetch_impl_tokens(ast: &DeriveInput) -> FetchImplTokens {
427-
let world_lt = ast.generics.params.first().and_then(|param| match param {
434+
let world_lifetime = ast.generics.params.first().and_then(|param| match param {
428435
lt @ GenericParam::Lifetime(_) => Some(lt.clone()),
429436
_ => None,
430437
});
431-
let struct_has_world_lt = world_lt.is_some();
432-
let world_lt = world_lt.unwrap_or_else(|| {
438+
let struct_has_world_lifetime = world_lifetime.is_some();
439+
let world_lifetime = world_lifetime.unwrap_or_else(|| {
433440
GenericParam::Lifetime(LifetimeDef::new(Lifetime::new("'world", Span::call_site())))
434441
});
435-
let state_lt =
442+
let state_lifetime =
436443
GenericParam::Lifetime(LifetimeDef::new(Lifetime::new("'state", Span::call_site())));
437444

438445
let mut fetch_trait_punctuated_lifetimes = Punctuated::<_, Token![,]>::new();
439-
fetch_trait_punctuated_lifetimes.push(world_lt.clone());
440-
fetch_trait_punctuated_lifetimes.push(state_lt.clone());
446+
fetch_trait_punctuated_lifetimes.push(world_lifetime.clone());
447+
fetch_trait_punctuated_lifetimes.push(state_lifetime.clone());
441448

442449
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
443450

@@ -453,9 +460,9 @@ fn fetch_impl_tokens(ast: &DeriveInput) -> FetchImplTokens {
453460
impl_generics,
454461
ty_generics,
455462
where_clause,
456-
struct_has_world_lt,
457-
world_lt,
458-
state_lt,
463+
struct_has_world_lifetime,
464+
world_lifetime,
465+
state_lifetime,
459466
}
460467
}
461468

crates/bevy_ecs/src/query/fetch.rs

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ use std::{
2222
///
2323
/// See [`Query`](crate::system::Query) for a primer on queries.
2424
///
25+
/// If you want to implement a custom query, see [`Fetch`] trait documentation.
26+
///
27+
/// If you want to implement a custom query filter, see [`FilterFetch`] trait documentation.
28+
///
2529
/// # Basic WorldQueries
2630
///
2731
/// Here is a small list of the most important world queries to know about where `C` stands for a
@@ -46,19 +50,47 @@ pub trait WorldQuery {
4650
type State: FetchState;
4751
}
4852

53+
/// Types that implement this trait are responsible for fetching query items from tables or
54+
/// archetypes.
55+
///
56+
/// Every type that implements [`WorldQuery`] have their associated [`WorldQuery::Fetch`] and
57+
/// [`WorldQuery::State`] types that are essential for fetching component data. If you want to
58+
/// implement a custom query type, you'll need to implement [`Fetch`] and [`FetchState`] for
59+
/// those associated types.
60+
///
61+
/// You may want to implement a custom query for the following reasons:
62+
/// - Named structs can be easier to use than complex query tuples. Access via struct fields
63+
/// is more convenient than destructuring tuples or accessing them via `q.0, q.1, ...` pattern
64+
/// and saves a lot of maintenance burden when adding or removing components.
65+
/// - Nested queries enable the composition pattern and makes query types easier to re-use.
66+
/// - It allows to go over the limit of 15 components that exists for query tuples.
67+
///
4968
/// # Derive
5069
///
5170
/// This trait can be derived with the [`derive@super::Fetch`] macro.
5271
/// To do so, all fields in the struct must themselves impl [`WorldQuery`].
5372
///
73+
/// The derive macro implements [`WorldQuery`] for your type and declares two structs that
74+
/// implement [`Fetch`] and [`FetchState`] and are used as [`WorldQuery::Fetch`] and
75+
/// [`WorldQuery::State`] associated types respectively.
76+
///
77+
/// **Note:** currently, the macro only supports named structs.
78+
///
5479
/// ```
5580
/// # use bevy_ecs::prelude::*;
5681
/// use bevy_ecs::query::Fetch;
5782
///
83+
/// struct Foo;
84+
/// struct Bar;
85+
/// struct OptionalFoo;
86+
/// struct OptionalBar;
87+
///
5888
/// #[derive(Fetch)]
5989
/// struct MyQuery<'w> {
60-
/// foo: &'w u32,
61-
/// bar: Mut<'w, i32>,
90+
/// foo: &'w Foo,
91+
/// bar: Mut<'w, Bar>,
92+
/// optional_foo: Option<&'w OptionalFoo>,
93+
/// optional_bar: Option<Mut<'w, OptionalBar>>,
6294
/// }
6395
///
6496
/// fn my_system(mut query: Query<MyQuery>) {
@@ -74,19 +106,55 @@ pub trait WorldQuery {
74106
///
75107
/// All filter members must be marked with `filter` attribute and have `bool` type.
76108
///
109+
/// **Note:** values of filter members will always be `true`, which means that the entities that
110+
/// don't meet filter requirements, won't be accessed. If you want to check, for instance, whether
111+
/// a component exists or not, use `Option<&T>` instead of filters.
112+
///
77113
/// ```
78114
/// # use bevy_ecs::prelude::*;
79115
/// use bevy_ecs::query::Fetch;
80116
///
117+
/// struct Foo;
118+
/// struct Bar;
119+
///
81120
/// #[derive(Fetch)]
82121
/// struct MyQuery<'w> {
83-
/// foo: &'w u32,
84-
/// bar: Mut<'w, i32>,
85-
/// #[filter(Changed<u32>)]
122+
/// foo: &'w Foo,
123+
/// bar: Mut<'w, Bar>,
124+
/// #[filter(Changed<Foo>)]
86125
/// foo_is_changed: bool,
87126
/// }
88127
/// ```
89128
///
129+
/// ## Nested queries
130+
///
131+
/// Using nested queries enable the composition pattern, which makes it possible to re-use other
132+
/// query types. All types that implement [`WorldQuery`] (including the ones that use this derive
133+
/// macro) are supported.
134+
///
135+
/// ```
136+
/// # use bevy_ecs::prelude::*;
137+
/// use bevy_ecs::query::Fetch;
138+
///
139+
/// struct Foo;
140+
/// struct Bar;
141+
/// struct OptionalFoo;
142+
/// struct OptionalBar;
143+
///
144+
/// #[derive(Fetch)]
145+
/// struct MyQuery<'w> {
146+
/// foo: FooQuery<'w>,
147+
/// bar: (&'w Bar, Option<&'w OptionalBar>)
148+
/// }
149+
///
150+
/// #[derive(Fetch)]
151+
/// struct FooQuery<'w> {
152+
/// foo: &'w Foo,
153+
/// optional_foo: Option<&'w OptionalFoo>,
154+
/// }
155+
///
156+
/// ```
157+
///
90158
/// ## Read-only queries
91159
///
92160
/// All queries that access components non-mutably are read-only by default, with the exception
@@ -98,41 +166,47 @@ pub trait WorldQuery {
98166
/// # use bevy_ecs::prelude::*;
99167
/// use bevy_ecs::query::{Fetch, ReadOnlyFetch, WorldQuery};
100168
///
169+
/// struct Foo;
170+
/// struct Bar;
171+
///
101172
/// #[derive(Fetch)]
102173
/// struct FooQuery<'w> {
103-
/// foo: &'w u32,
174+
/// foo: &'w Foo,
104175
/// #[readonly]
105176
/// bar_query: BarQuery<'w>,
106177
/// }
107178
///
108179
/// #[derive(Fetch)]
109180
/// struct BarQuery<'w> {
110-
/// bar: &'w u32,
181+
/// bar: &'w Bar,
111182
/// }
112183
///
113184
/// fn assert_readonly<T: ReadOnlyFetch>() {}
114185
///
115186
/// assert_readonly::<<FooQuery as WorldQuery>::Fetch>();
116187
/// ```
117188
///
118-
/// **Note** that if you mark a field that doesn't implement `ReadOnlyFetch` as `readonly`, the
189+
/// **Note:** if you mark a field that doesn't implement `ReadOnlyFetch` as `readonly`,
119190
/// compilation will fail. We insert static checks as in the example above for every nested query
120191
/// marked as `readonly`. (They neither affect the runtime, nor pollute your local namespace.)
121192
///
122193
/// ```compile_fail
123194
/// # use bevy_ecs::prelude::*;
124195
/// use bevy_ecs::query::{Fetch, ReadOnlyFetch, WorldQuery};
125196
///
197+
/// struct Foo;
198+
/// struct Bar;
199+
///
126200
/// #[derive(Fetch)]
127201
/// struct FooQuery<'w> {
128-
/// foo: &'w u32,
202+
/// foo: &'w Foo,
129203
/// #[readonly]
130204
/// bar_query: BarQuery<'w>,
131205
/// }
132206
///
133207
/// #[derive(Fetch)]
134208
/// struct BarQuery<'w> {
135-
/// bar: Mut<'w, u32>,
209+
/// bar: Mut<'w, Bar>,
136210
/// }
137211
/// ```
138212
pub trait Fetch<'world, 'state>: Sized {

crates/bevy_ecs/src/query/filter.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,42 @@ use std::{cell::UnsafeCell, marker::PhantomData, ptr};
1212
/// Extension trait for [`Fetch`] containing methods used by query filters.
1313
/// This trait exists to allow "short circuit" behaviors for relevant query filter fetches.
1414
///
15+
/// This trait is automatically implemented for every type that implements [`Fetch`] trait and
16+
/// specifies `bool` as the associated type for [`Fetch::Item`].
17+
///
18+
/// Using [`derive@super::FilterFetch`] macro allows creating custom query filters.
19+
/// You may want to implement a custom query filter for the following reasons:
20+
/// - Nested query filters enable the composition pattern and makes them easier to re-use.
21+
/// - It allows to go over the limit of 15 components that exists for query filters declared as
22+
/// tuples.
23+
///
1524
/// ## Derive
1625
///
1726
/// This trait can be derived with the [`derive@super::FilterFetch`] macro.
1827
/// To do so, all fields in the struct must be filters themselves (their [`WorldQuery::Fetch`]
1928
/// associated types should implement [`FilterFetch`]).
2029
///
30+
/// **Note:** currently, the macro only supports named structs.
31+
///
2132
/// ```
2233
/// # use bevy_ecs::prelude::*;
2334
/// use bevy_ecs::{query::FilterFetch, component::Component};
2435
///
36+
/// struct Foo;
37+
/// struct Bar;
38+
/// struct Baz;
39+
/// struct Qux;
40+
///
2541
/// #[derive(FilterFetch)]
2642
/// struct MyFilter<T: Component, P: Component> {
27-
/// _u_16: With<u16>,
28-
/// _u_32: With<u32>,
29-
/// _or: Or<(With<i16>, Changed<u16>, Added<u32>)>,
43+
/// _foo: With<Foo>,
44+
/// _bar: With<Bar>,
45+
/// _or: Or<(With<Baz>, Changed<Foo>, Added<Bar>)>,
3046
/// _generic_tuple: (With<T>, Without<P>),
3147
/// _tp: std::marker::PhantomData<(T, P)>,
3248
/// }
3349
///
34-
/// fn my_system(query: Query<Entity, MyFilter<u16, i16>>) {
50+
/// fn my_system(query: Query<Entity, MyFilter<Foo, Qux>>) {
3551
/// for _ in query.iter() {}
3652
/// }
3753
///

0 commit comments

Comments
 (0)