Remove upcasting methods + Cleanup interned label code (#18984)

Hiya!

# Objective

- Remove upcasting methods that are no longer necessary since Rust 1.86.
- Cleanup the interned label code.
 
## Notes
- I didn't try to remove the upcasting methods from `bevy_reflect`, as
there appears to be some complexity related to remote type reflection.
- There are likely some other upcasting methods floating around.

## Testing
I ran the `breakout` example to check that the hashing/eq
implementations of the labels are still correct.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
Tim 2025-05-26 17:38:12 +02:00 committed by GitHub
parent 93b8f9a303
commit 4924cf5828
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 23 additions and 97 deletions

View File

@ -10,7 +10,7 @@ keywords = ["game", "engine", "gamedev", "graphics", "bevy"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/bevyengine/bevy"
documentation = "https://docs.rs/bevy"
rust-version = "1.85.0"
rust-version = "1.86.0"
[workspace]
resolver = "2"

View File

@ -205,8 +205,6 @@ pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
pub fn derive_app_label(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let mut trait_path = BevyManifest::shared().get_path("bevy_app");
let mut dyn_eq_path = trait_path.clone();
trait_path.segments.push(format_ident!("AppLabel").into());
dyn_eq_path.segments.push(format_ident!("DynEq").into());
derive_label(input, "AppLabel", &trait_path, &dyn_eq_path)
derive_label(input, "AppLabel", &trait_path)
}

View File

@ -8,7 +8,7 @@ repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0"
keywords = ["ecs", "game", "bevy"]
categories = ["game-engines", "data-structures"]
rust-version = "1.85.0"
rust-version = "1.86.0"
[features]
default = ["std", "bevy_reflect", "async_executor", "backtrace"]

View File

@ -503,12 +503,10 @@ pub fn derive_schedule_label(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let mut trait_path = bevy_ecs_path();
trait_path.segments.push(format_ident!("schedule").into());
let mut dyn_eq_path = trait_path.clone();
trait_path
.segments
.push(format_ident!("ScheduleLabel").into());
dyn_eq_path.segments.push(format_ident!("DynEq").into());
derive_label(input, "ScheduleLabel", &trait_path, &dyn_eq_path)
derive_label(input, "ScheduleLabel", &trait_path)
}
/// Derive macro generating an impl of the trait `SystemSet`.
@ -519,10 +517,8 @@ pub fn derive_system_set(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let mut trait_path = bevy_ecs_path();
trait_path.segments.push(format_ident!("schedule").into());
let mut dyn_eq_path = trait_path.clone();
trait_path.segments.push(format_ident!("SystemSet").into());
dyn_eq_path.segments.push(format_ident!("DynEq").into());
derive_label(input, "SystemSet", &trait_path, &dyn_eq_path)
derive_label(input, "SystemSet", &trait_path)
}
pub(crate) fn bevy_ecs_path() -> syn::Path {

View File

@ -12,9 +12,6 @@ pub use alloc::boxed::Box;
/// An object safe version of [`Eq`]. This trait is automatically implemented
/// for any `'static` type that implements `Eq`.
pub trait DynEq: Any {
/// Casts the type to `dyn Any`.
fn as_any(&self) -> &dyn Any;
/// This method tests for `self` and `other` values to be equal.
///
/// Implementers should avoid returning `true` when the underlying types are
@ -29,12 +26,8 @@ impl<T> DynEq for T
where
T: Any + Eq,
{
fn as_any(&self) -> &dyn Any {
self
}
fn dyn_eq(&self, other: &dyn DynEq) -> bool {
if let Some(other) = other.as_any().downcast_ref::<T>() {
if let Some(other) = (other as &dyn Any).downcast_ref::<T>() {
return self == other;
}
false
@ -44,9 +37,6 @@ where
/// An object safe version of [`Hash`]. This trait is automatically implemented
/// for any `'static` type that implements `Hash`.
pub trait DynHash: DynEq {
/// Casts the type to `dyn Any`.
fn as_dyn_eq(&self) -> &dyn DynEq;
/// Feeds this value into the given [`Hasher`].
fn dyn_hash(&self, state: &mut dyn Hasher);
}
@ -58,10 +48,6 @@ impl<T> DynHash for T
where
T: DynEq + Hash,
{
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
T::hash(self, &mut state);
self.type_id().hash(&mut state);
@ -120,7 +106,7 @@ macro_rules! define_label {
) => {
$(#[$label_attr])*
pub trait $label_trait_name: 'static + Send + Sync + ::core::fmt::Debug {
pub trait $label_trait_name: Send + Sync + ::core::fmt::Debug + $crate::label::DynEq + $crate::label::DynHash {
$($trait_extra_methods)*
@ -129,12 +115,6 @@ macro_rules! define_label {
///`.
fn dyn_clone(&self) -> $crate::label::Box<dyn $label_trait_name>;
/// Casts this value to a form where it can be compared with other type-erased values.
fn as_dyn_eq(&self) -> &dyn $crate::label::DynEq;
/// Feeds this value into the given [`Hasher`].
fn dyn_hash(&self, state: &mut dyn ::core::hash::Hasher);
/// Returns an [`Interned`] value corresponding to `self`.
fn intern(&self) -> $crate::intern::Interned<dyn $label_trait_name>
where Self: Sized {
@ -151,15 +131,6 @@ macro_rules! define_label {
(**self).dyn_clone()
}
/// Casts this value to a form where it can be compared with other type-erased values.
fn as_dyn_eq(&self) -> &dyn $crate::label::DynEq {
(**self).as_dyn_eq()
}
fn dyn_hash(&self, state: &mut dyn ::core::hash::Hasher) {
(**self).dyn_hash(state);
}
fn intern(&self) -> Self {
*self
}
@ -167,7 +138,7 @@ macro_rules! define_label {
impl PartialEq for dyn $label_trait_name {
fn eq(&self, other: &Self) -> bool {
self.as_dyn_eq().dyn_eq(other.as_dyn_eq())
self.dyn_eq(other)
}
}
@ -188,7 +159,7 @@ macro_rules! define_label {
use ::core::ptr;
// Test that both the type id and pointer address are equivalent.
self.as_dyn_eq().type_id() == other.as_dyn_eq().type_id()
self.type_id() == other.type_id()
&& ptr::addr_eq(ptr::from_ref::<Self>(self), ptr::from_ref::<Self>(other))
}
@ -196,7 +167,7 @@ macro_rules! define_label {
use ::core::{hash::Hash, ptr};
// Hash the type id...
self.as_dyn_eq().type_id().hash(state);
self.type_id().hash(state);
// ...and the pointer address.
// Cast to a unit `()` first to discard any pointer metadata.

View File

@ -147,15 +147,6 @@ impl<T> SystemSet for SystemTypeSet<T> {
fn dyn_clone(&self) -> Box<dyn SystemSet> {
Box::new(*self)
}
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
TypeId::of::<Self>().hash(&mut state);
self.hash(&mut state);
}
}
/// A [`SystemSet`] implicitly created when using
@ -178,15 +169,6 @@ impl SystemSet for AnonymousSet {
fn dyn_clone(&self) -> Box<dyn SystemSet> {
Box::new(*self)
}
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
TypeId::of::<Self>().hash(&mut state);
self.hash(&mut state);
}
}
/// Types that can be converted into a [`SystemSet`].

View File

@ -2510,10 +2510,7 @@ impl DynSystemParamState {
}
/// Allows a [`SystemParam::State`] to be used as a trait object for implementing [`DynSystemParam`].
trait DynParamState: Sync + Send {
/// Casts the underlying `ParamState<T>` to an `Any` so it can be downcast.
fn as_any_mut(&mut self) -> &mut dyn Any;
trait DynParamState: Sync + Send + Any {
/// For the specified [`Archetype`], registers the components accessed by this [`SystemParam`] (if applicable).a
///
/// # Safety
@ -2544,10 +2541,6 @@ trait DynParamState: Sync + Send {
struct ParamState<T: SystemParam>(T::State);
impl<T: SystemParam + 'static> DynParamState for ParamState<T> {
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
unsafe fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) {
// SAFETY: The caller ensures that `archetype` is from the World the state was initialized from in `init_state`.
unsafe { T::new_archetype(&mut self.0, archetype, system_meta) };
@ -2597,18 +2590,11 @@ unsafe impl SystemParam for DynSystemParam<'_, '_> {
change_tick: Tick,
) -> Self::Item<'world, 'state> {
// SAFETY:
// - `state.0` is a boxed `ParamState<T>`, and its implementation of `as_any_mut` returns `self`.
// - `state.0` is a boxed `ParamState<T>`.
// - The state was obtained from `SystemParamBuilder::build()`, which registers all [`World`] accesses used
// by [`SystemParam::get_param`] with the provided [`system_meta`](SystemMeta).
// - The caller ensures that the provided world is the same and has the required access.
unsafe {
DynSystemParam::new(
state.0.as_any_mut(),
world,
system_meta.clone(),
change_tick,
)
}
unsafe { DynSystemParam::new(state.0.as_mut(), world, system_meta.clone(), change_tick) }
}
unsafe fn new_archetype(

View File

@ -58,7 +58,6 @@ pub fn derive_label(
input: syn::DeriveInput,
trait_name: &str,
trait_path: &syn::Path,
dyn_eq_path: &syn::Path,
) -> TokenStream {
if let syn::Data::Union(_) = &input.data {
let message = format!("Cannot derive {trait_name} for unions.");
@ -89,16 +88,6 @@ pub fn derive_label(
fn dyn_clone(&self) -> alloc::boxed::Box<dyn #trait_path> {
alloc::boxed::Box::new(::core::clone::Clone::clone(self))
}
fn as_dyn_eq(&self) -> &dyn #dyn_eq_path {
self
}
fn dyn_hash(&self, mut state: &mut dyn ::core::hash::Hasher) {
let ty_id = ::core::any::TypeId::of::<Self>();
::core::hash::Hash::hash(&ty_id, &mut state);
::core::hash::Hash::hash(self, &mut state);
}
}
};
}

View File

@ -80,12 +80,10 @@ pub fn derive_render_label(input: TokenStream) -> TokenStream {
trait_path
.segments
.push(format_ident!("render_graph").into());
let mut dyn_eq_path = trait_path.clone();
trait_path
.segments
.push(format_ident!("RenderLabel").into());
dyn_eq_path.segments.push(format_ident!("DynEq").into());
derive_label(input, "RenderLabel", &trait_path, &dyn_eq_path)
derive_label(input, "RenderLabel", &trait_path)
}
/// Derive macro generating an impl of the trait `RenderSubGraph`.
@ -98,10 +96,8 @@ pub fn derive_render_sub_graph(input: TokenStream) -> TokenStream {
trait_path
.segments
.push(format_ident!("render_graph").into());
let mut dyn_eq_path = trait_path.clone();
trait_path
.segments
.push(format_ident!("RenderSubGraph").into());
dyn_eq_path.segments.push(format_ident!("DynEq").into());
derive_label(input, "RenderSubGraph", &trait_path, &dyn_eq_path)
derive_label(input, "RenderSubGraph", &trait_path)
}

View File

@ -0,0 +1,8 @@
---
title: Interned labels cleanup
pull_requests: [18984]
---
- `DynEq::as_any` has been removed. Use `&value as &dyn Any` instead.
- `DynHash::as_dyn_eq` has been removed. Use `&value as &dyn DynEq` instead.
- `as_dyn_eq` has been removed from 'label' types such as `ScheduleLabel` and `SystemSet`. Call `DynEq::dyn_eq` directly on the label instead.