Skip to content

Commit bf842a4

Browse files
committed
support generic hashed labels
1 parent 46d4226 commit bf842a4

File tree

3 files changed

+41
-6
lines changed

3 files changed

+41
-6
lines changed

crates/bevy_ecs/examples/derive_label.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{hash::Hash, marker::PhantomData};
1+
use std::{fmt::Debug, hash::Hash, marker::PhantomData};
22

33
use bevy_ecs::prelude::*;
44

@@ -93,3 +93,7 @@ pub struct BadLabel2 {
9393
pub struct ComplexLabel {
9494
people: Vec<&'static str>,
9595
}
96+
97+
#[derive(Debug, Clone, PartialEq, Eq, Hash, SystemLabel)]
98+
#[system_label(hash)]
99+
pub struct ComplexerLabel<T>(T);

crates/bevy_ecs/src/schedule/label.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
use std::fmt::Debug;
2+
13
use bevy_utils::{define_label, StableHashMap};
4+
use downcast_rs::{impl_downcast, Downcast};
25
use parking_lot::{RwLock, RwLockReadGuard};
36

47
pub use bevy_ecs_macros::{AmbiguitySetLabel, RunCriteriaLabel, StageLabel, SystemLabel};
@@ -75,3 +78,8 @@ impl<L> Labels<L> {
7578
RwLockReadGuard::try_map(self.0.read(), |map| map.get(&key)).ok()
7679
}
7780
}
81+
82+
#[doc(hidden)]
83+
pub trait DowncastDebug: Debug + Downcast {}
84+
impl<T: Debug + Downcast> DowncastDebug for T {}
85+
impl_downcast!(DowncastDebug);

crates/bevy_macro_utils/src/lib.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,14 @@ fn derive_hashed_label(
304304

305305
let ident = input.ident;
306306
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
307-
let where_clause = with_static_bound(where_clause);
307+
let mut where_clause = with_static_bound(where_clause);
308+
where_clause.predicates.push(
309+
syn::parse2(quote! {
310+
Self: ::std::clone::Clone + ::std::cmp::Eq + ::std::hash::Hash + ::std::fmt::Debug
311+
+ ::std::marker::Send + ::std::marker::Sync + 'static
312+
})
313+
.unwrap(),
314+
);
308315

309316
let compute_hash_path = {
310317
let mut path = manifest.get_path("bevy_utils");
@@ -331,15 +338,27 @@ fn derive_hashed_label(
331338
path.segments.push(format_ident!("LabelDowncast").into());
332339
path
333340
};
341+
let downcast_debug_path = {
342+
let mut path = manifest.get_path("bevy_ecs");
343+
path.segments.push(format_ident!("schedule").into());
344+
path.segments.push(format_ident!("DowncastDebug").into());
345+
path
346+
};
334347

335348
quote! {
336-
static #interner_ident : #interner_type_path <#ident #ty_generics> = #interner_type_path::new();
349+
// NOTE: We need to box the interned objects in order to deal with generics.
350+
// Unfortunately, we cannot associate data with generic impls, so they all must be
351+
// stored together.
352+
// FIXME: Make this concrete for types without generics.
353+
static #interner_ident
354+
: #interner_type_path <::std::boxed::Box::<dyn #downcast_debug_path + ::std::marker::Send + ::std::marker::Sync>>
355+
= #interner_type_path::new();
337356

338357
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
339358
#[inline]
340359
fn data(&self) -> u64 {
341360
let hash = #compute_hash_path(self);
342-
#interner_ident .intern(hash, || ::std::clone::Clone::clone(self));
361+
#interner_ident .intern(hash, || ::std::boxed::Box::new(::std::clone::Clone::clone(self)));
343362
hash
344363
}
345364
fn fmt(hash: u64, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
@@ -353,8 +372,12 @@ fn derive_hashed_label(
353372
type Output = #guard_type_path <'static, Self>;
354373
fn downcast_from(label: #id_path) -> Option<Self::Output> {
355374
let hash = <#id_path as #trait_path>::data(&label);
356-
#interner_ident .get(hash)
375+
<#guard_type_path<_>>::try_map(
376+
#interner_ident .get(hash)?,
377+
|val| <dyn #downcast_debug_path>::downcast_ref::<Self>(&**val),
378+
).ok()
357379
}
358380
}
359-
}.into()
381+
}
382+
.into()
360383
}

0 commit comments

Comments
 (0)