worlds_ecs/
bundle.rs

1use bevy_ptr::OwningPtr;
2use worlds_derive::all_tuples;
3
4use crate::prelude::{Component, ComponentFactory, ComponentId};
5
6/// A bundle of components.
7pub trait Bundle {
8    /// This method calls `f` on all of the components in the bundle. This could, for example,
9    ///  be used in conjunction with [`Vec::push`] to collect all the components into a [`Vec`].
10    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                // SAFETY: We own self
27                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}