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

Implement ReadOnlyQueryData for Parent and Children #15049

Closed
Show file tree
Hide file tree
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
6 changes: 3 additions & 3 deletions crates/bevy_hierarchy/src/child_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1265,17 +1265,17 @@ mod tests {
.push_children(&[child])
.id();

let mut query = world.query::<&Children>();
let mut query = world.query::<Children>();
let children = query.get(&world, parent).unwrap();
assert_eq!(**children, [child]);
assert_eq!(children, [child]);
}

#[test]
fn push_children_does_not_insert_empty_children() {
let mut world = World::new();
let parent = world.spawn_empty().push_children(&[]).id();

let mut query = world.query::<&Children>();
let mut query = world.query::<Children>();
let children = query.get(&world, parent);
assert!(children.is_err());
}
Expand Down
100 changes: 98 additions & 2 deletions crates/bevy_hierarchy/src/components/children.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<ComponentId>) {
<&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::State> {
<&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 {}
96 changes: 94 additions & 2 deletions crates/bevy_hierarchy/src/components/parent.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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<ComponentId>) {
<&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::State> {
<&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 {}
2 changes: 1 addition & 1 deletion crates/bevy_hierarchy/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
3 changes: 1 addition & 2 deletions crates/bevy_hierarchy/src/valid_parent_check_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,13 @@ impl<T> Default for ReportHierarchyIssue<T> {
/// (See B0004 explanation linked in warning message)
pub fn check_hierarchy_component_has_valid_parent<T: Component>(
parent_query: Query<
(Entity, &Parent, Option<&bevy_core::Name>),
(Entity, Parent, Option<&bevy_core::Name>),
(With<T>, Or<(Changed<Parent>, Added<T>)>),
>,
component_query: Query<(), With<T>>,
mut already_diagnosed: Local<HashSet<Entity>>,
) {
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!(
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_render/src/mesh/morph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Handle<Mesh>>, Changed<MorphWeights>)>,
morph_nodes: Query<(Children, &MorphWeights), (Without<Handle<Mesh>>, Changed<MorphWeights>)>,
mut morph_primitives: Query<&mut MeshMorphWeights, With<Handle<Mesh>>>,
) {
for (children, parent_weights) in &morph_nodes {
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_render/src/view/visibility/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,19 +344,19 @@ pub fn update_frusta<T: Component + CameraProjection + Send + Sync + 'static>(

fn visibility_propagate_system(
changed: Query<
(Entity, &Visibility, Option<&Parent>, Option<&Children>),
(Entity, &Visibility, Option<Parent>, Option<Children>),
(With<InheritedVisibility>, Changed<Visibility>),
>,
mut visibility_query: Query<(&Visibility, &mut InheritedVisibility)>,
children_query: Query<&Children, (With<Visibility>, With<InheritedVisibility>)>,
children_query: Query<Children, (With<Visibility>, With<InheritedVisibility>)>,
) {
for (entity, visibility, parent, children) in &changed {
let is_visible = match visibility {
Visibility::Visible => true,
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
Expand All @@ -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<Visibility>, With<InheritedVisibility>)>,
children_query: &Query<Children, (With<Visibility>, With<InheritedVisibility>)>,
// 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<(), ()> {
Expand Down
9 changes: 3 additions & 6 deletions crates/bevy_transform/src/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Transform>, &mut GlobalTransform),
(Entity, Children, Ref<Transform>, &mut GlobalTransform),
Without<Parent>,
>,
mut orphaned: RemovedComponents<Parent>,
transform_query: Query<(Ref<Transform>, &mut GlobalTransform, Option<&Children>), With<Parent>>,
transform_query: Query<(Ref<Transform>, &mut GlobalTransform, Option<Children>), With<Parent>>,
parent_query: Query<(Entity, Ref<Parent>), With<GlobalTransform>>,
mut orphaned_entities: Local<Vec<Entity>>,
) {
Expand Down Expand Up @@ -110,10 +110,7 @@ pub fn propagate_transforms(
#[allow(unsafe_code)]
unsafe fn propagate_recursive(
parent: &GlobalTransform,
transform_query: &Query<
(Ref<Transform>, &mut GlobalTransform, Option<&Children>),
With<Parent>,
>,
transform_query: &Query<(Ref<Transform>, &mut GlobalTransform, Option<Children>), With<Parent>>,
parent_query: &Query<(Entity, Ref<Parent>), With<GlobalTransform>>,
entity: Entity,
mut changed: bool,
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_ui/src/accessibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Box<str>> {
fn calc_name(texts: &Query<&Text>, children: &[Entity]) -> Option<Box<str>> {
let mut name = None;
for child in children {
if let Ok(text) = texts.get(*child) {
Expand Down Expand Up @@ -59,7 +59,7 @@ fn calc_bounds(

fn button_changed(
mut commands: Commands,
mut query: Query<(Entity, &Children, Option<&mut AccessibilityNode>), Changed<Button>>,
mut query: Query<(Entity, Children, Option<&mut AccessibilityNode>), Changed<Button>>,
texts: Query<&Text>,
) {
for (entity, children, accessible) in &mut query {
Expand All @@ -86,7 +86,7 @@ fn button_changed(
fn image_changed(
mut commands: Commands,
mut query: Query<
(Entity, &Children, Option<&mut AccessibilityNode>),
(Entity, Children, Option<&mut AccessibilityNode>),
(Changed<UiImage>, Without<Button>),
>,
texts: Query<&Text>,
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ui/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ pub fn ui_layout_system(
With<Node>,
>,
children_query: Query<(Entity, Ref<Children>), With<Node>>,
just_children_query: Query<&Children>,
just_children_query: Query<Children>,
mut removed_components: UiLayoutSystemRemovedComponentParam,
mut node_transform_query: Query<(
&mut Node,
Expand Down Expand Up @@ -293,7 +293,7 @@ pub fn ui_layout_system(
Option<&BorderRadius>,
Option<&Outline>,
)>,
children_query: &Query<&Children>,
children_query: &Query<Children>,
inverse_target_scale_factor: f32,
parent_size: Vec2,
mut absolute_location: Vec2,
Expand Down
Loading