Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
bae4957
implement a get_components_mut
hymm Nov 7, 2025
ec5a064
rework access enum for clarity
hymm Nov 7, 2025
8c19f82
rename method
hymm Nov 7, 2025
0ee0b0b
add docs
hymm Nov 9, 2025
37b1fdf
special case FilteredEntity*
hymm Nov 10, 2025
14cce3c
add a index
hymm Nov 10, 2025
a4aaa94
use new index for Entity*Except
hymm Nov 11, 2025
b8ef2b7
cleanup
hymm Nov 11, 2025
6ff805d
add tests and fix some bugs
hymm Nov 11, 2025
1b3f947
checked that filtered are compatible
hymm Nov 12, 2025
a5f91c7
convert to result
hymm Nov 12, 2025
31a1deb
convert other get_components to return a result
hymm Nov 12, 2025
f4abf4a
add more benches
hymm Nov 13, 2025
59c0f22
add a migration guide
hymm Nov 14, 2025
f541f83
add some comments
hymm Nov 14, 2025
16ca607
add a release note
hymm Nov 14, 2025
067f35c
shrink error type size
hymm Nov 14, 2025
61b0e43
fix errors after rebase
hymm Nov 14, 2025
9c5e3f0
filter instead
hymm Nov 14, 2025
41740b7
implement a faster algorithm for smaller QueryData
hymm Nov 14, 2025
caf7606
cleanup
hymm Nov 14, 2025
59e604c
fix test
hymm Nov 15, 2025
8a019f4
fix md lints
hymm Nov 15, 2025
aa4d98a
cache access type after lookup
hymm Nov 16, 2025
b8814a0
into_components_mut
hymm Nov 17, 2025
4542a81
clean up
hymm Nov 17, 2025
3c33496
change to borrow access
hymm Nov 17, 2025
8d480d2
put inner access on stack for small Q
hymm Nov 17, 2025
a6f33b7
refactor to panic on conflicts
hymm Nov 17, 2025
586efc6
typo
hymm Nov 17, 2025
1533c14
remove a inline never
hymm Nov 17, 2025
dcfa045
remove some unneeded lifetimes
hymm Nov 17, 2025
261bc60
add link to new method on unchecked versions
hymm Nov 17, 2025
e6a5b74
fix doc link
hymm Nov 17, 2025
01a8de4
link to correct method
hymm Nov 17, 2025
f4f6fd3
reuse iter
hymm Nov 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions benches/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ autobenches = false
# The primary crate that runs and analyzes our benchmarks. This is a regular dependency because the
# `bench!` macro refers to it in its documentation.
criterion = { version = "0.7.0", features = ["html_reports"] }
seq-macro = "0.3.6"

[dev-dependencies]
# Bevy crates
Expand Down
3 changes: 3 additions & 0 deletions benches/benches/bevy_ecs/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,8 @@ criterion_group!(
query_get_many::<2>,
query_get_many::<5>,
query_get_many::<10>,
query_get_components_mut_2,
query_get_components_mut_5,
query_get_components_mut_10,
entity_set_build_and_lookup,
);
65 changes: 64 additions & 1 deletion benches/benches/bevy_ecs/world/world_get.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use benches::bench;
use core::hint::black_box;

use bevy_ecs::{
bundle::{Bundle, NoBundleEffect},
component::Component,
entity::Entity,
system::{Query, SystemState},
world::World,
world::{EntityMut, World},
};
use criterion::Criterion;
use rand::{prelude::SliceRandom, SeedableRng};
use rand_chacha::ChaCha8Rng;
use seq_macro::seq;

#[derive(Component, Default)]
#[component(storage = "Table")]
Expand Down Expand Up @@ -357,3 +359,64 @@ pub fn query_get_many<const N: usize>(criterion: &mut Criterion) {
});
}
}

macro_rules! query_get_components_mut {
($function_name:ident, $val:literal) => {
pub fn $function_name(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group(bench!("world_query_get_components_mut"));
group.warm_up_time(core::time::Duration::from_millis(500));
group.measurement_time(core::time::Duration::from_secs(4));

for entity_count in RANGE.map(|i| i * 10_000) {
seq!(N in 0..$val {
let (mut world, entities) = setup_wide::<(
#(WideTable<N>,)*
)>(entity_count);
});
let mut query = world.query::<EntityMut>();
group.bench_function(format!("{}_components_{entity_count}_entities", $val), |bencher| {
bencher.iter(|| {
for entity in &entities {
seq!(N in 0..$val {
assert!(query
.get_mut(&mut world, *entity)
.unwrap()
.get_components_mut::<(
#(&mut WideTable<N>,)*
)>()
.is_ok());
});
}
});
});
group.bench_function(
format!("unchecked_{}_components_{entity_count}_entities", $val),
|bencher| {
bencher.iter(|| {
for entity in &entities {
// SAFETY: no duplicate components are listed
unsafe {
seq!(N in 0..$val {
assert!(query
.get_mut(&mut world, *entity)
.unwrap()
.get_components_mut_unchecked::<(
#(&mut WideTable<N>,)*
)>()
.is_ok());
});
}
}
});
},
);
}

group.finish();
}
};
}

query_get_components_mut!(query_get_components_mut_2, 2);
query_get_components_mut!(query_get_components_mut_5, 5);
query_get_components_mut!(query_get_components_mut_10, 10);
16 changes: 16 additions & 0 deletions crates/bevy_ecs/macros/src/query_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
let path = bevy_ecs_path();

let user_generics = ast.generics.clone();
let user_generics_ty_params = user_generics.type_params().map(|p| p.ident.clone());
let (user_impl_generics, user_ty_generics, user_where_clauses) = user_generics.split_for_impl();
let user_generics_with_world = {
let mut generics = ast.generics.clone();
Expand Down Expand Up @@ -267,6 +268,13 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
#(#field_members: <#read_only_field_types>::fetch(&_state.#field_aliases, &mut _fetch.#field_aliases, _entity, _table_row)?,)*
})
}

fn iter_access<'c>(
components: &'c #path::component::Components,
index: &mut usize
) -> impl core::iter::Iterator<Item = Option<#path::query::EcsAccessType>> + use<'c, #(#user_generics_ty_params,)*> {
core::iter::empty() #(.chain(<#field_types>::iter_access(components, index)))*
}
}

impl #user_impl_generics #path::query::ReleaseStateQueryData
Expand All @@ -293,6 +301,7 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {

let is_read_only = !attributes.is_mutable;

let user_generics_ty_params = user_generics.type_params().map(|p| p.ident.clone());
quote! {
/// SAFETY: we assert fields are readonly below
unsafe impl #user_impl_generics #path::query::QueryData
Expand Down Expand Up @@ -332,6 +341,13 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
#(#field_members: <#field_types>::fetch(&_state.#field_aliases, &mut _fetch.#field_aliases, _entity, _table_row)?,)*
})
}

fn iter_access<'c>(
components: &'c #path::component::Components,
index: &mut usize
) -> impl core::iter::Iterator<Item = Option<#path::query::EcsAccessType>> + use<'c, #(#user_generics_ty_params,)*> {
core::iter::empty() #(.chain(<#field_types>::iter_access(components, index)))*
}
}

impl #user_impl_generics #path::query::ReleaseStateQueryData
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/event/trigger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ unsafe impl<
return;
}
if let Ok(entity) = world.get_entity(current_entity)
&& let Some(item) = entity.get_components::<T>()
&& let Ok(item) = entity.get_components::<T>()
&& let Some(traverse_to) = T::traverse(item, event)
{
current_entity = traverse_to;
Expand Down
Loading
Loading