1use bevy_ptr::OwningPtr;
2use worlds_derive::all_tuples;
3
4use crate::prelude::{Component, ComponentFactory, ComponentId};
5
6pub trait Bundle {
8 fn raw_components_scope(
11 self,
12 comp_factory: &ComponentFactory,
13 f: &mut impl FnMut(ComponentId, OwningPtr<'_>),
14 );
15}
16
17impl<C: Component> Bundle for C {
18 fn raw_components_scope(
19 self,
20 comp_factory: &ComponentFactory,
21 f: &mut impl FnMut(ComponentId, OwningPtr<'_>),
22 ) {
23 OwningPtr::make(self, |ptr| {
24 f(
25 comp_factory.get_component_id::<C>().unwrap(),
26 ptr,
28 )
29 })
30 }
31}
32
33macro_rules! impl_bundle_for_tuple {
34 ($($name:ident),*) => {
35 impl<$($name: Bundle),*> Bundle for ($($name,)*) {
36 #[allow(non_snake_case, unused)]
37 fn raw_components_scope(self, comp_factory: &ComponentFactory, f: &mut impl FnMut(ComponentId, OwningPtr<'_>)) {
38 let ($($name,)*) = self;
39 $($name.raw_components_scope(comp_factory, f);)*
40 }
41 }
42 };
43}
44
45all_tuples!(impl_bundle_for_tuple, 0, 12, B);
46
47#[cfg(test)]
48mod tests {
49 use crate::prelude::*;
50 use worlds_derive::Component;
51
52 #[derive(Component)]
53 struct A(usize);
54
55 #[derive(Component)]
56 struct B(isize, isize, [isize; 20]);
57
58 #[test]
59 fn test_bundle() {
60 let mut comp_factory = ComponentFactory::default();
61 comp_factory.register_component::<A>();
62 comp_factory.register_component::<B>();
63
64 let blob_vec_a = unsafe {
65 comp_factory
66 .new_component_storage(ComponentId::new(0))
67 .unwrap()
68 };
69 let blob_vec_b = unsafe {
70 comp_factory
71 .new_component_storage(ComponentId::new(1))
72 .unwrap()
73 };
74
75 let mut storage = vec![blob_vec_a, blob_vec_b];
76 <(A, B) as Bundle>::raw_components_scope(
77 (A(33), B(-11, -99, [-456; 20])),
78 &comp_factory,
79 &mut |comp_id, raw_comp| unsafe { storage[comp_id.id()].push(raw_comp) },
80 );
81 <(A, B) as Bundle>::raw_components_scope(
82 (A(66), B(-22, -99, [-56; 20])),
83 &comp_factory,
84 &mut |comp_id, raw_comp| unsafe { storage[comp_id.id()].push(raw_comp) },
85 );
86 <(A, B) as Bundle>::raw_components_scope(
87 (A(99), B(-33, -99, [-4; 20])),
88 &comp_factory,
89 &mut |comp_id, raw_comp| unsafe { storage[comp_id.id()].push(raw_comp) },
90 );
91
92 assert_eq!(unsafe { storage[0].get_unchecked(0).deref::<A>().0 }, 33);
93 assert_eq!(unsafe { storage[0].get_unchecked(1).deref::<A>().0 }, 66);
94 assert_eq!(unsafe { storage[0].get_unchecked(2).deref::<A>().0 }, 99);
95
96 assert_eq!(unsafe { storage[1].get_unchecked(0).deref::<B>().0 }, -11);
97 assert_eq!(unsafe { storage[1].get_unchecked(1).deref::<B>().0 }, -22);
98 assert_eq!(unsafe { storage[1].get_unchecked(2).deref::<B>().0 }, -33);
99
100 assert_eq!(unsafe { storage[1].get_unchecked(0).deref::<B>().1 }, -99);
101 assert_eq!(unsafe { storage[1].get_unchecked(1).deref::<B>().1 }, -99);
102 assert_eq!(unsafe { storage[1].get_unchecked(2).deref::<B>().1 }, -99);
103
104 assert_eq!(
105 unsafe { storage[1].get_unchecked(0).deref::<B>().2 },
106 [-456; 20]
107 );
108 assert_eq!(
109 unsafe { storage[1].get_unchecked(1).deref::<B>().2 },
110 [-56; 20]
111 );
112 assert_eq!(
113 unsafe { storage[1].get_unchecked(2).deref::<B>().2 },
114 [-4; 20]
115 );
116 }
117}