Groundwork for dynamic types in archetypes
This commit is contained in:
parent
808cb77040
commit
e867aaeadb
|
@ -1,6 +1,6 @@
|
|||
use std::{any::TypeId, ptr::{NonNull, self}, alloc::{self, Layout, alloc, dealloc}, mem, collections::HashMap, cell::{RefCell, Ref, RefMut, BorrowError, BorrowMutError}, ops::{DerefMut, Deref}};
|
||||
|
||||
use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle, component_info::ComponentInfo};
|
||||
use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle, component_info::ComponentInfo, DynTypeId};
|
||||
|
||||
pub struct ComponentColumn {
|
||||
data: RefCell<NonNull<u8>>,
|
||||
|
@ -16,8 +16,8 @@ impl Drop for ComponentColumn {
|
|||
|
||||
unsafe {
|
||||
// layout of current alloc
|
||||
let layout = Layout::from_size_align_unchecked(self.info.layout.size() * self.capacity,
|
||||
self.info.layout.align());
|
||||
let layout = Layout::from_size_align_unchecked(self.info.layout.size * self.capacity,
|
||||
self.info.layout.alignment);
|
||||
dealloc(data, layout);
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ impl ComponentColumn {
|
|||
}
|
||||
|
||||
pub unsafe fn new(info: ComponentInfo, capacity: usize) -> Self {
|
||||
let data = ComponentColumn::alloc(info.layout, capacity);
|
||||
let data = ComponentColumn::alloc(info.layout.into_layout_unchecked(), capacity);
|
||||
|
||||
Self {
|
||||
data: RefCell::new(data),
|
||||
|
@ -71,8 +71,8 @@ impl ComponentColumn {
|
|||
let mut data = self.data.borrow_mut();
|
||||
let data = data.deref_mut();
|
||||
|
||||
let dest = NonNull::new_unchecked(data.as_ptr().add(entity_index * self.info.layout.size()));
|
||||
ptr::copy_nonoverlapping(comp_src.as_ptr(), dest.as_ptr(), self.info.layout.size());
|
||||
let dest = NonNull::new_unchecked(data.as_ptr().add(entity_index * self.info.layout.size));
|
||||
ptr::copy_nonoverlapping(comp_src.as_ptr(), dest.as_ptr(), self.info.layout.size);
|
||||
self.len += 1;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ impl ComponentColumn {
|
|||
let data = data.deref();
|
||||
|
||||
let ptr = NonNull::new_unchecked(data.as_ptr()
|
||||
.add(entity_index * self.info.layout.size()))
|
||||
.add(entity_index * self.info.layout.size))
|
||||
.cast();
|
||||
&*ptr.as_ptr()
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ impl ComponentColumn {
|
|||
|
||||
let p = data.as_ptr()
|
||||
.cast::<T>()
|
||||
.add(entity_index * self.info.layout.size());
|
||||
.add(entity_index * self.info.layout.size);
|
||||
&mut *p
|
||||
}
|
||||
|
||||
|
@ -120,17 +120,17 @@ impl ComponentColumn {
|
|||
let mut data = self.data.borrow_mut();
|
||||
//let data = data.deref_mut();
|
||||
|
||||
let mut new_ptr = Self::alloc(self.info.layout, new_capacity);
|
||||
let mut new_ptr = Self::alloc(self.info.layout.into_layout_unchecked(), new_capacity);
|
||||
|
||||
if self.len > 0 {
|
||||
ptr::copy_nonoverlapping(data.as_ptr(), new_ptr.as_ptr(), self.len * self.info.layout.size());
|
||||
ptr::copy_nonoverlapping(data.as_ptr(), new_ptr.as_ptr(), self.len * self.info.layout.size);
|
||||
}
|
||||
|
||||
// dont attempt to free if we weren't able to store anything anyway
|
||||
if self.capacity != 0 {
|
||||
let old_layout = Layout::from_size_align_unchecked(
|
||||
self.info.layout.size().checked_mul(self.capacity).unwrap(),
|
||||
self.info.layout.align()
|
||||
self.info.layout.size.checked_mul(self.capacity).unwrap(),
|
||||
self.info.layout.alignment
|
||||
);
|
||||
|
||||
mem::swap(data.deref_mut(), &mut new_ptr);
|
||||
|
@ -148,14 +148,14 @@ impl ComponentColumn {
|
|||
let data = data.deref_mut();
|
||||
|
||||
let mut old_comp_ptr = NonNull::new_unchecked(data.as_ptr()
|
||||
.add(entity_index * self.info.layout.size()));
|
||||
.add(entity_index * self.info.layout.size));
|
||||
|
||||
let moved_index = if entity_index != self.len - 1 {
|
||||
let moved_index = self.len - 1;
|
||||
let mut new_comp_ptr = NonNull::new_unchecked(data.as_ptr()
|
||||
.add(moved_index * self.info.layout.size()));
|
||||
.add(moved_index * self.info.layout.size));
|
||||
|
||||
ptr::copy_nonoverlapping(new_comp_ptr.as_ptr(), old_comp_ptr.as_ptr(), self.info.layout.size());
|
||||
ptr::copy_nonoverlapping(new_comp_ptr.as_ptr(), old_comp_ptr.as_ptr(), self.info.layout.size);
|
||||
|
||||
mem::swap(&mut old_comp_ptr, &mut new_comp_ptr); // new_comp_ptr is now the old ptr
|
||||
Some(moved_index)
|
||||
|
@ -276,7 +276,7 @@ impl Archetype {
|
|||
}
|
||||
|
||||
/// Returns a boolean indicating whether this archetype can store the TypeIds given
|
||||
pub(crate) fn is_archetype_for(&self, types: Vec<TypeId>) -> bool {
|
||||
pub(crate) fn is_archetype_for(&self, types: Vec<DynTypeId>) -> bool {
|
||||
self.columns.iter().all(|c| types.contains(&c.info.type_id))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
use std::{any::{TypeId, Any}, ptr::NonNull, mem::size_of};
|
||||
|
||||
use crate::{component::Component, component_info::ComponentInfo};
|
||||
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<TypeId>;
|
||||
fn type_ids(&self) -> Vec<DynTypeId>;
|
||||
|
||||
/// Get ComponentInfo's for the components in this bundle
|
||||
fn info(&self) -> Vec<ComponentInfo>;
|
||||
|
||||
/// 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<u8>, TypeId, usize));
|
||||
fn take(self, f: impl FnMut(NonNull<u8>, DynTypeId, usize));
|
||||
}
|
||||
|
||||
// The macro below can implement this for us, but this is here for development
|
||||
impl<C1: Component> Bundle for (C1,) {
|
||||
fn type_ids(&self) -> Vec<TypeId> {
|
||||
vec![self.0.type_id()]
|
||||
fn type_ids(&self) -> Vec<DynTypeId> {
|
||||
vec![DynTypeId::of::<C1>()]
|
||||
}
|
||||
|
||||
fn info(&self) -> Vec<ComponentInfo> {
|
||||
vec![ComponentInfo::new::<C1>()]
|
||||
}
|
||||
|
||||
fn take(self, mut f: impl FnMut(NonNull<u8>, TypeId, usize)) {
|
||||
fn take(self, mut f: impl FnMut(NonNull<u8>, DynTypeId, usize)) {
|
||||
let (c1, ) = self;
|
||||
|
||||
f(NonNull::from(&c1).cast(), TypeId::of::<C1>(), size_of::<C1>());
|
||||
f(NonNull::from(&c1).cast(), DynTypeId::of::<C1>(), size_of::<C1>());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,21 +35,21 @@ macro_rules! impl_bundle_tuple {
|
|||
( $($name: ident),+ ) => (
|
||||
#[allow(non_snake_case)]
|
||||
impl<$($name: Component),+> Bundle for ($($name,)+) {
|
||||
fn type_ids(&self) -> Vec<TypeId> {
|
||||
fn type_ids(&self) -> Vec<DynTypeId> {
|
||||
// these names wont follow rust convention, but its a macro so deal with it
|
||||
let ($($name),+) = self;
|
||||
vec![$($name.type_id()),+]
|
||||
vec![$(DynTypeId::of::<$name>()),+]
|
||||
}
|
||||
|
||||
fn info(&self) -> Vec<ComponentInfo> {
|
||||
vec![$(ComponentInfo::new::<$name>()),+]
|
||||
}
|
||||
|
||||
fn take(self, mut f: impl FnMut(NonNull<u8>, TypeId, usize)) {
|
||||
fn take(self, mut f: impl FnMut(NonNull<u8>, DynTypeId, usize)) {
|
||||
// these names wont follow rust convention, but its a macro so deal with it
|
||||
let ($($name),+) = self;
|
||||
|
||||
$(f(NonNull::from(&$name).cast(), TypeId::of::<$name>(), size_of::<$name>());)+
|
||||
$(f(NonNull::from(&$name).cast(), DynTypeId::of::<$name>(), size_of::<$name>());)+
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,18 +1,91 @@
|
|||
use std::{any::{TypeId, type_name}, alloc::Layout};
|
||||
use std::{any::{TypeId, type_name}, alloc::{Layout, LayoutError}};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MemoryLayout {
|
||||
pub size: usize,
|
||||
pub alignment: usize
|
||||
}
|
||||
|
||||
impl TryInto<Layout> for MemoryLayout {
|
||||
type Error = LayoutError;
|
||||
|
||||
fn try_into(self) -> Result<Layout, Self::Error> {
|
||||
Layout::from_size_align(self.size, self.alignment)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Layout> for MemoryLayout {
|
||||
fn from(value: Layout) -> Self {
|
||||
Self {
|
||||
size: value.size(),
|
||||
alignment: value.align(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryLayout {
|
||||
pub fn new(size: usize, alignment: usize) -> Self {
|
||||
MemoryLayout {
|
||||
size,
|
||||
alignment
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn into_layout_unchecked(self) -> Layout {
|
||||
Layout::from_size_align_unchecked(self.size, self.alignment)
|
||||
}
|
||||
}
|
||||
|
||||
/// A dynamic type id. Supports types that are not known to Rust.
|
||||
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
|
||||
pub enum DynTypeId {
|
||||
Rust(TypeId),
|
||||
Unknown(u128),
|
||||
}
|
||||
|
||||
impl Into<DynTypeId> for u128 {
|
||||
fn into(self) -> DynTypeId {
|
||||
DynTypeId::Unknown(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TypeId> for DynTypeId {
|
||||
fn from(value: TypeId) -> Self {
|
||||
DynTypeId::Rust(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl DynTypeId {
|
||||
pub fn of<T: 'static>() -> Self {
|
||||
Self::Rust(TypeId::of::<T>())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ComponentInfo {
|
||||
pub type_id: TypeId,
|
||||
pub type_id: DynTypeId,
|
||||
pub name: String,
|
||||
pub layout: Layout,
|
||||
pub layout: MemoryLayout,
|
||||
}
|
||||
|
||||
impl ComponentInfo {
|
||||
pub fn new<T: 'static>() -> Self {
|
||||
Self {
|
||||
type_id: TypeId::of::<T>(),
|
||||
type_id: DynTypeId::from(TypeId::of::<T>()),
|
||||
name: type_name::<T>().to_string(),
|
||||
layout: Layout::new::<T>(),
|
||||
layout: MemoryLayout::from(Layout::new::<T>()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create ComponentInfo from a type that is not known to rust
|
||||
pub fn new_unknown<D>(type_id: D, name: &str, layout: MemoryLayout) -> Self
|
||||
where
|
||||
D: Into<DynTypeId>,
|
||||
{
|
||||
Self {
|
||||
type_id: type_id.into(),
|
||||
name: name.to_string(),
|
||||
layout,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use std::{marker::PhantomData, any::TypeId, ptr::NonNull, cell::{Ref, RefCell, RefMut}};
|
||||
|
||||
use crate::{world::World, ComponentColumn};
|
||||
use crate::{world::World, ComponentColumn, DynTypeId};
|
||||
|
||||
use super::{Fetch, Query, AsQuery};
|
||||
|
||||
|
@ -41,7 +41,7 @@ where
|
|||
/// }
|
||||
/// ```
|
||||
pub struct QueryBorrow<T> {
|
||||
type_id: TypeId,
|
||||
type_id: DynTypeId,
|
||||
_phantom: PhantomData<T>
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ impl<T> Clone for QueryBorrow<T> {
|
|||
impl<T: 'static> QueryBorrow<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
type_id: TypeId::of::<T>(),
|
||||
type_id: DynTypeId::of::<T>(),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ where
|
|||
|
||||
FetchBorrow {
|
||||
col,
|
||||
size: col.info.layout.size(),
|
||||
size: col.info.layout.size,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ where
|
|||
/// }
|
||||
/// ```
|
||||
pub struct QueryBorrowMut<T> {
|
||||
type_id: TypeId,
|
||||
type_id: DynTypeId,
|
||||
_phantom: PhantomData<T>
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ impl<T> Clone for QueryBorrowMut<T> {
|
|||
impl<T: 'static> QueryBorrowMut<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
type_id: TypeId::of::<T>(),
|
||||
type_id: DynTypeId::of::<T>(),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ where
|
|||
|
||||
FetchBorrowMut {
|
||||
col,
|
||||
size: col.info.layout.size(),
|
||||
size: col.info.layout.size,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ impl<T: 'static> AsQuery for &mut T {
|
|||
mod tests {
|
||||
use std::{any::TypeId, mem::size_of, marker::PhantomData};
|
||||
|
||||
use crate::{world::{World, Entity, EntityId}, archetype::{Archetype, ArchetypeId}, query::View, tests::Vec2, bundle::Bundle, Fetch};
|
||||
use crate::{world::{World, Entity, EntityId}, archetype::{Archetype, ArchetypeId}, query::View, tests::Vec2, bundle::Bundle, Fetch, DynTypeId};
|
||||
|
||||
use super::{QueryBorrow, QueryBorrowMut, FetchBorrowMut};
|
||||
|
||||
|
@ -215,7 +215,7 @@ mod tests {
|
|||
let world = prepare_world();
|
||||
|
||||
let borrow = QueryBorrow::<Vec2> {
|
||||
type_id: TypeId::of::<Vec2>(),
|
||||
type_id: DynTypeId::of::<Vec2>(),
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||
|
@ -231,7 +231,7 @@ mod tests {
|
|||
let world = prepare_world();
|
||||
|
||||
let borrow = QueryBorrowMut::<Vec2> {
|
||||
type_id: TypeId::of::<Vec2>(),
|
||||
type_id: DynTypeId::of::<Vec2>(),
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||
|
@ -248,7 +248,7 @@ mod tests {
|
|||
// Now make sure the changes were actually made
|
||||
|
||||
let borrow = QueryBorrow::<Vec2> {
|
||||
type_id: TypeId::of::<Vec2>(),
|
||||
type_id: DynTypeId::of::<Vec2>(),
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||
|
@ -273,7 +273,7 @@ mod tests {
|
|||
}, (Vec2::rand(),));
|
||||
}
|
||||
|
||||
let col = a.columns.iter().find(|c| c.info.type_id == TypeId::of::<Vec2>()).unwrap();
|
||||
let col = a.columns.iter().find(|c| c.info.type_id == DynTypeId::of::<Vec2>()).unwrap();
|
||||
|
||||
let mut bmut = FetchBorrowMut::<Vec2> {
|
||||
col,
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
use std::ptr::NonNull;
|
||||
|
||||
use crate::{Fetch, world::World, Query};
|
||||
|
||||
#[derive(Clone, Copy, Hash)]
|
||||
enum TypeId {
|
||||
Rust(std::any::TypeId),
|
||||
Unknown(u128),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Hash)]
|
||||
pub struct DynamicTypeInfo {
|
||||
id: TypeId,
|
||||
size: usize,
|
||||
alignment: usize,
|
||||
}
|
||||
|
||||
/// Data that is unknown to rust
|
||||
pub struct DynamicType {
|
||||
info: DynamicTypeInfo,
|
||||
ptr: NonNull<u8>,
|
||||
}
|
||||
|
||||
pub struct FetchDynamicType {
|
||||
info: Option<DynamicTypeInfo>,
|
||||
}
|
||||
|
||||
impl<'a> Fetch<'a> for FetchDynamicType {
|
||||
type Item = DynamicType;
|
||||
|
||||
fn dangling() -> Self {
|
||||
Self {
|
||||
info: None,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get_item(&mut self, entity: crate::ArchetypeEntityId) -> Self::Item {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct QueryDynamicType {
|
||||
info: DynamicTypeInfo,
|
||||
}
|
||||
|
||||
impl Query for QueryDynamicType {
|
||||
type Item<'a> = DynamicType;
|
||||
|
||||
type Fetch<'a> = FetchDynamicType;
|
||||
|
||||
const ALWAYS_FETCHES: bool = false;
|
||||
|
||||
fn new() -> Self {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn can_visit_archetype(&self, _archetype: &crate::archetype::Archetype) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn fetch<'a>(&self, world: &'a World, _arch_id: crate::archetype::ArchetypeId, _archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -19,6 +19,10 @@ pub mod resource;
|
|||
#[allow(unused_imports)]
|
||||
pub use resource::*;
|
||||
|
||||
pub mod dynamic;
|
||||
#[allow(unused_imports)]
|
||||
pub use dynamic::*;
|
||||
|
||||
/// A [`Fetch`]er implementation gets data out of an archetype.
|
||||
pub trait Fetch<'a> {
|
||||
/// The type that this Fetch yields
|
||||
|
|
Loading…
Reference in New Issue