Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QueryState::new_with_state #6240

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
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
68 changes: 68 additions & 0 deletions crates/bevy_ecs/src/query/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,74 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
let fetch_state = Q::init_state(world);
let filter_state = F::init_state(world);

// SAFETY: uses state initialized by `init_state`
unsafe { Self::new_with_state(world, fetch_state, filter_state) }
}

/// Creates a new [`QueryState`] with custom state initializer
///
/// This is useful when you need to initialize [`WorldQuery::State`] using a different implementation
/// than provided by [`WorldQuery::init_state`] which is called by [`QueryState::new`].
///
/// # Safety
///
/// State must be the same as what is returned by [`WorldQuery::init_state`] with the same [`World`]
/// passed into the function, as long as [`WorldQuery::init_state`] can be used.
///
/// Use [`QueryState::new`] directly when possible.
///
/// It is possible to get Bevy to cast `&U` into `&T` by providing the incorrect [`ComponentId`]
/// when querying references to components.
///
/// ```rust
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// # #[derive(Component)]
/// # struct T(usize);
/// # #[derive(Component)]
/// # struct U(usize);
/// # let mut world = World::new();
/// // `QueryState` will cast `&U` into `&T` when executing the query
/// let incorrect_fetch_state = world.init_component::<U>();
/// let query_state = unsafe {
/// QueryState::<&T, ()>::new_with_state(&mut world, incorrect_fetch_state, ());
/// };
/// ```
///
/// # Examples
///
/// ```rust
/// use bevy_ecs::prelude::*;
/// use bevy_ecs::query::WorldQuery;
///
/// #[derive(Component)]
/// struct A(usize);
///
/// #[derive(Component)]
/// struct B(usize);
///
/// let mut world = World::new();
///
/// // Query state will be initialized using `<&A as WorldQuery>::init_state`
/// let query_state = QueryState::<&A, ()>::new(&mut world);
///
/// // Alternatively we can initialize the state ourselves
/// // The state for `&T` is it's `ComponentId`.
/// # unsafe {
/// let fetch_state = world.init_component::<A>();
/// let query_state = QueryState::<&A, ()>::new_with_state(&mut world, fetch_state, ());
///
/// // We can do the same when initializing filters
/// let fetch_state = <&A as WorldQuery>::init_state(&mut world);
/// let filter_state = world.init_component::<B>();
/// let query_state = QueryState::<&A, With<B>>::new_with_state(&mut world, fetch_state, filter_state);
/// # }
/// ```
pub unsafe fn new_with_state(
world: &mut World,
fetch_state: Q::State,
filter_state: F::State,
) -> Self {
let mut component_access = FilteredAccess::default();
Q::update_component_access(&fetch_state, &mut component_access);

Expand Down