goud_engine/ecs/schedule/
system_label.rs1use std::any::TypeId;
4use std::fmt;
5use std::hash::{Hash, Hasher};
6
7use super::stage_label::DynHasherWrapper;
8
9pub trait SystemLabel: Send + Sync + 'static {
29 fn label_id(&self) -> TypeId;
31
32 fn label_name(&self) -> &'static str;
34
35 fn dyn_clone(&self) -> Box<dyn SystemLabel>;
37
38 fn dyn_eq(&self, other: &dyn SystemLabel) -> bool {
40 self.label_id() == other.label_id()
41 }
42
43 fn dyn_hash(&self, state: &mut dyn Hasher) {
45 self.label_id().hash(&mut DynHasherWrapper(state));
46 }
47}
48
49impl Clone for Box<dyn SystemLabel> {
50 fn clone(&self) -> Self {
51 self.dyn_clone()
52 }
53}
54
55impl PartialEq for dyn SystemLabel {
56 fn eq(&self, other: &Self) -> bool {
57 self.dyn_eq(other)
58 }
59}
60
61impl Eq for dyn SystemLabel {}
62
63impl Hash for dyn SystemLabel {
64 fn hash<H: Hasher>(&self, state: &mut H) {
65 self.label_id().hash(state);
66 }
67}
68
69impl fmt::Debug for dyn SystemLabel {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 write!(f, "SystemLabel({})", self.label_name())
72 }
73}
74
75#[derive(Clone)]
93pub struct SystemLabelId(Box<dyn SystemLabel>);
94
95impl SystemLabelId {
96 pub fn of<L: SystemLabel + Clone>(label: L) -> Self {
98 Self(Box::new(label))
99 }
100
101 #[inline]
103 pub fn name(&self) -> &'static str {
104 self.0.label_name()
105 }
106
107 #[inline]
109 pub fn type_id(&self) -> TypeId {
110 self.0.label_id()
111 }
112
113 #[inline]
115 pub fn inner(&self) -> &dyn SystemLabel {
116 &*self.0
117 }
118}
119
120impl PartialEq for SystemLabelId {
121 fn eq(&self, other: &Self) -> bool {
122 self.0.label_id() == other.0.label_id()
123 }
124}
125
126impl Eq for SystemLabelId {}
127
128impl Hash for SystemLabelId {
129 fn hash<H: Hasher>(&self, state: &mut H) {
130 self.0.label_id().hash(state);
131 }
132}
133
134impl fmt::Debug for SystemLabelId {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 write!(f, "SystemLabelId({})", self.0.label_name())
137 }
138}
139
140impl fmt::Display for SystemLabelId {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 write!(f, "{}", self.0.label_name())
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use crate::ecs::schedule::CoreSystemLabel;
150 use std::collections::HashMap;
151
152 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
153 struct CustomLabel;
154
155 impl SystemLabel for CustomLabel {
156 fn label_id(&self) -> TypeId {
157 TypeId::of::<Self>()
158 }
159 fn label_name(&self) -> &'static str {
160 "CustomLabel"
161 }
162 fn dyn_clone(&self) -> Box<dyn SystemLabel> {
163 Box::new(*self)
164 }
165 }
166
167 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
168 struct AnotherLabel;
169
170 impl SystemLabel for AnotherLabel {
171 fn label_id(&self) -> TypeId {
172 TypeId::of::<Self>()
173 }
174 fn label_name(&self) -> &'static str {
175 "AnotherLabel"
176 }
177 fn dyn_clone(&self) -> Box<dyn SystemLabel> {
178 Box::new(*self)
179 }
180 }
181
182 #[test]
185 fn test_custom_label_name() {
186 assert_eq!(CustomLabel.label_name(), "CustomLabel");
187 }
188
189 #[test]
190 fn test_custom_label_id() {
191 assert_eq!(CustomLabel.label_id(), TypeId::of::<CustomLabel>());
192 }
193
194 #[test]
195 fn test_custom_label_dyn_clone() {
196 let cloned = CustomLabel.dyn_clone();
197 assert_eq!(cloned.label_name(), "CustomLabel");
198 }
199
200 #[test]
201 fn test_dyn_eq_same() {
202 assert!(CustomLabel.dyn_eq(&CustomLabel));
203 }
204
205 #[test]
206 fn test_dyn_eq_different() {
207 assert!(!CustomLabel.dyn_eq(&AnotherLabel));
208 }
209
210 #[test]
211 fn test_box_clone() {
212 let label: Box<dyn SystemLabel> = Box::new(CustomLabel);
213 let cloned = label.clone();
214 assert_eq!(label.label_name(), cloned.label_name());
215 }
216
217 #[test]
218 fn test_dyn_partial_eq() {
219 let a: &dyn SystemLabel = &CustomLabel;
220 let b: &dyn SystemLabel = &CustomLabel;
221 assert!(a == b);
222 }
223
224 #[test]
225 fn test_dyn_hash() {
226 use std::collections::hash_map::DefaultHasher;
227 let a: &dyn SystemLabel = &CustomLabel;
228 let b: &dyn SystemLabel = &CustomLabel;
229 let mut hasher_a = DefaultHasher::new();
230 let mut hasher_b = DefaultHasher::new();
231 a.hash(&mut hasher_a);
232 b.hash(&mut hasher_b);
233 assert_eq!(hasher_a.finish(), hasher_b.finish());
234 }
235
236 #[test]
237 fn test_dyn_debug() {
238 let label: &dyn SystemLabel = &CustomLabel;
239 let debug = format!("{:?}", label);
240 assert!(debug.contains("CustomLabel"));
241 }
242
243 #[test]
244 fn test_system_label_send_sync() {
245 fn assert_send<T: Send>() {}
246 fn assert_sync<T: Sync>() {}
247 assert_send::<CustomLabel>();
248 assert_sync::<CustomLabel>();
249 }
250
251 #[test]
254 fn test_of() {
255 let id = SystemLabelId::of(CustomLabel);
256 assert_eq!(id.name(), "CustomLabel");
257 }
258
259 #[test]
260 fn test_name() {
261 let id = SystemLabelId::of(CoreSystemLabel::Physics);
262 assert_eq!(id.name(), "Physics");
263 }
264
265 #[test]
266 fn test_type_id() {
267 let id = SystemLabelId::of(CustomLabel);
268 assert_eq!(id.type_id(), TypeId::of::<CustomLabel>());
269 }
270
271 #[test]
272 fn test_inner() {
273 let id = SystemLabelId::of(CoreSystemLabel::Input);
274 assert_eq!(id.inner().label_name(), "Input");
275 }
276
277 #[test]
278 fn test_equality_same() {
279 let a = SystemLabelId::of(CustomLabel);
280 let b = SystemLabelId::of(CustomLabel);
281 assert_eq!(a, b);
282 }
283
284 #[test]
285 fn test_equality_different() {
286 let a = SystemLabelId::of(CustomLabel);
287 let b = SystemLabelId::of(CoreSystemLabel::Physics);
288 assert_ne!(a, b);
289 }
290
291 #[test]
292 fn test_hash() {
293 use std::collections::hash_map::DefaultHasher;
294 let a = SystemLabelId::of(CustomLabel);
295 let b = SystemLabelId::of(CustomLabel);
296 let mut hasher_a = DefaultHasher::new();
297 let mut hasher_b = DefaultHasher::new();
298 a.hash(&mut hasher_a);
299 b.hash(&mut hasher_b);
300 assert_eq!(hasher_a.finish(), hasher_b.finish());
301 }
302
303 #[test]
304 fn test_debug() {
305 let id = SystemLabelId::of(CustomLabel);
306 assert!(format!("{:?}", id).contains("CustomLabel"));
307 }
308
309 #[test]
310 fn test_display() {
311 let id = SystemLabelId::of(CoreSystemLabel::Audio);
312 assert_eq!(format!("{}", id), "Audio");
313 }
314
315 #[test]
316 fn test_clone() {
317 let id = SystemLabelId::of(CustomLabel);
318 let cloned = id.clone();
319 assert_eq!(id, cloned);
320 }
321
322 #[test]
323 fn test_in_hashmap() {
324 let mut map = HashMap::new();
325 let id = SystemLabelId::of(CustomLabel);
326 map.insert(id.clone(), "value");
327 assert_eq!(map.get(&id), Some(&"value"));
328 }
329}