Dynamically typed bundles and archetypes

This commit is contained in:
SeanOMik 2023-12-09 12:23:10 -05:00
parent e867aaeadb
commit a1ca2789ce
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
3 changed files with 77 additions and 4 deletions

View File

@ -311,9 +311,11 @@ impl Archetype {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{alloc::Layout, ptr::NonNull};
use rand::Rng; 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; use super::Archetype;
@ -486,4 +488,31 @@ mod tests {
let comp = unsafe { col.get::<Vec2>(1) }; let comp = unsafe { col.get::<Vec2>(1) };
assert_eq!(comp.clone(), bundles[2]); 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::<u32>());
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::<u8>();
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::<u32>().as_ref() }, comp);
assert_eq!(col.info, info);
}
} }

View File

@ -71,3 +71,47 @@ 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 }
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 }
impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16 } 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<u8>, ComponentInfo)>,
}
impl DynamicBundle {
pub fn new() -> Self {
Self::default()
}
/// Push a type known to rust to this bundle
pub fn push<C>(&mut self, comp: C)
where
C: Component
{
let info = ComponentInfo::new::<C>();
let data = NonNull::from(&comp).cast::<u8>();
self.bundle.push((data, info));
}
/// Push an unknown type to the bundle
pub fn push_unknown(&mut self, data: NonNull<u8>, info: ComponentInfo) {
self.bundle.push((data, info));
}
}
impl Bundle for DynamicBundle {
fn type_ids(&self) -> Vec<DynTypeId> {
self.bundle.iter().map(|b| b.1.type_id).collect()
}
fn info(&self) -> Vec<ComponentInfo> {
self.bundle.iter().map(|b| b.1.clone()).collect()
}
fn take(self, mut f: impl FnMut(NonNull<u8>, DynTypeId, usize)) {
for (data, info) in self.bundle.iter() {
f(data.clone(), info.type_id, info.layout.size);
}
}
}

View File

@ -1,6 +1,6 @@
use std::{any::{TypeId, type_name}, alloc::{Layout, LayoutError}}; use std::{any::{TypeId, type_name}, alloc::{Layout, LayoutError}};
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MemoryLayout { pub struct MemoryLayout {
pub size: usize, pub size: usize,
pub alignment: usize pub alignment: usize
@ -61,7 +61,7 @@ impl DynTypeId {
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct ComponentInfo { pub struct ComponentInfo {
pub type_id: DynTypeId, pub type_id: DynTypeId,
pub name: String, pub name: String,