Skip to content

Commit b73811d

Browse files
authored
Remove ChildOf::get and Deref impl (#18080)
# Objective There are currently three ways to access the parent stored on a ChildOf relationship: 1. `child_of.parent` (field accessor) 2. `child_of.get()` (get function) 3. `**child_of` (Deref impl) I will assert that we should only have one (the field accessor), and that the existence of the other implementations causes confusion and legibility issues. The deref approach is heinous, and `child_of.get()` is significantly less clear than `child_of.parent`. ## Solution Remove `impl Deref for ChildOf` and `ChildOf::get`. The one "downside" I'm seeing is that: ```rust entity.get::<ChildOf>().map(ChildOf::get) ``` Becomes this: ```rust entity.get::<ChildOf>().map(|c| c.parent) ``` I strongly believe that this is worth the increased clarity and consistency. I'm also not really a huge fan of the "pass function pointer to map" syntax. I think most people don't think this way about maps. They think in terms of a function that takes the item in the Option and returns the result of some action on it. ## Migration Guide ```rust // Before **child_of // After child_of.parent // Before child_of.get() // After child_of.parent // Before entity.get::<ChildOf>().map(ChildOf::get) // After entity.get::<ChildOf>().map(|c| c.parent) ```
1 parent 0122b85 commit b73811d

File tree

11 files changed

+44
-60
lines changed

11 files changed

+44
-60
lines changed

crates/bevy_ecs/src/hierarchy.rs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,6 @@ pub struct ChildOf {
9999
pub parent: Entity,
100100
}
101101

102-
impl ChildOf {
103-
/// Returns the parent entity, which is the "target" of this relationship.
104-
pub fn get(&self) -> Entity {
105-
self.parent
106-
}
107-
}
108-
109-
impl Deref for ChildOf {
110-
type Target = Entity;
111-
112-
#[inline]
113-
fn deref(&self) -> &Self::Target {
114-
&self.parent
115-
}
116-
}
117-
118102
// TODO: We need to impl either FromWorld or Default so ChildOf can be registered as Reflect.
119103
// This is because Reflect deserialize by creating an instance and apply a patch on top.
120104
// However ChildOf should only ever be set with a real user-defined entity. Its worth looking into
@@ -280,7 +264,7 @@ pub fn validate_parent_has_component<C: Component>(
280264
return;
281265
};
282266
if !world
283-
.get_entity(child_of.get())
267+
.get_entity(child_of.parent)
284268
.is_ok_and(|e| e.contains::<C>())
285269
{
286270
// TODO: print name here once Name lives in bevy_ecs

crates/bevy_input_focus/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,17 @@ impl<E: Event + Clone> Event for FocusedInput<E> {
151151
#[derive(QueryData)]
152152
/// These are for accessing components defined on the targeted entity
153153
pub struct WindowTraversal {
154-
parent: Option<&'static ChildOf>,
154+
child_of: Option<&'static ChildOf>,
155155
window: Option<&'static Window>,
156156
}
157157

158158
impl<E: Event + Clone> Traversal<FocusedInput<E>> for WindowTraversal {
159159
fn traverse(item: Self::Item<'_>, event: &FocusedInput<E>) -> Option<Entity> {
160-
let WindowTraversalItem { parent, window } = item;
160+
let WindowTraversalItem { child_of, window } = item;
161161

162162
// Send event to parent, if it has one.
163-
if let Some(parent) = parent {
164-
return Some(parent.get());
163+
if let Some(child_of) = child_of {
164+
return Some(child_of.parent);
165165
};
166166

167167
// Otherwise, send it to the window entity (unless this is a window entity).
@@ -334,7 +334,7 @@ impl IsFocused for World {
334334
if e == entity {
335335
return true;
336336
}
337-
if let Some(parent) = self.entity(e).get::<ChildOf>().map(ChildOf::get) {
337+
if let Some(parent) = self.entity(e).get::<ChildOf>().map(|c| c.parent) {
338338
e = parent;
339339
} else {
340340
return false;

crates/bevy_picking/src/events.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub struct Pointer<E: Debug + Clone + Reflect> {
7979
/// propagates to the pointer's window and stops there.
8080
#[derive(QueryData)]
8181
pub struct PointerTraversal {
82-
parent: Option<&'static ChildOf>,
82+
child_of: Option<&'static ChildOf>,
8383
window: Option<&'static Window>,
8484
}
8585

@@ -88,11 +88,11 @@ where
8888
E: Debug + Clone + Reflect,
8989
{
9090
fn traverse(item: Self::Item<'_>, pointer: &Pointer<E>) -> Option<Entity> {
91-
let PointerTraversalItem { parent, window } = item;
91+
let PointerTraversalItem { child_of, window } = item;
9292

9393
// Send event to parent, if it has one.
94-
if let Some(parent) = parent {
95-
return Some(parent.get());
94+
if let Some(child_of) = child_of {
95+
return Some(child_of.parent);
9696
};
9797

9898
// Otherwise, send it to the window entity (unless this is a window entity).

crates/bevy_render/src/view/visibility/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,13 +405,13 @@ fn visibility_propagate_system(
405405
mut visibility_query: Query<(&Visibility, &mut InheritedVisibility)>,
406406
children_query: Query<&Children, (With<Visibility>, With<InheritedVisibility>)>,
407407
) {
408-
for (entity, visibility, parent, children) in &changed {
408+
for (entity, visibility, child_of, children) in &changed {
409409
let is_visible = match visibility {
410410
Visibility::Visible => true,
411411
Visibility::Hidden => false,
412412
// fall back to true if no parent is found or parent lacks components
413-
Visibility::Inherited => parent
414-
.and_then(|p| visibility_query.get(p.get()).ok())
413+
Visibility::Inherited => child_of
414+
.and_then(|c| visibility_query.get(c.parent).ok())
415415
.is_none_or(|(_, x)| x.get()),
416416
};
417417
let (_, mut inherited_visibility) = visibility_query

crates/bevy_scene/src/dynamic_scene.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ mod tests {
316316
.unwrap()
317317
.get::<ChildOf>()
318318
.unwrap()
319-
.get(),
319+
.parent,
320320
"something about reloading the scene is touching entities with the same scene Ids"
321321
);
322322
assert_eq!(
@@ -326,7 +326,7 @@ mod tests {
326326
.unwrap()
327327
.get::<ChildOf>()
328328
.unwrap()
329-
.get(),
329+
.parent,
330330
"something about reloading the scene is touching components not defined in the scene but on entities defined in the scene"
331331
);
332332
assert_eq!(
@@ -336,7 +336,7 @@ mod tests {
336336
.unwrap()
337337
.get::<ChildOf>()
338338
.expect("something is wrong with this test, and the scene components don't have a parent/child relationship")
339-
.get(),
339+
.parent,
340340
"something is wrong with this test or the code reloading scenes since the relationship between scene entities is broken"
341341
);
342342
}

crates/bevy_text/src/text.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -508,14 +508,14 @@ pub fn detect_text_needs_rerender<Root: Component>(
508508
// - Span component changed.
509509
// - Span TextFont changed.
510510
// - Span children changed (can include additions and removals).
511-
for (entity, maybe_span_parent, has_text_block) in changed_spans.iter() {
511+
for (entity, maybe_span_child_of, has_text_block) in changed_spans.iter() {
512512
if has_text_block {
513513
once!(warn!("found entity {} with a TextSpan that has a TextLayout, which should only be on root \
514514
text entities (that have {}); this warning only prints once",
515515
entity, core::any::type_name::<Root>()));
516516
}
517517

518-
let Some(span_parent) = maybe_span_parent else {
518+
let Some(span_child_of) = maybe_span_child_of else {
519519
once!(warn!(
520520
"found entity {} with a TextSpan that has no parent; it should have an ancestor \
521521
with a root text component ({}); this warning only prints once",
@@ -524,13 +524,13 @@ pub fn detect_text_needs_rerender<Root: Component>(
524524
));
525525
continue;
526526
};
527-
let mut parent: Entity = span_parent.get();
527+
let mut parent: Entity = span_child_of.parent;
528528

529529
// Search for the nearest ancestor with ComputedTextBlock.
530530
// Note: We assume the perf cost from duplicate visits in the case that multiple spans in a block are visited
531531
// is outweighed by the expense of tracking visited spans.
532532
loop {
533-
let Ok((maybe_parent, maybe_computed, has_span)) = computed.get_mut(parent) else {
533+
let Ok((maybe_child_of, maybe_computed, has_span)) = computed.get_mut(parent) else {
534534
once!(warn!("found entity {} with a TextSpan that is part of a broken hierarchy with a ChildOf \
535535
component that points at non-existent entity {}; this warning only prints once",
536536
entity, parent));
@@ -546,7 +546,7 @@ pub fn detect_text_needs_rerender<Root: Component>(
546546
entity, parent));
547547
break;
548548
}
549-
let Some(next_parent) = maybe_parent else {
549+
let Some(next_child_of) = maybe_child_of else {
550550
once!(warn!(
551551
"found entity {} with a TextSpan that has no ancestor with the root text \
552552
component ({}); this warning only prints once",
@@ -555,7 +555,7 @@ pub fn detect_text_needs_rerender<Root: Component>(
555555
));
556556
break;
557557
};
558-
parent = next_parent.get();
558+
parent = next_child_of.parent;
559559
}
560560
}
561561
}

crates/bevy_transform/src/systems.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ pub fn compute_transform_leaves(
5252
) {
5353
leaves
5454
.par_iter_mut()
55-
.for_each(|(transform, mut global_transform, parent)| {
56-
let Ok(parent_transform) = parents.get(parent.get()) else {
55+
.for_each(|(transform, mut global_transform, child_of)| {
56+
let Ok(parent_transform) = parents.get(child_of.parent) else {
5757
return;
5858
};
5959
if parent_transform.is_changed()
@@ -102,7 +102,7 @@ mod serial {
102102
(Ref<Transform>, &mut GlobalTransform, Option<&Children>),
103103
(With<ChildOf>, With<Children>),
104104
>,
105-
parent_query: Query<(Entity, Ref<ChildOf>), With<GlobalTransform>>,
105+
child_query: Query<(Entity, Ref<ChildOf>), With<GlobalTransform>>,
106106
mut orphaned_entities: Local<Vec<Entity>>,
107107
) {
108108
orphaned_entities.clear();
@@ -115,9 +115,9 @@ mod serial {
115115
*global_transform = GlobalTransform::from(*transform);
116116
}
117117

118-
for (child, actual_parent) in parent_query.iter_many(children) {
118+
for (child, child_of) in child_query.iter_many(children) {
119119
assert_eq!(
120-
actual_parent.get(), entity,
120+
child_of.parent, entity,
121121
"Malformed hierarchy. This probably means that your hierarchy has been improperly maintained, or contains a cycle"
122122
);
123123
// SAFETY:
@@ -137,9 +137,9 @@ mod serial {
137137
propagate_recursive(
138138
&global_transform,
139139
&transform_query,
140-
&parent_query,
140+
&child_query,
141141
child,
142-
changed || actual_parent.is_changed(),
142+
changed || child_of.is_changed(),
143143
);
144144
}
145145
}
@@ -170,7 +170,7 @@ mod serial {
170170
(Ref<Transform>, &mut GlobalTransform, Option<&Children>),
171171
(With<ChildOf>, With<Children>),
172172
>,
173-
parent_query: &Query<(Entity, Ref<ChildOf>), With<GlobalTransform>>,
173+
child_query: &Query<(Entity, Ref<ChildOf>), With<GlobalTransform>>,
174174
entity: Entity,
175175
mut changed: bool,
176176
) {
@@ -215,9 +215,9 @@ mod serial {
215215
};
216216

217217
let Some(children) = children else { return };
218-
for (child, actual_parent) in parent_query.iter_many(children) {
218+
for (child, child_of) in child_query.iter_many(children) {
219219
assert_eq!(
220-
actual_parent.get(), entity,
220+
child_of.parent, entity,
221221
"Malformed hierarchy. This probably means that your hierarchy has been improperly maintained, or contains a cycle"
222222
);
223223
// SAFETY: The caller guarantees that `transform_query` will not be fetched for any
@@ -229,9 +229,9 @@ mod serial {
229229
propagate_recursive(
230230
global_matrix.as_ref(),
231231
transform_query,
232-
parent_query,
232+
child_query,
233233
child,
234-
changed || actual_parent.is_changed(),
234+
changed || child_of.is_changed(),
235235
);
236236
}
237237
}
@@ -463,7 +463,7 @@ mod parallel {
463463
let mut last_child = None;
464464
let new_children = children_iter.map(
465465
|(child, (transform, mut global_transform), (children, child_of))| {
466-
assert_eq!(child_of.get(), parent);
466+
assert_eq!(child_of.parent, parent);
467467
if p_global_transform.is_changed()
468468
|| transform.is_changed()
469469
|| global_transform.is_added()

crates/bevy_ui/src/layout/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,12 @@ pub fn ui_layout_system(
127127

128128
computed_node_query
129129
.iter()
130-
.for_each(|(entity, maybe_parent)| {
131-
if let Some(parent) = maybe_parent {
130+
.for_each(|(entity, maybe_child_of)| {
131+
if let Some(child_of) = maybe_child_of {
132132
// Note: This does not cover the case where a parent's Node component was removed.
133133
// Users are responsible for fixing hierarchies if they do that (it is not recommended).
134134
// Detecting it here would be a permanent perf burden on the hot path.
135-
if parent.is_changed() && !ui_children.is_ui_node(parent.get()) {
135+
if child_of.is_changed() && !ui_children.is_ui_node(child_of.parent) {
136136
warn!(
137137
"Node ({entity}) is in a non-UI entity hierarchy. You are using an entity \
138138
with UI components as a child of an entity without UI components, your UI layout may be broken."

crates/bevy_winit/src/accessibility.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,9 @@ fn update_adapter(
227227
) -> TreeUpdate {
228228
let mut to_update = vec![];
229229
let mut window_children = vec![];
230-
for (entity, node, children, parent) in &nodes {
230+
for (entity, node, children, child_of) in &nodes {
231231
let mut node = (**node).clone();
232-
queue_node_for_update(entity, parent, &node_entities, &mut window_children);
232+
queue_node_for_update(entity, child_of, &node_entities, &mut window_children);
233233
add_children_nodes(children, &node_entities, &mut node);
234234
let node_id = NodeId(entity.to_bits());
235235
to_update.push((node_id, node));
@@ -258,7 +258,7 @@ fn queue_node_for_update(
258258
window_children: &mut Vec<NodeId>,
259259
) {
260260
let should_push = if let Some(child_of) = child_of {
261-
!node_entities.contains(child_of.get())
261+
!node_entities.contains(child_of.parent)
262262
} else {
263263
true
264264
};

examples/tools/scene_viewer/animation_plugin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ fn assign_clips(
109109
}
110110

111111
// Go to the next parent.
112-
current = children.get(entity).ok().map(ChildOf::get);
112+
current = children.get(entity).ok().map(|c| c.parent);
113113
}
114114
}
115115

0 commit comments

Comments
 (0)