diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index 90ea42af39e4a..921e9ab8e3782 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -1265,9 +1265,9 @@ mod tests { .push_children(&[child]) .id(); - let mut query = world.query::<&Children>(); + let mut query = world.query::(); let children = query.get(&world, parent).unwrap(); - assert_eq!(**children, [child]); + assert_eq!(children, [child]); } #[test] @@ -1275,7 +1275,7 @@ mod tests { let mut world = World::new(); let parent = world.spawn_empty().push_children(&[]).id(); - let mut query = world.query::<&Children>(); + let mut query = world.query::(); let children = query.get(&world, parent); assert!(children.is_err()); } diff --git a/crates/bevy_hierarchy/src/components/children.rs b/crates/bevy_hierarchy/src/components/children.rs index 5a53462d82c58..ac3eec2d9b372 100644 --- a/crates/bevy_hierarchy/src/components/children.rs +++ b/crates/bevy_hierarchy/src/components/children.rs @@ -1,10 +1,13 @@ #[cfg(feature = "reflect")] use bevy_ecs::reflect::{ReflectComponent, ReflectMapEntities}; use bevy_ecs::{ - component::Component, + archetype::Archetype, + component::{Component, ComponentId, Components, Tick}, entity::{Entity, EntityMapper, MapEntities}, prelude::FromWorld, - world::World, + query::{FilteredAccess, QueryData, ReadFetch, ReadOnlyQueryData, WorldQuery}, + storage::{Table, TableRow}, + world::{unsafe_world_cell::UnsafeWorldCell, World}, }; use core::slice; use smallvec::SmallVec; @@ -162,3 +165,96 @@ impl<'a> IntoIterator for &'a Children { self.0.iter() } } + +#[allow(unsafe_code)] +/// SAFETY: +/// This implementation delegates to the existing implementation for &Children +unsafe impl WorldQuery for Children +where + Self: Component, +{ + type Item<'w> = &'w [Entity]; + type Fetch<'w> = ReadFetch<'w, Self>; + type State = ComponentId; + + fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> { + item + } + + fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> { + <&Self as WorldQuery>::shrink_fetch(fetch) + } + + #[inline] + unsafe fn init_fetch<'w>( + world: UnsafeWorldCell<'w>, + state: &Self::State, + last_run: Tick, + this_run: Tick, + ) -> Self::Fetch<'w> { + // SAFETY: This implementation delegates to the existing implementation for &Self + unsafe { <&Self as WorldQuery>::init_fetch(world, state, last_run, this_run) } + } + + const IS_DENSE: bool = <&Self as WorldQuery>::IS_DENSE; + + #[inline] + unsafe fn set_archetype<'w>( + fetch: &mut Self::Fetch<'w>, + state: &Self::State, + archetype: &'w Archetype, + table: &'w Table, + ) { + // SAFETY: This implementation delegates to the existing implementation for &Self + unsafe { <&Self as WorldQuery>::set_archetype(fetch, state, archetype, table) } + } + + #[inline] + unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) { + // SAFETY: This implementation delegates to the existing implementation for &Self + unsafe { <&Self as WorldQuery>::set_table(fetch, state, table) } + } + + #[inline(always)] + unsafe fn fetch<'w>( + fetch: &mut Self::Fetch<'w>, + entity: Entity, + table_row: TableRow, + ) -> Self::Item<'w> { + // SAFETY: This implementation delegates to the existing implementation for &Self + unsafe { + <&Self as WorldQuery>::fetch(fetch, entity, table_row) + .0 + .as_ref() + } + } + + fn update_component_access(state: &Self::State, access: &mut FilteredAccess) { + <&Self as WorldQuery>::update_component_access(state, access); + } + + fn init_state(world: &mut World) -> ComponentId { + <&Self as WorldQuery>::init_state(world) + } + + fn get_state(components: &Components) -> Option { + <&Self as WorldQuery>::get_state(components) + } + + fn matches_component_set( + state: &Self::State, + set_contains_id: &impl Fn(ComponentId) -> bool, + ) -> bool { + <&Self as WorldQuery>::matches_component_set(state, set_contains_id) + } +} + +#[allow(unsafe_code)] +/// SAFETY: `Self` is the same as `Self::ReadOnly` +unsafe impl QueryData for Children { + type ReadOnly = Self; +} + +#[allow(unsafe_code)] +/// SAFETY: access is read only +unsafe impl ReadOnlyQueryData for Children {} diff --git a/crates/bevy_hierarchy/src/components/parent.rs b/crates/bevy_hierarchy/src/components/parent.rs index 99d8e45460a8d..25be1f805b49c 100644 --- a/crates/bevy_hierarchy/src/components/parent.rs +++ b/crates/bevy_hierarchy/src/components/parent.rs @@ -1,10 +1,13 @@ #[cfg(feature = "reflect")] use bevy_ecs::reflect::{ReflectComponent, ReflectMapEntities}; use bevy_ecs::{ - component::Component, + archetype::Archetype, + component::{Component, ComponentId, Components, Tick}, entity::{Entity, EntityMapper, MapEntities}, + query::{FilteredAccess, QueryData, ReadFetch, ReadOnlyQueryData, WorldQuery}, + storage::{Table, TableRow}, traversal::Traversal, - world::{FromWorld, World}, + world::{unsafe_world_cell::UnsafeWorldCell, FromWorld, World}, }; use std::ops::Deref; @@ -81,3 +84,92 @@ impl Traversal for Parent { Some(self.0) } } + +#[allow(unsafe_code)] +/// SAFETY: +/// This implementation delegates to the existing implementation for &Parent +unsafe impl WorldQuery for Parent +where + Self: Component, +{ + type Item<'w> = Entity; + type Fetch<'w> = ReadFetch<'w, Self>; + type State = ComponentId; + + fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> { + item + } + + fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> { + <&Self as WorldQuery>::shrink_fetch(fetch) + } + + #[inline] + unsafe fn init_fetch<'w>( + world: UnsafeWorldCell<'w>, + state: &Self::State, + last_run: Tick, + this_run: Tick, + ) -> Self::Fetch<'w> { + // SAFETY: This implementation delegates to the existing implementation for &Self + unsafe { <&Self as WorldQuery>::init_fetch(world, state, last_run, this_run) } + } + + const IS_DENSE: bool = <&Self as WorldQuery>::IS_DENSE; + + #[inline] + unsafe fn set_archetype<'w>( + fetch: &mut Self::Fetch<'w>, + state: &Self::State, + archetype: &'w Archetype, + table: &'w Table, + ) { + // SAFETY: This implementation delegates to the existing implementation for &Self + unsafe { <&Self as WorldQuery>::set_archetype(fetch, state, archetype, table) } + } + + #[inline] + unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) { + // SAFETY: This implementation delegates to the existing implementation for &Self + unsafe { <&Self as WorldQuery>::set_table(fetch, state, table) } + } + + #[inline(always)] + unsafe fn fetch<'w>( + fetch: &mut Self::Fetch<'w>, + entity: Entity, + table_row: TableRow, + ) -> Self::Item<'w> { + // SAFETY: This implementation delegates to the existing implementation for &Self + unsafe { <&Self as WorldQuery>::fetch(fetch, entity, table_row).get() } + } + + fn update_component_access(state: &Self::State, access: &mut FilteredAccess) { + <&Self as WorldQuery>::update_component_access(state, access); + } + + fn init_state(world: &mut World) -> ComponentId { + <&Self as WorldQuery>::init_state(world) + } + + fn get_state(components: &Components) -> Option { + <&Self as WorldQuery>::get_state(components) + } + + fn matches_component_set( + state: &Self::State, + set_contains_id: &impl Fn(ComponentId) -> bool, + ) -> bool { + <&Self as WorldQuery>::matches_component_set(state, set_contains_id) + } +} + +#[allow(unsafe_code)] +/// SAFETY: `Self` is the same as `Self::ReadOnly` +unsafe impl QueryData for Parent { + type ReadOnly = Self; +} + +#[allow(unsafe_code)] +/// SAFETY: access is read only +unsafe impl ReadOnlyQueryData for Parent {} diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index 75fc8492024a6..393638e01a8f8 100755 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![forbid(unsafe_code)] +#![deny(unsafe_code)] #![doc( html_logo_url = "https://bevyengine.org/assets/icon.png", html_favicon_url = "https://bevyengine.org/assets/icon.png" diff --git a/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs b/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs index 21cde05f52865..6e2a59b5960d3 100644 --- a/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs +++ b/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs @@ -54,14 +54,13 @@ impl Default for ReportHierarchyIssue { /// (See B0004 explanation linked in warning message) pub fn check_hierarchy_component_has_valid_parent( parent_query: Query< - (Entity, &Parent, Option<&bevy_core::Name>), + (Entity, Parent, Option<&bevy_core::Name>), (With, Or<(Changed, Added)>), >, component_query: Query<(), With>, mut already_diagnosed: Local>, ) { for (entity, parent, name) in &parent_query { - let parent = parent.get(); if !component_query.contains(parent) && !already_diagnosed.contains(&entity) { already_diagnosed.insert(entity); bevy_utils::tracing::warn!( diff --git a/crates/bevy_render/src/mesh/morph.rs b/crates/bevy_render/src/mesh/morph.rs index 8055d2975fa0c..23a1f7f6da2e3 100644 --- a/crates/bevy_render/src/mesh/morph.rs +++ b/crates/bevy_render/src/mesh/morph.rs @@ -198,7 +198,7 @@ impl MeshMorphWeights { /// /// Only direct children are updated, to fulfill the expectations of glTF spec. pub fn inherit_weights( - morph_nodes: Query<(&Children, &MorphWeights), (Without>, Changed)>, + morph_nodes: Query<(Children, &MorphWeights), (Without>, Changed)>, mut morph_primitives: Query<&mut MeshMorphWeights, With>>, ) { for (children, parent_weights) in &morph_nodes { diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 8181d3c91118f..b8f69fd578a42 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -344,11 +344,11 @@ pub fn update_frusta( fn visibility_propagate_system( changed: Query< - (Entity, &Visibility, Option<&Parent>, Option<&Children>), + (Entity, &Visibility, Option, Option), (With, Changed), >, mut visibility_query: Query<(&Visibility, &mut InheritedVisibility)>, - children_query: Query<&Children, (With, With)>, + children_query: Query, With)>, ) { for (entity, visibility, parent, children) in &changed { let is_visible = match visibility { @@ -356,7 +356,7 @@ fn visibility_propagate_system( Visibility::Hidden => false, // fall back to true if no parent is found or parent lacks components Visibility::Inherited => parent - .and_then(|p| visibility_query.get(p.get()).ok()) + .and_then(|p| visibility_query.get(p).ok()) .map_or(true, |(_, x)| x.get()), }; let (_, mut inherited_visibility) = visibility_query @@ -382,7 +382,7 @@ fn propagate_recursive( parent_is_visible: bool, entity: Entity, visibility_query: &mut Query<(&Visibility, &mut InheritedVisibility)>, - children_query: &Query<&Children, (With, With)>, + children_query: &Query, With)>, // BLOCKED: https://github.com/rust-lang/rust/issues/31436 // We use a result here to use the `?` operator. Ideally we'd use a try block instead ) -> Result<(), ()> { diff --git a/crates/bevy_transform/src/systems.rs b/crates/bevy_transform/src/systems.rs index f32a19dc42982..806d03a245735 100644 --- a/crates/bevy_transform/src/systems.rs +++ b/crates/bevy_transform/src/systems.rs @@ -48,11 +48,11 @@ pub fn sync_simple_transforms( /// Third party plugins should ensure that this is used in concert with [`sync_simple_transforms`]. pub fn propagate_transforms( mut root_query: Query< - (Entity, &Children, Ref, &mut GlobalTransform), + (Entity, Children, Ref, &mut GlobalTransform), Without, >, mut orphaned: RemovedComponents, - transform_query: Query<(Ref, &mut GlobalTransform, Option<&Children>), With>, + transform_query: Query<(Ref, &mut GlobalTransform, Option), With>, parent_query: Query<(Entity, Ref), With>, mut orphaned_entities: Local>, ) { @@ -110,10 +110,7 @@ pub fn propagate_transforms( #[allow(unsafe_code)] unsafe fn propagate_recursive( parent: &GlobalTransform, - transform_query: &Query< - (Ref, &mut GlobalTransform, Option<&Children>), - With, - >, + transform_query: &Query<(Ref, &mut GlobalTransform, Option), With>, parent_query: &Query<(Entity, Ref), With>, entity: Entity, mut changed: bool, diff --git a/crates/bevy_ui/src/accessibility.rs b/crates/bevy_ui/src/accessibility.rs index 53cfb272b2219..176d403cf5154 100644 --- a/crates/bevy_ui/src/accessibility.rs +++ b/crates/bevy_ui/src/accessibility.rs @@ -19,7 +19,7 @@ use bevy_render::{camera::CameraUpdateSystem, prelude::Camera}; use bevy_text::Text; use bevy_transform::prelude::GlobalTransform; -fn calc_name(texts: &Query<&Text>, children: &Children) -> Option> { +fn calc_name(texts: &Query<&Text>, children: &[Entity]) -> Option> { let mut name = None; for child in children { if let Ok(text) = texts.get(*child) { @@ -59,7 +59,7 @@ fn calc_bounds( fn button_changed( mut commands: Commands, - mut query: Query<(Entity, &Children, Option<&mut AccessibilityNode>), Changed