Skip to content

Commit baa0e2d

Browse files
authored
Fix ComponentsRegistrator unsoundness (#20187)
# Objective - Fix #20174 ## Solution - Avoid implementing `DerefMut` for `ComponentsRegistrator` - To avoid potential breakage, expose the `any_queued_mut` and `num_queued_mut` on `ComponentsRegistrator`. These are the only methods taking `&mut self` on `Components` and for which the `DerefMut` impl could have been useful for.
1 parent e45a77a commit baa0e2d

File tree

3 files changed

+46
-26
lines changed

3 files changed

+46
-26
lines changed

crates/bevy_ecs/src/component/register.rs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ use alloc::{boxed::Box, vec::Vec};
22
use bevy_platform::sync::PoisonError;
33
use bevy_utils::TypeIdMap;
44
use core::any::Any;
5-
use core::ops::DerefMut;
65
use core::{any::TypeId, fmt::Debug, ops::Deref};
76

8-
use crate::query::DebugCheckedUnwrap as _;
97
use crate::{
108
component::{
119
Component, ComponentDescriptor, ComponentId, Components, RequiredComponents, StorageType,
1210
},
11+
query::DebugCheckedUnwrap as _,
1312
resource::Resource,
1413
};
1514

@@ -62,8 +61,8 @@ impl ComponentIds {
6261

6362
/// A [`Components`] wrapper that enables additional features, like registration.
6463
pub struct ComponentsRegistrator<'w> {
65-
components: &'w mut Components,
66-
ids: &'w mut ComponentIds,
64+
pub(super) components: &'w mut Components,
65+
pub(super) ids: &'w mut ComponentIds,
6766
}
6867

6968
impl Deref for ComponentsRegistrator<'_> {
@@ -74,12 +73,6 @@ impl Deref for ComponentsRegistrator<'_> {
7473
}
7574
}
7675

77-
impl DerefMut for ComponentsRegistrator<'_> {
78-
fn deref_mut(&mut self) -> &mut Self::Target {
79-
self.components
80-
}
81-
}
82-
8376
impl<'w> ComponentsRegistrator<'w> {
8477
/// Constructs a new [`ComponentsRegistrator`].
8578
///
@@ -223,10 +216,11 @@ impl<'w> ComponentsRegistrator<'w> {
223216
) {
224217
// SAFETY: ensured by caller.
225218
unsafe {
226-
self.register_component_inner(id, ComponentDescriptor::new::<T>());
219+
self.components
220+
.register_component_inner(id, ComponentDescriptor::new::<T>());
227221
}
228222
let type_id = TypeId::of::<T>();
229-
let prev = self.indices.insert(type_id, id);
223+
let prev = self.components.indices.insert(type_id, id);
230224
debug_assert!(prev.is_none());
231225

232226
let mut required_components = RequiredComponents::default();
@@ -272,7 +266,7 @@ impl<'w> ComponentsRegistrator<'w> {
272266
let id = self.ids.next_mut();
273267
// SAFETY: The id is fresh.
274268
unsafe {
275-
self.register_component_inner(id, descriptor);
269+
self.components.register_component_inner(id, descriptor);
276270
}
277271
id
278272
}
@@ -339,7 +333,8 @@ impl<'w> ComponentsRegistrator<'w> {
339333
let id = self.ids.next_mut();
340334
// SAFETY: The resource is not currently registered, the id is fresh, and the [`ComponentDescriptor`] matches the [`TypeId`]
341335
unsafe {
342-
self.register_resource_unchecked(type_id, id, descriptor());
336+
self.components
337+
.register_resource_unchecked(type_id, id, descriptor());
343338
}
344339
id
345340
}
@@ -363,10 +358,20 @@ impl<'w> ComponentsRegistrator<'w> {
363358
let id = self.ids.next_mut();
364359
// SAFETY: The id is fresh.
365360
unsafe {
366-
self.register_component_inner(id, descriptor);
361+
self.components.register_component_inner(id, descriptor);
367362
}
368363
id
369364
}
365+
366+
/// Equivalent of `Components::any_queued_mut`
367+
pub fn any_queued_mut(&mut self) -> bool {
368+
self.components.any_queued_mut()
369+
}
370+
371+
/// Equivalent of `Components::any_queued_mut`
372+
pub fn num_queued_mut(&mut self) -> usize {
373+
self.components.num_queued_mut()
374+
}
370375
}
371376

372377
/// A queued component registration.
@@ -587,7 +592,9 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
587592
self.register_arbitrary_dynamic(descriptor, |registrator, id, descriptor| {
588593
// SAFETY: Id uniqueness handled by caller.
589594
unsafe {
590-
registrator.register_component_inner(id, descriptor);
595+
registrator
596+
.components
597+
.register_component_inner(id, descriptor);
591598
}
592599
})
593600
}
@@ -616,7 +623,9 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
616623
// SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor.
617624
#[expect(unused_unsafe, reason = "More precise to specify.")]
618625
unsafe {
619-
registrator.register_resource_unchecked(type_id, id, descriptor);
626+
registrator
627+
.components
628+
.register_resource_unchecked(type_id, id, descriptor);
620629
}
621630
},
622631
)
@@ -648,7 +657,9 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
648657
// SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor.
649658
#[expect(unused_unsafe, reason = "More precise to specify.")]
650659
unsafe {
651-
registrator.register_resource_unchecked(type_id, id, descriptor);
660+
registrator
661+
.components
662+
.register_resource_unchecked(type_id, id, descriptor);
652663
}
653664
},
654665
)
@@ -672,7 +683,9 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
672683
self.register_arbitrary_dynamic(descriptor, |registrator, id, descriptor| {
673684
// SAFETY: Id uniqueness handled by caller.
674685
unsafe {
675-
registrator.register_component_inner(id, descriptor);
686+
registrator
687+
.components
688+
.register_component_inner(id, descriptor);
676689
}
677690
})
678691
}

crates/bevy_ecs/src/component/required.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,14 @@ impl<'w> ComponentsRegistrator<'w> {
253253

254254
// SAFETY: We just created the components.
255255
unsafe {
256-
self.register_required_components_manual_unchecked::<R>(
257-
requiree,
258-
required,
259-
required_components,
260-
constructor,
261-
inheritance_depth,
262-
);
256+
self.components
257+
.register_required_components_manual_unchecked::<R>(
258+
requiree,
259+
required,
260+
required_components,
261+
constructor,
262+
inheritance_depth,
263+
);
263264
}
264265
}
265266
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
title: ComponentsRegistrator no longer implements DerefMut
3+
pull_requests: [14791, 15458, 15269]
4+
---
5+
6+
`ComponentsRegistrator` no longer implements `DerefMut<Target = Components>`, meaning you won't be able to get a `&mut Components` from it. The only two methods on `Components` that took `&mut self` (`any_queued_mut` and `num_queued_mut`) have been reimplemented on `ComponentsRegistrator`, meaning you won't need to migrate them. Other usages of `&mut Components` were unsupported.

0 commit comments

Comments
 (0)