1use core::{
4 any::Any,
5 hash::{Hash, Hasher},
6};
7
8#[doc(hidden)]
10pub use alloc::boxed::Box;
11
12pub trait DynEq: Any {
15 fn as_any(&self) -> &dyn Any;
17
18 fn dyn_eq(&self, other: &dyn DynEq) -> bool;
23}
24
25impl<T> DynEq for T
26where
27 T: Any + Eq,
28{
29 fn as_any(&self) -> &dyn Any {
30 self
31 }
32
33 fn dyn_eq(&self, other: &dyn DynEq) -> bool {
34 if let Some(other) = other.as_any().downcast_ref::<T>() {
35 return self == other;
36 }
37 false
38 }
39}
40
41pub trait DynHash: DynEq {
44 fn as_dyn_eq(&self) -> &dyn DynEq;
46
47 fn dyn_hash(&self, state: &mut dyn Hasher);
49}
50
51impl<T> DynHash for T
52where
53 T: DynEq + Hash,
54{
55 fn as_dyn_eq(&self) -> &dyn DynEq {
56 self
57 }
58
59 fn dyn_hash(&self, mut state: &mut dyn Hasher) {
60 T::hash(self, &mut state);
61 self.type_id().hash(&mut state);
62 }
63}
64
65#[macro_export]
94macro_rules! define_label {
95 (
96 $(#[$label_attr:meta])*
97 $label_trait_name:ident,
98 $interner_name:ident
99 ) => {
100 $crate::define_label!(
101 $(#[$label_attr])*
102 $label_trait_name,
103 $interner_name,
104 extra_methods: {},
105 extra_methods_impl: {}
106 );
107 };
108 (
109 $(#[$label_attr:meta])*
110 $label_trait_name:ident,
111 $interner_name:ident,
112 extra_methods: { $($trait_extra_methods:tt)* },
113 extra_methods_impl: { $($interned_extra_methods_impl:tt)* }
114 ) => {
115
116 $(#[$label_attr])*
117 pub trait $label_trait_name: 'static + Send + Sync + ::core::fmt::Debug {
118
119 $($trait_extra_methods)*
120
121 #[doc = stringify!($label_trait_name)]
123 fn dyn_clone(&self) -> $crate::label::Box<dyn $label_trait_name>;
125
126 fn as_dyn_eq(&self) -> &dyn $crate::label::DynEq;
128
129 fn dyn_hash(&self, state: &mut dyn ::core::hash::Hasher);
131
132 fn intern(&self) -> $crate::intern::Interned<dyn $label_trait_name>
134 where Self: Sized {
135 $interner_name.intern(self)
136 }
137 }
138
139 impl $label_trait_name for $crate::intern::Interned<dyn $label_trait_name> {
140
141 $($interned_extra_methods_impl)*
142
143 fn dyn_clone(&self) -> $crate::label::Box<dyn $label_trait_name> {
144 (**self).dyn_clone()
145 }
146
147 fn as_dyn_eq(&self) -> &dyn $crate::label::DynEq {
149 (**self).as_dyn_eq()
150 }
151
152 fn dyn_hash(&self, state: &mut dyn ::core::hash::Hasher) {
153 (**self).dyn_hash(state);
154 }
155
156 fn intern(&self) -> Self {
157 *self
158 }
159 }
160
161 impl PartialEq for dyn $label_trait_name {
162 fn eq(&self, other: &Self) -> bool {
163 self.as_dyn_eq().dyn_eq(other.as_dyn_eq())
164 }
165 }
166
167 impl Eq for dyn $label_trait_name {}
168
169 impl ::core::hash::Hash for dyn $label_trait_name {
170 fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
171 self.dyn_hash(state);
172 }
173 }
174
175 impl $crate::intern::Internable for dyn $label_trait_name {
176 fn leak(&self) -> &'static Self {
177 Box::leak(self.dyn_clone())
178 }
179
180 fn ref_eq(&self, other: &Self) -> bool {
181 use ::core::ptr;
182
183 self.as_dyn_eq().type_id() == other.as_dyn_eq().type_id()
185 && ptr::addr_eq(ptr::from_ref::<Self>(self), ptr::from_ref::<Self>(other))
186 }
187
188 fn ref_hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
189 use ::core::{hash::Hash, ptr};
190
191 self.as_dyn_eq().type_id().hash(state);
193
194 ptr::from_ref::<Self>(self).cast::<()>().hash(state);
197 }
198 }
199
200 static $interner_name: $crate::intern::Interner<dyn $label_trait_name> =
201 $crate::intern::Interner::new();
202 };
203}
204
205#[cfg(test)]
206mod tests {
207 use super::{DynEq, DynHash};
208 use bevy_utils::assert_object_safe;
209
210 #[test]
211 fn dyn_eq_object_safe() {
212 assert_object_safe::<dyn DynEq>();
213 }
214
215 #[test]
216 fn dyn_hash_object_safe() {
217 assert_object_safe::<dyn DynHash>();
218 }
219}