use std::{any::{TypeId, Any}, ptr::NonNull, mem::size_of}; use crate::{component::Component, component_info::ComponentInfo, DynTypeId}; pub trait Bundle { /// Get a list of type ids that this bundle is storing fn type_ids(&self) -> Vec; /// Get ComponentInfo's for the components in this bundle fn info(&self) -> Vec; /// Take the bundle by calling the closure with pointers to each component, its type and size. /// The closure is expected to take ownership of the pointer. fn take(self, f: impl FnMut(NonNull, DynTypeId, usize)); } // The macro below can implement this for us, but this is here for development impl Bundle for (C1,) { fn type_ids(&self) -> Vec { vec![DynTypeId::of::()] } fn info(&self) -> Vec { vec![ComponentInfo::new::()] } fn take(self, mut f: impl FnMut(NonNull, DynTypeId, usize)) { let (c1, ) = self; f(NonNull::from(&c1).cast(), DynTypeId::of::(), size_of::()); } } macro_rules! impl_bundle_tuple { ( $($name: ident),+ ) => ( #[allow(non_snake_case)] impl<$($name: Component),+> Bundle for ($($name,)+) { fn type_ids(&self) -> Vec { // these names wont follow rust convention, but its a macro so deal with it let ($($name),+) = self; vec![$(DynTypeId::of::<$name>()),+] } fn info(&self) -> Vec { vec![$(ComponentInfo::new::<$name>()),+] } fn take(self, mut f: impl FnMut(NonNull, DynTypeId, usize)) { // these names wont follow rust convention, but its a macro so deal with it let ($($name),+) = self; $(f(NonNull::from(&$name).cast(), DynTypeId::of::<$name>(), size_of::<$name>());)+ } } ); } // hopefully 16 components in a bundle is enough impl_bundle_tuple! { C1, C2 } impl_bundle_tuple! { C1, C2, C3 } impl_bundle_tuple! { C1, C2, C3, C4 } impl_bundle_tuple! { C1, C2, C3, C4, C5 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15 } impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16 } /// A bundle of components #[derive(Default)] pub struct DynamicBundle { bundle: Vec<(NonNull, ComponentInfo)>, } impl DynamicBundle { pub fn new() -> Self { Self::default() } /// Push a type known to rust to this bundle pub fn push(&mut self, comp: C) where C: Component { let info = ComponentInfo::new::(); let data = NonNull::from(&comp).cast::(); self.bundle.push((data, info)); } /// Push an unknown type to the bundle pub fn push_unknown(&mut self, data: NonNull, info: ComponentInfo) { self.bundle.push((data, info)); } } impl Bundle for DynamicBundle { fn type_ids(&self) -> Vec { self.bundle.iter().map(|b| b.1.type_id).collect() } fn info(&self) -> Vec { self.bundle.iter().map(|b| b.1.clone()).collect() } fn take(self, mut f: impl FnMut(NonNull, DynTypeId, usize)) { for (data, info) in self.bundle.iter() { f(data.clone(), info.type_id, info.layout.size); } } }