Skip to content

Commit 6341f2a

Browse files
committed
don't box non-generic hashed labels
1 parent cbe61bc commit 6341f2a

File tree

1 file changed

+35
-15
lines changed
  • crates/bevy_macro_utils/src

1 file changed

+35
-15
lines changed

crates/bevy_macro_utils/src/lib.rs

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -345,29 +345,53 @@ fn derive_hashed_label(
345345
path
346346
};
347347

348-
let boxed_ty = quote! { ::std::boxed::Box::<dyn #downcast_debug_path + ::std::marker::Send + ::std::marker::Sync> };
348+
// If the type is generic, we need to box it before interning it.
349+
// Since Rust does not currently allow us to have generic types with associated statics,
350+
// all of the labels for any generic type must be interned in the same global.
351+
let is_generic = !input.generics.params.is_empty();
352+
353+
let interner_generics = if !is_generic {
354+
quote! { <u64, #ident> }
355+
} else {
356+
let boxed_ty = quote! { ::std::boxed::Box::<dyn #downcast_debug_path + ::std::marker::Send + ::std::marker::Sync> };
357+
quote! { <(u64, ::std::any::TypeId), #boxed_ty> }
358+
};
359+
360+
let mut clone_expr = quote! { ::std::clone::Clone::clone(self) };
361+
if is_generic {
362+
clone_expr = quote! { ::std::boxed::Box::new(#clone_expr) };
363+
}
364+
365+
let key_expr = if !is_generic {
366+
quote! { hash }
367+
} else {
368+
quote! { (hash, ::std::any::TypeId::of::<Self>()) }
369+
};
370+
371+
let mut get_expr = quote! { #interner_ident .get(#key_expr) };
372+
if is_generic {
373+
let try_map = quote! { <#guard_type_path<_>>::try_map };
374+
let downcast = quote! { <dyn #downcast_debug_path>::downcast_ref };
375+
get_expr = quote! {
376+
#try_map(#get_expr?, |val| #downcast::<Self>(&**val)).ok()
377+
};
378+
}
349379

350380
quote! {
351-
// NOTE: We need to box the interned objects in order to deal with generics.
352-
// Unfortunately, we cannot associate data with generic impls, so they all must be
353-
// stored together.
354-
// FIXME: Make this concrete for types without generics.
355381
static #interner_ident
356-
: #interner_type_path <(u64, ::std::any::TypeId), #boxed_ty>
382+
: #interner_type_path #interner_generics
357383
= #interner_type_path::new();
358384

359385
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
360386
#[inline]
361387
fn data(&self) -> u64 {
362388
let hash = #compute_hash_path(self);
363-
let key = (hash, ::std::any::TypeId::of::<Self>());
364-
#interner_ident .intern(key, || ::std::boxed::Box::new(::std::clone::Clone::clone(self)));
389+
#interner_ident .intern(#key_expr, || #clone_expr);
365390
hash
366391
}
367392
fn fmt(hash: u64, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
368-
let key = (hash, ::std::any::TypeId::of::<Self>());
369393
#interner_ident
370-
.scope(key, |val| ::std::fmt::Debug::fmt(val, f))
394+
.scope(#key_expr, |val| ::std::fmt::Debug::fmt(val, f))
371395
.ok_or(::std::fmt::Error)?
372396
}
373397
}
@@ -376,11 +400,7 @@ fn derive_hashed_label(
376400
type Output = #guard_type_path <'static, Self>;
377401
fn downcast_from(label: #id_path) -> Option<Self::Output> {
378402
let hash = <#id_path as #trait_path>::data(&label);
379-
let key = (hash, ::std::any::TypeId::of::<Self>());
380-
<#guard_type_path<_>>::try_map(
381-
#interner_ident .get(key)?,
382-
|val| <dyn #downcast_debug_path>::downcast_ref::<Self>(&**val),
383-
).ok()
403+
#get_expr
384404
}
385405
}
386406
}

0 commit comments

Comments
 (0)