Skip to main content

ponko_ecs/
bundle.rs

1//! Bundles: tuples of components spawned together.
2
3use std::mem::ManuallyDrop;
4
5use crate::storage::ComponentId;
6use crate::world::World;
7
8/// Any `Send + Sync + 'static` type can be a component. No derive needed.
9pub trait Component: Send + Sync + 'static {}
10impl<T: Send + Sync + 'static> Component for T {}
11
12/// A tuple of components that are spawned together: `(Pos, Vel)`, `(Pos,)`.
13///
14/// Implemented for tuples of up to 12 components.
15///
16/// # Safety
17/// `write` must call `f` exactly once per element, in the order of
18/// `component_ids`, with a pointer to a value whose ownership the callee takes.
19pub unsafe trait Bundle: Send + Sync + 'static {
20    #[doc(hidden)]
21    fn component_ids(world: &mut World, out: &mut Vec<ComponentId>);
22    #[doc(hidden)]
23    unsafe fn write(self, f: &mut impl FnMut(usize, *const u8));
24}
25
26macro_rules! bundle_tuple {
27    ($($t:ident $i:tt),*) => {
28        unsafe impl<$($t: Component),*> Bundle for ($($t,)*) {
29            fn component_ids(world: &mut World, out: &mut Vec<ComponentId>) {
30                $(out.push(world.register::<$t>());)*
31            }
32            unsafe fn write(self, f: &mut impl FnMut(usize, *const u8)) {
33                let me = ManuallyDrop::new(self);
34                $(f($i, (&me.$i as *const $t).cast());)*
35            }
36        }
37    };
38}
39bundle_tuple!(A 0);
40bundle_tuple!(A 0, B 1);
41bundle_tuple!(A 0, B 1, C 2);
42bundle_tuple!(A 0, B 1, C 2, D 3);
43bundle_tuple!(A 0, B 1, C 2, D 3, E 4);
44bundle_tuple!(A 0, B 1, C 2, D 3, E 4, F 5);
45bundle_tuple!(A 0, B 1, C 2, D 3, E 4, F 5, G 6);
46bundle_tuple!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
47bundle_tuple!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8);
48bundle_tuple!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9);
49bundle_tuple!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10);
50bundle_tuple!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11);