Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/label.rs
6601 views
1
//! Traits used by label implementations
2
3
use core::{
4
any::Any,
5
hash::{Hash, Hasher},
6
};
7
8
// Re-exported for use within `define_label!`
9
#[doc(hidden)]
10
pub use alloc::boxed::Box;
11
12
/// An object safe version of [`Eq`]. This trait is automatically implemented
13
/// for any `'static` type that implements `Eq`.
14
pub trait DynEq: Any {
15
/// This method tests for `self` and `other` values to be equal.
16
///
17
/// Implementers should avoid returning `true` when the underlying types are
18
/// not the same.
19
fn dyn_eq(&self, other: &dyn DynEq) -> bool;
20
}
21
22
// Tests that this trait is dyn-compatible
23
const _: Option<Box<dyn DynEq>> = None;
24
25
impl<T> DynEq for T
26
where
27
T: Any + Eq,
28
{
29
fn dyn_eq(&self, other: &dyn DynEq) -> bool {
30
if let Some(other) = (other as &dyn Any).downcast_ref::<T>() {
31
return self == other;
32
}
33
false
34
}
35
}
36
37
/// An object safe version of [`Hash`]. This trait is automatically implemented
38
/// for any `'static` type that implements `Hash`.
39
pub trait DynHash: DynEq {
40
/// Feeds this value into the given [`Hasher`].
41
fn dyn_hash(&self, state: &mut dyn Hasher);
42
}
43
44
// Tests that this trait is dyn-compatible
45
const _: Option<Box<dyn DynHash>> = None;
46
47
impl<T> DynHash for T
48
where
49
T: DynEq + Hash,
50
{
51
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
52
T::hash(self, &mut state);
53
self.type_id().hash(&mut state);
54
}
55
}
56
57
/// Macro to define a new label trait
58
///
59
/// # Example
60
///
61
/// ```
62
/// # use bevy_ecs::define_label;
63
/// define_label!(
64
/// /// Documentation of label trait
65
/// MyNewLabelTrait,
66
/// MY_NEW_LABEL_TRAIT_INTERNER
67
/// );
68
///
69
/// define_label!(
70
/// /// Documentation of another label trait
71
/// MyNewExtendedLabelTrait,
72
/// MY_NEW_EXTENDED_LABEL_TRAIT_INTERNER,
73
/// extra_methods: {
74
/// // Extra methods for the trait can be defined here
75
/// fn additional_method(&self) -> i32;
76
/// },
77
/// extra_methods_impl: {
78
/// // Implementation of the extra methods for Interned<dyn MyNewExtendedLabelTrait>
79
/// fn additional_method(&self) -> i32 {
80
/// 0
81
/// }
82
/// }
83
/// );
84
/// ```
85
#[macro_export]
86
macro_rules! define_label {
87
(
88
$(#[$label_attr:meta])*
89
$label_trait_name:ident,
90
$interner_name:ident
91
) => {
92
$crate::define_label!(
93
$(#[$label_attr])*
94
$label_trait_name,
95
$interner_name,
96
extra_methods: {},
97
extra_methods_impl: {}
98
);
99
};
100
(
101
$(#[$label_attr:meta])*
102
$label_trait_name:ident,
103
$interner_name:ident,
104
extra_methods: { $($trait_extra_methods:tt)* },
105
extra_methods_impl: { $($interned_extra_methods_impl:tt)* }
106
) => {
107
108
$(#[$label_attr])*
109
pub trait $label_trait_name: Send + Sync + ::core::fmt::Debug + $crate::label::DynEq + $crate::label::DynHash {
110
111
$($trait_extra_methods)*
112
113
/// Clones this `
114
#[doc = stringify!($label_trait_name)]
115
///`.
116
fn dyn_clone(&self) -> $crate::label::Box<dyn $label_trait_name>;
117
118
/// Returns an [`Interned`] value corresponding to `self`.
119
fn intern(&self) -> $crate::intern::Interned<dyn $label_trait_name>
120
where Self: Sized {
121
$interner_name.intern(self)
122
}
123
}
124
125
#[diagnostic::do_not_recommend]
126
impl $label_trait_name for $crate::intern::Interned<dyn $label_trait_name> {
127
128
$($interned_extra_methods_impl)*
129
130
fn dyn_clone(&self) -> $crate::label::Box<dyn $label_trait_name> {
131
(**self).dyn_clone()
132
}
133
134
fn intern(&self) -> Self {
135
*self
136
}
137
}
138
139
impl PartialEq for dyn $label_trait_name {
140
fn eq(&self, other: &Self) -> bool {
141
self.dyn_eq(other)
142
}
143
}
144
145
impl Eq for dyn $label_trait_name {}
146
147
impl ::core::hash::Hash for dyn $label_trait_name {
148
fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
149
self.dyn_hash(state);
150
}
151
}
152
153
impl $crate::intern::Internable for dyn $label_trait_name {
154
fn leak(&self) -> &'static Self {
155
$crate::label::Box::leak(self.dyn_clone())
156
}
157
158
fn ref_eq(&self, other: &Self) -> bool {
159
use ::core::ptr;
160
161
// Test that both the type id and pointer address are equivalent.
162
self.type_id() == other.type_id()
163
&& ptr::addr_eq(ptr::from_ref::<Self>(self), ptr::from_ref::<Self>(other))
164
}
165
166
fn ref_hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
167
use ::core::{hash::Hash, ptr};
168
169
// Hash the type id...
170
self.type_id().hash(state);
171
172
// ...and the pointer address.
173
// Cast to a unit `()` first to discard any pointer metadata.
174
ptr::from_ref::<Self>(self).cast::<()>().hash(state);
175
}
176
}
177
178
static $interner_name: $crate::intern::Interner<dyn $label_trait_name> =
179
$crate::intern::Interner::new();
180
};
181
}
182
183