From a1ca2789ce2f6914b051c62cb24e19dcf1d379c2 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sat, 9 Dec 2023 12:23:10 -0500 Subject: [PATCH] Dynamically typed bundles and archetypes --- lyra-ecs/src/archetype.rs | 31 ++++++++++++++++++++++- lyra-ecs/src/bundle.rs | 46 +++++++++++++++++++++++++++++++++- lyra-ecs/src/component_info.rs | 4 +-- 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/lyra-ecs/src/archetype.rs b/lyra-ecs/src/archetype.rs index 6f9eb08..113c3a3 100644 --- a/lyra-ecs/src/archetype.rs +++ b/lyra-ecs/src/archetype.rs @@ -311,9 +311,11 @@ impl Archetype { #[cfg(test)] mod tests { + use std::{alloc::Layout, ptr::NonNull}; + use rand::Rng; - use crate::{tests::{Vec2, Vec3}, world::{Entity, EntityId}, bundle::{Bundle, self}}; + use crate::{tests::{Vec2, Vec3}, world::{Entity, EntityId}, bundle::{Bundle, self}, ComponentInfo, MemoryLayout, DynTypeId, DynamicBundle}; use super::Archetype; @@ -486,4 +488,31 @@ mod tests { let comp = unsafe { col.get::(1) }; assert_eq!(comp.clone(), bundles[2]); } + + /// This test simulates an archetype that stores types that rust does not know about. + #[test] + fn dynamic_archetype() { + let layout = MemoryLayout::from(Layout::new::()); + let info = ComponentInfo::new_unknown(DynTypeId::Unknown(100), "u32", layout); + let infos = vec![info.clone()]; + + let mut a = Archetype::from_bundle_info(super::ArchetypeId(0), infos); + + let mut dynamic_bundle = DynamicBundle::default(); + let comp = 50u32; + let ptr = NonNull::from(&comp).cast::(); + dynamic_bundle.push_unknown(ptr, info.clone()); + + a.add_entity( + Entity { + id: EntityId(0), + generation: 0 + }, dynamic_bundle + ); + + let col = a.columns.iter().next().unwrap(); + let ptr = col.borrow_ptr(); + assert_eq!(unsafe { *ptr.cast::().as_ref() }, comp); + assert_eq!(col.info, info); + } } \ No newline at end of file diff --git a/lyra-ecs/src/bundle.rs b/lyra-ecs/src/bundle.rs index 39698b4..aaa9495 100644 --- a/lyra-ecs/src/bundle.rs +++ b/lyra-ecs/src/bundle.rs @@ -70,4 +70,48 @@ 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 } \ No newline at end of file +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); + } + } +} \ No newline at end of file diff --git a/lyra-ecs/src/component_info.rs b/lyra-ecs/src/component_info.rs index aec19c5..515c8b8 100644 --- a/lyra-ecs/src/component_info.rs +++ b/lyra-ecs/src/component_info.rs @@ -1,6 +1,6 @@ use std::{any::{TypeId, type_name}, alloc::{Layout, LayoutError}}; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct MemoryLayout { pub size: usize, pub alignment: usize @@ -61,7 +61,7 @@ impl DynTypeId { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ComponentInfo { pub type_id: DynTypeId, pub name: String,