bevy_trait_query/lib.rs
1//! Let's say you have a trait that you want to implement for some of your components.
2//!
3//! ```
4//! # use bevy::prelude::*;
5//! #
6//! /// Components that display a message when hovered.
7//! pub trait Tooltip {
8//! /// Text displayed when hovering over an entity with this trait.
9//! fn tooltip(&self) -> &str;
10//! }
11//! ```
12//!
13//! In order to be useful within bevy, you'll want to be able to query for this trait.
14//!
15//! ```
16//! # use bevy::prelude::*;
17//!
18//! // Just add this attribute...
19//! #[bevy_trait_query::queryable]
20//! pub trait Tooltip {
21//! fn tooltip(&self) -> &str;
22//! }
23//!
24//! // ...and now you can use your trait in queries.
25//! fn show_tooltips_system(
26//! tooltips: Query<&dyn Tooltip>,
27//! // ...
28//! ) {
29//! // ...
30//! }
31//! # bevy_ecs::system::assert_is_system(show_tooltips_system);
32//! ```
33//!
34//! Since Rust unfortunately lacks any kind of reflection, it is necessary to register each
35//! component with the trait when the app gets built.
36//!
37//! ```
38//! # use bevy::prelude::*;
39//! # use bevy_trait_query::*;
40//! #
41//! # #[bevy_trait_query::queryable]
42//! # pub trait Tooltip {
43//! # fn tooltip(&self) -> &str;
44//! # }
45//! #
46//! #[derive(Component)]
47//! struct Player(String);
48//!
49//! #[derive(Component)]
50//! enum Villager {
51//! Farmer,
52//! // ...
53//! }
54//!
55//! #[derive(Component)]
56//! struct Monster;
57//!
58//! /* ...trait implementations omitted for brevity... */
59//!
60//! # impl Tooltip for Player {
61//! # fn tooltip(&self) -> &str {
62//! # &self.0
63//! # }
64//! # }
65//! #
66//! # impl Tooltip for Villager {
67//! # fn tooltip(&self) -> &str {
68//! # "Villager"
69//! # }
70//! # }
71//! #
72//! # impl Tooltip for Monster {
73//! # fn tooltip(&self) -> &str {
74//! # "Run!"
75//! # }
76//! # }
77//! #
78//! struct TooltipPlugin;
79//!
80//! impl Plugin for TooltipPlugin {
81//! fn build(&self, app: &mut App) {
82//! // We must import this trait in order to register our components.
83//! // If we don't register them, they will be invisible to the game engine.
84//! use bevy_trait_query::RegisterExt;
85//!
86//! app
87//! .register_component_as::<dyn Tooltip, Player>()
88//! .register_component_as::<dyn Tooltip, Villager>()
89//! .register_component_as::<dyn Tooltip, Monster>()
90//! .add_systems(Update, show_tooltips);
91//! }
92//! }
93//! # fn show_tooltips() {}
94//! #
95//! # fn main() {
96//! # App::new().add_plugins((DefaultPlugins, TooltipPlugin)).update();
97//! # }
98//! ```
99//!
100//! Unlike queries for concrete types, it's possible for an entity to have multiple components
101//! that match a trait query.
102//!
103//! ```
104//! # use bevy::prelude::*;
105//! # use bevy_trait_query::*;
106//! #
107//! # #[bevy_trait_query::queryable]
108//! # pub trait Tooltip {
109//! # fn tooltip(&self) -> &str;
110//! # }
111//! #
112//! # #[derive(Component)]
113//! # struct Player(String);
114//! #
115//! # #[derive(Component)]
116//! # struct Monster;
117//! #
118//! # impl Tooltip for Player {
119//! # fn tooltip(&self) -> &str {
120//! # &self.0
121//! # }
122//! # }
123//! #
124//! # impl Tooltip for Monster {
125//! # fn tooltip(&self) -> &str {
126//! # "Run!"
127//! # }
128//! # }
129//! #
130//! # fn main() {
131//! # App::new()
132//! # .add_plugins(DefaultPlugins)
133//! # .register_component_as::<dyn Tooltip, Player>()
134//! # .register_component_as::<dyn Tooltip, Monster>()
135//! # .add_systems(Startup, setup)
136//! # .update();
137//! # }
138//! #
139//! # fn setup(mut commands: Commands) {
140//! # commands.spawn(Player("Fourier".to_owned()));
141//! # commands.spawn(Monster);
142//! # }
143//!
144//! fn show_tooltips(
145//! tooltips: Query<&dyn Tooltip>,
146//! // ...
147//! ) {
148//! // Iterate over each entity that has tooltips.
149//! for entity_tooltips in &tooltips {
150//! // Iterate over each component implementing `Tooltip` for the current entity.
151//! for tooltip in entity_tooltips {
152//! println!("Tooltip: {}", tooltip.tooltip());
153//! }
154//! }
155//!
156//! // If you instead just want to iterate over all tooltips, you can do:
157//! for tooltip in tooltips.iter().flatten() {
158//! println!("Tooltip: {}", tooltip.tooltip());
159//! }
160//! }
161//! ```
162//!
163//! Alternatively, if you expect to only have component implementing the trait for each entity,
164//! you can use the filter [`One`](crate::one::One). This has significantly better performance than iterating
165//! over all trait impls.
166//!
167//! ```
168//! # use bevy::prelude::*;
169//! # use bevy_trait_query::*;
170//! #
171//! # #[bevy_trait_query::queryable]
172//! # pub trait Tooltip {
173//! # fn tooltip(&self) -> &str;
174//! # }
175//! #
176//! use bevy_trait_query::One;
177//!
178//! fn show_tooltips(
179//! tooltips: Query<One<&dyn Tooltip>>,
180//! // ...
181//! ) {
182//! for tooltip in &tooltips {
183//! println!("Tooltip: {}", tooltip.tooltip());
184//! }
185//! }
186//! # bevy_ecs::system::assert_is_system(show_tooltips);
187//! ```
188//!
189//! Trait queries support basic change detection filtration.
190//!
191//! - queries requesting shared access yield [`ReadTraits`](`crate::all::ReadTraits`) which is
192//! similar to [`Ref`](https://docs.rs/bevy/latest/bevy/ecs/change_detection/struct.Ref.html)
193//! - queries requesting exclusive access yield [`WriteTraits`](`crate::all::WriteTraits`) which is
194//! similar to [`Mut`](https://docs.rs/bevy/latest/bevy/ecs/change_detection/struct.Mut.html)
195//!
196//! To get all the components that implement the target trait, and have also changed in some way
197//! since the last tick, you can:
198//! ```no_run
199//! # use bevy::prelude::*;
200//! # use bevy_trait_query::*;
201//! #
202//! # #[bevy_trait_query::queryable]
203//! # pub trait Tooltip {
204//! # fn tooltip(&self) -> &str;
205//! # }
206//! #
207//! fn show_tooltips(
208//! tooltips_query: Query<All<&dyn Tooltip>>
209//! // tooltips_query: Query<&dyn Tooltip> // <-- equivalent to line above
210//! // ...
211//! ) {
212//! // Iterate over all entities with at least one component implementing `Tooltip`
213//! for entity_tooltips in &tooltips_query {
214//! // Iterate over each component for the current entity that changed since the last time the system was run.
215//! for tooltip in entity_tooltips.iter_changed() {
216//! println!("Changed Tooltip: {}", tooltip.tooltip());
217//! }
218//! }
219//! }
220//! ```
221//!
222//! Similar to [`iter_changed`](crate::all::ReadTraits), we have [`iter_added`](crate::all::ReadTraits)
223//! to detect entities which have had a trait-implementing component added since the last tick.
224//!
225//! If you know you have only one component that implements the target trait,
226//! you can use [`OneAdded`](crate::one::OneAdded) or [`OneChanged`](crate::one::OneChanged) which behave more like the typical
227//! `bevy` [`Added`](https://docs.rs/bevy/latest/bevy/ecs/query/struct.Added.html)/[`Changed`](https://docs.rs/bevy/latest/bevy/ecs/query/struct.Changed.html) filters:
228//! ```no_run
229//! # use bevy::prelude::*;
230//! # use bevy_trait_query::*;
231//! #
232//! # #[bevy_trait_query::queryable]
233//! # pub trait Tooltip {
234//! # fn tooltip(&self) -> &str;
235//! # }
236//! #
237//! fn show_tooltips(
238//! tooltips_query: Query<One<&dyn Tooltip>, OneChanged<dyn Tooltip>>
239//! // ...
240//! ) {
241//! // Iterate over each entity that has one tooltip implementing component that has also changed
242//! for tooltip in &tooltips_query {
243//! println!("Changed Tooltip: {}", tooltip.tooltip());
244//! }
245//! }
246//! ```
247//! Note in the above example how [`OneChanged`](crate::one::OneChanged) does *not* take a reference to the trait object!
248//!
249//! # Performance
250//!
251//! The performance of trait queries is quite competitive. Here are some benchmarks for simple cases:
252//!
253//! | | Concrete type | [`One<dyn Trait>`](crate::one::One) | [`All<dyn Trait>`](crate::all::All) |
254//! |-------------------|----------------|---------------------|-------------------|
255//! | 1 match | 8.395 µs | 28.174 µs | 81.027 µs |
256//! | 2 matches | 8.473 µs | - | 106.47 µs |
257//! | 1-2 matches | - | 14.619 µs | 92.876 µs |
258//!
259
260mod internal;
261#[cfg(test)]
262mod tests;
263
264pub mod all;
265pub mod one;
266
267pub use all::*;
268pub use internal::*;
269pub use one::*;
270
271pub use bevy_trait_query_impl::queryable;
272
273// used by proc macro crate, it's important to keep these things as they are. Only make changes if
274// you know what you're doing
275#[doc(hidden)]
276pub mod imports {
277 pub use bevy_ecs::{
278 archetype::{Archetype, ArchetypeComponentId},
279 component::Tick,
280 component::{Component, ComponentId, Components},
281 entity::Entity,
282 query::{
283 Access, Added, Changed, FilteredAccess, QueryData, QueryFilter, QueryItem,
284 ReadOnlyQueryData, WorldQuery,
285 },
286 storage::{Table, TableRow},
287 world::{unsafe_world_cell::UnsafeWorldCell, World},
288 };
289}
290
291#[track_caller]
292#[inline(always)]
293unsafe fn debug_unreachable() -> ! {
294 #[cfg(debug_assertions)]
295 unreachable!();
296
297 #[cfg(not(debug_assertions))]
298 std::hint::unreachable_unchecked();
299}
300
301#[inline(never)]
302#[cold]
303fn trait_registry_error() -> ! {
304 panic!("The trait query registry has not been initialized; did you forget to register your traits with the world?")
305}