1#[allow(unused_imports)]
2use super::*;
3use core::fmt::{self, Debug};
4use fnv::FnvHashMap;
5#[allow(unused_imports)]
6use paste::paste;
7use std::any::Any;
8use std::hash::{Hash, Hasher};
9use std::marker::Unsize;
10use std::ptr::{DynMetadata, Pointee};
11use type_erased_ptr::*;
12
13pub struct Component {
19 pub id: ComponentId,
20 objects: FnvHashMap<TypeId, Box<dyn Any + Send + Sync>>, traits: FnvHashMap<TypeId, TypeErasedPointer>, repeated: FnvHashMap<TypeId, Vec<TypeErasedPointer>>, refs: FnvHashMap<TypeId, ObjectRefs>, empty: Vec<TypeErasedPointer>,
25}
26
27impl Component {
28 pub fn new(tag: &str) -> Component {
30 Component {
31 id: next_component_id(tag),
32 objects: FnvHashMap::default(),
33 traits: FnvHashMap::default(),
34 repeated: FnvHashMap::default(),
35 empty: Vec::new(),
36 refs: FnvHashMap::default(),
37 }
38 }
39
40 #[doc(hidden)]
42 pub fn add_trait<Trait, Object>(
43 &mut self,
44 object_id: TypeId,
45 trait_id: TypeId,
46 obj_ptr: *mut Object,
47 ) where
48 Trait: ?Sized + Pointee<Metadata = DynMetadata<Trait>> + 'static,
49 Object: Unsize<Trait> + 'static,
50 {
51 let erased = TypeErasedPointer::from_trait::<Object, Trait>(object_id, obj_ptr);
52 let old = self.traits.insert(trait_id, erased);
53 assert!(old.is_none(), "trait was already added to the component");
54 }
55
56 #[doc(hidden)]
58 pub fn add_repeated_trait<Trait, Object>(
59 &mut self,
60 object_id: TypeId,
61 trait_id: TypeId,
62 obj_ptr: *mut Object,
63 ) where
64 Trait: ?Sized + Pointee<Metadata = DynMetadata<Trait>> + 'static,
65 Object: Unsize<Trait> + 'static,
66 {
67 let erased = TypeErasedPointer::from_trait::<Object, Trait>(object_id, obj_ptr);
68 let pointers = self.repeated.entry(trait_id).or_insert(vec![]);
69 pointers.push(erased);
70 }
71
72 #[doc(hidden)]
74 pub fn add_object<Object>(&mut self, obj_id: TypeId, obj_ptr: *mut Object)
75 where
76 Object: Send + Sync + 'static,
77 {
78 let erased: Box<dyn Any + Send + Sync> = unsafe { Box::from_raw(obj_ptr) };
79 let old = self.objects.insert(obj_id, erased);
80 assert!(
81 old.is_none(),
82 "object type was already added to the component"
83 );
84
85 self.refs.entry(obj_id).or_insert(ObjectRefs::new());
86 }
87
88 #[doc(hidden)]
95 pub fn has<Trait>(&self, trait_id: TypeId) -> bool
96 where
97 Trait: ?Sized + Pointee<Metadata = DynMetadata<Trait>> + 'static,
98 {
99 self.traits.get(&trait_id).is_some()
100 }
101
102 #[doc(hidden)]
104 pub fn find<Trait>(&self, trait_id: TypeId) -> Option<RefTrait<Trait>>
105 where
106 Trait: ?Sized + Pointee<Metadata = DynMetadata<Trait>> + 'static,
107 {
108 if let Some(erased) = self.traits.get(&trait_id) {
109 let refs = self.refs.get(&erased.object_id).unwrap();
110 let r = unsafe { erased.to_trait::<Trait>(refs) };
111 Some(r)
112 } else {
113 None
114 }
115 }
116
117 #[doc(hidden)]
119 pub fn find_mut<Trait>(&self, trait_id: TypeId) -> Option<RefMutTrait<Trait>>
120 where
121 Trait: ?Sized + Pointee<Metadata = DynMetadata<Trait>> + 'static,
122 {
123 if let Some(erased) = self.traits.get(&trait_id) {
124 let refs = self.refs.get(&erased.object_id).unwrap();
125 let r = unsafe { erased.to_trait_mut::<Trait>(refs) };
126 Some(r)
127 } else {
128 None
129 }
130 }
131
132 #[doc(hidden)]
134 pub fn find_repeated<Trait>(&self, trait_id: TypeId) -> impl Iterator<Item = RefTrait<Trait>>
135 where
136 Trait: ?Sized + Pointee<Metadata = DynMetadata<Trait>> + 'static,
137 {
138 self.repeated
139 .get(&trait_id)
140 .unwrap_or(&self.empty)
141 .iter()
142 .map(|e| unsafe {
143 let refs = self.refs.get(&e.object_id).unwrap();
144 e.to_trait::<Trait>(refs)
145 })
146 }
147
148 #[doc(hidden)]
150 pub fn find_repeated_mut<Trait>(
151 &self,
152 trait_id: TypeId,
153 ) -> impl Iterator<Item = RefMutTrait<Trait>>
154 where
155 Trait: ?Sized + Pointee<Metadata = DynMetadata<Trait>> + 'static,
156 {
157 self.repeated
158 .get(&trait_id)
159 .unwrap_or(&self.empty)
160 .iter()
161 .map(|e| unsafe {
162 let refs = self.refs.get(&e.object_id).unwrap();
163 e.to_trait_mut::<Trait>(refs)
164 })
165 }
166}
167
168#[macro_export]
183macro_rules! register_type {
184 ($type:ty) => {
185 paste! {
186 pub fn [<get_ $type:lower _id>]() -> TypeId {
187 unique_type_id!()
188 }
189 }
190 };
191}
192
193#[doc(hidden)]
195#[macro_export]
196macro_rules! add_traits {
197 ($component:expr, $obj_type:ty, $obj_ptr:expr, $trait1:ty) => {{
198 paste! {
199 $component.add_trait::<dyn $trait1, $obj_type>(
200 [<get_ $obj_type:lower _id>](),
201 [<get_ $trait1:lower _id>](),
202 $obj_ptr);
203 }
204 }};
205
206 ($component:expr, $obj_type:ty, $obj_ptr:expr, $trait1:ty, $($trait2:ty),+) => {{
207 add_traits!($component, $obj_type, $obj_ptr, $trait1);
208 add_traits!($component, $obj_type, $obj_ptr, $($trait2),+)
209 }};
210}
211
212#[doc(hidden)]
214#[macro_export]
215macro_rules! add_repeated_traits {
216 ($component:expr, $obj_type:ty, $obj_ptr:expr, $trait1:ty) => {{
217 paste! {
218 $component.add_repeated_trait::<dyn $trait1, $obj_type>(
219 [<get_ $obj_type:lower _id>](),
220 [<get_ $trait1:lower _id>](),
221 $obj_ptr);
222 }
223 }};
224
225 ($component:expr, $obj_type:ty, $obj_ptr:expr, $trait1:ty, $($trait2:ty),+) => {{
226 add_repeated_traits!($component, $obj_type, $obj_ptr, $trait1);
227 add_repeated_traits!($component, $obj_type, $obj_ptr, $($trait2),+)
228 }};
229}
230
231#[macro_export]
269macro_rules! add_object {
270 ($component:expr, $obj_type:ty, $object:expr, [$trait1:ty]) => {{ paste! {
272 let boxed = Box::new($object);
273 let obj_ptr = Box::into_raw(boxed);
274 add_traits!($component, $obj_type, obj_ptr, $trait1);
275 $component.add_object::<$obj_type>(
276 [<get_ $obj_type:lower _id>](),
277 obj_ptr);
278 }
279 }};
280
281 ($component:expr, $obj_type:ty, $object:expr, [$trait1:ty], [$trait2:ty]) => {{ paste! {
283 let boxed = Box::new($object);
284 let obj_ptr = Box::into_raw(boxed);
285 add_traits!($component, $obj_type, obj_ptr, $trait1);
286 add_repeated_traits!($component, $obj_type, obj_ptr, $trait2);
287 $component.add_object::<$obj_type>(
288 [<get_ $obj_type:lower _id>](),
289 obj_ptr);
290 }
291 }};
292
293 ($component:expr, $obj_type:ty, $object:expr, [$trait1:ty], [$trait2:ty, $($trait3:ty),+]) => {{ paste! {
295 let boxed = Box::new($object);
296 let obj_ptr = Box::into_raw(boxed);
297 add_traits!($component, $obj_type, obj_ptr, $trait1);
298 add_repeated_traits!($component, $obj_type, obj_ptr, $trait2);
299 add_repeated_traits!($component, $obj_type, obj_ptr, $($trait3),+);
300 $component.add_object::<$obj_type>(
301 [<get_ $obj_type:lower _id>](),
302 obj_ptr);
303 }
304 }};
305
306 ($component:expr, $obj_type:ty, $object:expr, [$trait1:ty, $($trait2:ty),+]) => {{ paste! {
308 let boxed = Box::new($object);
309 let obj_ptr = Box::into_raw(boxed);
310 add_traits!($component, $obj_type, obj_ptr, $trait1);
311 add_traits!($component, $obj_type, obj_ptr, $($trait2),+);
312 $component.add_object::<$obj_type>(
313 [<get_ $obj_type:lower _id>](),
314 obj_ptr);
315 }
316 }};
317
318 ($component:expr, $obj_type:ty, $object:expr, [$trait1:ty, $($trait2:ty),+], [$trait3:ty]) => {{ paste! {
320 let boxed = Box::new($object);
321 let obj_ptr = Box::into_raw(boxed);
322 add_traits!($component, $obj_type, obj_ptr, $trait1);
323 add_traits!($component, $obj_type, obj_ptr, $($trait2),+);
324 add_repeated_traits!($component, $obj_type, obj_ptr, $trait3);
325 $component.add_object::<$obj_type>(
326 [<get_ $obj_type:lower _id>](),
327 obj_ptr);
328 }
329 }};
330
331 ($component:expr, $obj_type:ty, $object:expr, [$trait1:ty, $($trait2:ty),+], [$trait3:ty, $($trait4:ty),+]) => {{ paste! {
333 let boxed = Box::new($object);
334 let obj_ptr = Box::into_raw(boxed);
335 add_traits!($component, $obj_type, obj_ptr, $trait1);
336 add_traits!($component, $obj_type, obj_ptr, $($trait2),+);
337 add_repeated_traits!($component, $obj_type, obj_ptr, $trait3);
338 add_repeated_traits!($component, $obj_type, obj_ptr, $($trait4),+);
339 $component.add_object::<$obj_type>(
340 [<get_ $obj_type:lower _id>](),
341 obj_ptr);
342 }
343 }};
344}
345
346#[macro_export]
347macro_rules! has_trait {
348 ($component:expr, $trait:ty) => {{
349 paste! {
350 $component.has::<dyn $trait>([<get_ $trait:lower _id>]())
351 }
352 }};
353}
354
355#[macro_export]
386macro_rules! find_trait {
387 ($component:expr, $trait:ty) => {{
388 paste! {
389 $component.find::<dyn $trait>([<get_ $trait:lower _id>]())
390 }
391 }};
392}
393
394#[macro_export]
400macro_rules! find_trait_mut {
401 ($component:expr, $trait:ty) => {{
402 paste! {
403 $component.find_mut::<dyn $trait>([<get_ $trait:lower _id>]())
404 }
405 }};
406}
407
408#[macro_export]
411macro_rules! find_repeated_trait {
412 ($component:expr, $trait:ty) => {{
413 paste! {
414 $component.find_repeated::<dyn $trait>([<get_ $trait:lower _id>]())
415 }
416 }};
417}
418
419#[macro_export]
422macro_rules! find_repeated_trait_mut {
423 ($component:expr, $trait:ty) => {{
424 paste! {
425 $component.find_repeated_mut::<dyn $trait>([<get_ $trait:lower _id>]())
426 }
427 }};
428}
429
430impl PartialEq for Component {
431 fn eq(&self, other: &Component) -> bool {
432 self.id == other.id
433 }
434}
435
436impl Eq for Component {}
437
438impl Ord for Component {
439 fn cmp(&self, rhs: &Self) -> std::cmp::Ordering {
440 self.id.cmp(&rhs.id)
441 }
442}
443
444impl PartialOrd for Component {
445 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
446 Some(self.cmp(other))
447 }
448}
449
450impl Hash for Component {
451 fn hash<H: Hasher>(&self, state: &mut H) {
452 self.id.hash(state);
453 }
454}
455
456impl Debug for Component {
457 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
458 writeln!(f, "{:?}", self.id)?;
459 for d in find_repeated_trait!(self, Debug) {
460 d.fmt(f)?;
461 }
462 fmt::Result::Ok(())
463 }
464}
465register_type!(Debug);
466
467#[cfg(test)]
468mod tests {
469 use super::*;
470 use std::fmt::Display;
471 use std::sync::atomic::AtomicU8;
472 use std::sync::atomic::Ordering;
473
474 trait Fruit {
475 fn eat(&self) -> String;
476 }
477 register_type!(Fruit);
478
479 trait Ball {
480 fn throw(&self) -> String;
481 }
482 register_type!(Ball);
483
484 struct Apple {}
485 register_type!(Apple);
486
487 impl Fruit for Apple {
488 fn eat(&self) -> String {
489 "yum!".to_owned()
490 }
491 }
492
493 impl Ball for Apple {
494 fn throw(&self) -> String {
495 "splat".to_owned()
496 }
497 }
498
499 impl fmt::Display for Apple {
500 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
501 write!(f, "Apple")
502 }
503 }
504 register_type!(Display);
505
506 trait Ripe {
507 fn ripeness(&self) -> i32;
508 fn ripen(&mut self);
509 }
510 register_type!(Ripe);
511 struct Banana {
512 ripeness: i32,
513 }
514 register_type!(Banana);
515
516 impl Ripe for Banana {
517 fn ripeness(&self) -> i32 {
518 self.ripeness
519 }
520
521 fn ripen(&mut self) {
522 self.ripeness += 1;
523 }
524 }
525
526 impl Fruit for Banana {
527 fn eat(&self) -> String {
528 "mushy".to_owned()
529 }
530 }
531
532 impl fmt::Display for Banana {
533 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
534 write!(f, "Banana")
535 }
536 }
537
538 static DROP_COUNT: AtomicU8 = AtomicU8::new(0);
539
540 struct Football {}
541 register_type!(Football);
542
543 impl Ball for Football {
544 fn throw(&self) -> String {
545 "touchdown".to_owned()
546 }
547 }
548
549 impl Drop for Football {
550 fn drop(&mut self) {
551 DROP_COUNT.fetch_add(1, Ordering::Relaxed);
552 }
553 }
554
555 #[test]
556 fn two_traits() {
557 let apple = Apple {};
558 let mut component = Component::new("apple");
559 add_object!(component, Apple, apple, [Fruit, Ball]);
560
561 let fruit = find_trait!(component, Fruit);
562 assert!(fruit.is_some());
563 assert_eq!(fruit.unwrap().eat(), "yum!");
564
565 let ball = find_trait!(component, Ball);
566 assert!(ball.is_some());
567 assert_eq!(ball.unwrap().throw(), "splat");
568 }
569
570 #[test]
571 fn has() {
572 let apple = Apple {};
573 let mut component = Component::new("apple");
574 add_object!(component, Apple, apple, [Fruit, Ball]);
575
576 assert!(has_trait!(component, Fruit));
577 assert!(!has_trait!(component, Ripe));
578 }
579
580 #[test]
581 fn missing_trait() {
582 let banana = Banana { ripeness: 0 };
583 let mut component = Component::new("banana");
584 add_object!(component, Banana, banana, [Fruit]);
585
586 let fruit = find_trait!(component, Fruit);
587 assert!(fruit.is_some());
588 assert_eq!(fruit.unwrap().eat(), "mushy");
589
590 let ball = find_trait!(component, Ball);
591 assert!(ball.is_none());
592 }
593
594 #[test]
595 fn dropped_object() {
596 assert_eq!(DROP_COUNT.load(Ordering::Relaxed), 0);
597 {
598 let football = Football {};
599 let mut component = Component::new("football");
600 add_object!(component, Football, football, [Ball]);
601
602 let ball = find_trait!(component, Ball);
603 assert!(ball.is_some());
604 assert_eq!(ball.unwrap().throw(), "touchdown");
605 }
606 assert_eq!(DROP_COUNT.load(Ordering::Relaxed), 1);
607 }
608
609 #[test]
610 fn mutable_find() {
611 let banana = Banana { ripeness: 0 };
612 let mut component = Component::new("banana");
613 add_object!(component, Banana, banana, [Fruit, Ripe]);
614
615 {
616 let ripe = find_trait!(component, Ripe).unwrap();
617 assert_eq!(ripe.ripeness(), 0);
618 }
619
620 {
621 let mut ripe = find_trait_mut!(component, Ripe).unwrap();
622 ripe.ripen();
623 ripe.ripen();
624
625 }
629
630 let ripe = find_trait!(component, Ripe).unwrap(); assert_eq!(ripe.ripeness(), 2);
632 }
633
634 #[test]
635 fn repeated() {
636 let banana = Banana { ripeness: 0 };
637 let apple = Apple {};
638 let mut component = Component::new("banana");
639 add_object!(component, Banana, banana, [Fruit, Ripe], [Display]);
640 add_object!(component, Apple, apple, [Ball], [Display]);
641
642 let displays: Vec<String> = find_repeated_trait!(component, Display)
646 .map(|t| format!("{}", &(*t)))
647 .collect();
648 assert_eq!(displays.len(), 2);
649 assert!(
650 (displays[0] == "Apple" && displays[1] == "Banana")
651 || (displays[1] == "Apple" && displays[0] == "Banana")
652 );
653 }
654}
655
656#[cfg(test)]
657mod thread_tests {
658 use super::*;
659 use std::{
660 sync::{Arc, RwLock},
661 thread,
662 };
663
664 trait Name {
665 fn get(&self) -> &str;
666 fn get_mut(&mut self) -> &mut String;
667 }
668 register_type!(Name);
669
670 struct Thing {
671 name: String,
672 }
673 register_type!(Thing);
674
675 impl Name for Thing {
676 fn get(&self) -> &str {
677 &self.name
678 }
679
680 fn get_mut(&mut self) -> &mut String {
681 &mut self.name
682 }
683 }
684
685 #[test]
686 fn threading() {
687 let thing = Thing {
688 name: "hello world".to_owned(),
689 };
690 let mut component = Component::new("thing");
691 add_object!(component, Thing, thing, [Name]);
692
693 let gstate = Arc::new(RwLock::new(component));
694
695 let state = gstate.clone();
696 let thread1 = thread::spawn(move || {
697 for _ in 0..100 {
698 {
699 let component = state.write().unwrap();
700 let mut name = find_trait_mut!(component, Name).unwrap();
701 let name = name.get_mut();
702 if name.len() < 30 {
703 name.insert(6, '_');
704 }
705 }
706 thread::yield_now();
707 }
708 });
709
710 let state = gstate.clone();
711 let thread2 = thread::spawn(move || {
712 for _ in 0..100 {
713 {
714 let component = state.write().unwrap();
715 let mut name = find_trait_mut!(component, Name).unwrap();
716 let name = name.get_mut();
717 if name.len() > 11 {
718 name.remove(6);
719 }
720 }
721 thread::yield_now();
722 }
723 });
724
725 thread1.join().unwrap();
726 thread2.join().unwrap();
727
728 let component = &gstate.read().unwrap();
729 let name = find_trait!(component, Name).unwrap();
730 let name = name.get();
731 assert!(name.starts_with("hello"));
732 assert!(name.ends_with("world"));
733 }
734}