use std::any::TypeId;
use smallvec::{smallvec, SmallVec};
use crate::archetype::Archetype;
pub const MAX_BUNDLE_COMPONENTS: usize = 8;
pub trait Component: 'static + Send + Sync {}
impl<T: 'static + Send + Sync> Component for T {}
pub trait Bundle: Send + Sync + 'static {
fn type_ids() -> SmallVec<[TypeId; MAX_BUNDLE_COMPONENTS]>
where
Self: Sized;
fn register_components(archetype: &mut Archetype)
where
Self: Sized;
unsafe fn write_components(self, ptrs: &[*mut u8]);
}
macro_rules! impl_bundle {
($($T:ident),*) => {
impl<$($T: Component),*> Bundle for ($($T,)*) {
fn type_ids() -> SmallVec<[TypeId; MAX_BUNDLE_COMPONENTS]> {
smallvec![$(TypeId::of::<$T>()),*]
}
fn register_components(archetype: &mut Archetype) {
$(archetype.register_component::<$T>();)*
}
#[allow(non_snake_case)]
unsafe fn write_components(self, ptrs: &[*mut u8]) {
let ($($T,)*) = self;
let mut i = 0;
$(
std::ptr::write(ptrs[i] as *mut $T, $T);
i += 1;
)*
let _ = i; }
}
};
}
impl Bundle for () {
fn type_ids() -> SmallVec<[TypeId; MAX_BUNDLE_COMPONENTS]> {
smallvec![]
}
fn register_components(_: &mut Archetype) {}
unsafe fn write_components(self, _: &[*mut u8]) {}
}
impl_bundle!(A);
impl_bundle!(A, B);
impl_bundle!(A, B, C);
impl_bundle!(A, B, C, D);
impl_bundle!(A, B, C, D, E);
impl_bundle!(A, B, C, D, E, F);
impl_bundle!(A, B, C, D, E, F, G);
impl_bundle!(A, B, C, D, E, F, G, H);
#[cfg(test)]
mod tests {
#![allow(dead_code)]
use super::*;
#[test]
fn test_single_component() {
#[derive(Debug, Clone, Copy)]
struct Position {
x: f32,
y: f32,
}
let type_ids = <(Position,)>::type_ids();
assert_eq!(type_ids.len(), 1);
assert_eq!(type_ids[0], TypeId::of::<Position>());
}
#[test]
fn test_multiple_components() {
#[derive(Debug, Clone, Copy)]
struct Position {
x: f32,
}
#[derive(Debug, Clone, Copy)]
struct Velocity {
x: f32,
}
let type_ids = <(Position, Velocity)>::type_ids();
assert_eq!(type_ids.len(), 2);
}
}