use crate::alloc::alloc::{alloc, dealloc, Layout};
use crate::alloc::vec::Vec;
use crate::bundle::{DynamicBundleClone, DynamicClone};
use core::any::TypeId;
use core::ptr::{self, NonNull};
use hashbrown::hash_map::Entry;
use crate::archetype::{TypeIdMap, TypeInfo};
use crate::{align, Component, ComponentRef, ComponentRefShared, DynamicBundle};
#[derive(Default)]
pub struct EntityBuilder {
inner: Common<()>,
}
impl EntityBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn add<T: Component>(&mut self, component: T) -> &mut Self {
self.add_bundle((component,))
}
pub fn add_bundle(&mut self, bundle: impl DynamicBundle) -> &mut Self {
unsafe {
bundle.put(|ptr, ty| self.inner.add(ptr, ty, ()));
}
self
}
pub fn build(&mut self) -> BuiltEntity<'_> {
self.inner.info.sort_unstable_by_key(|x| x.0);
self.inner
.ids
.extend(self.inner.info.iter().map(|x| x.0.id()));
BuiltEntity {
builder: &mut self.inner,
}
}
pub fn has<T: Component>(&self) -> bool {
self.inner.has::<T>()
}
pub fn get<'a, T: ComponentRefShared<'a>>(&'a self) -> Option<T> {
self.inner.get::<T>()
}
pub fn get_mut<'a, T: ComponentRef<'a>>(&'a mut self) -> Option<T> {
self.inner.get_mut::<T>()
}
pub fn component_types(&self) -> impl Iterator<Item = TypeId> + '_ {
self.inner.component_types()
}
pub fn clear(&mut self) {
self.inner.clear()
}
}
pub struct BuiltEntity<'a> {
builder: &'a mut Common<()>,
}
unsafe impl DynamicBundle for BuiltEntity<'_> {
fn has<T: Component>(&self) -> bool {
self.builder.has::<T>()
}
fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
f(&self.builder.ids)
}
#[doc(hidden)]
fn type_info(&self) -> Vec<TypeInfo> {
self.builder.info.iter().map(|x| x.0).collect()
}
unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
for (ty, offset, ()) in self.builder.info.drain(..) {
let ptr = self.builder.storage.as_ptr().add(offset);
f(ptr, ty);
}
}
}
impl Drop for BuiltEntity<'_> {
fn drop(&mut self) {
self.builder.clear();
}
}
#[derive(Clone, Default)]
pub struct EntityBuilderClone {
inner: Common<DynamicClone>,
}
impl EntityBuilderClone {
pub fn new() -> Self {
Self::default()
}
pub fn add<T: Component + Clone>(&mut self, mut component: T) -> &mut Self {
unsafe {
self.inner.add(
(&mut component as *mut T).cast(),
TypeInfo::of::<T>(),
DynamicClone::new::<T>(),
);
}
core::mem::forget(component);
self
}
pub fn add_bundle(&mut self, bundle: impl DynamicBundleClone) -> &mut Self {
unsafe {
bundle.put_with_clone(|ptr, ty, cloneable| self.inner.add(ptr, ty, cloneable));
}
self
}
pub fn build(self) -> BuiltEntityClone {
self.into()
}
pub fn has<T: Component>(&self) -> bool {
self.inner.has::<T>()
}
pub fn get<'a, T: ComponentRefShared<'a>>(&'a self) -> Option<T> {
self.inner.get::<T>()
}
pub fn get_mut<'a, T: ComponentRef<'a>>(&'a mut self) -> Option<T> {
self.inner.get_mut::<T>()
}
pub fn component_types(&self) -> impl Iterator<Item = TypeId> + '_ {
self.inner.component_types()
}
pub fn clear(&mut self) {
self.inner.clear()
}
}
#[derive(Clone)]
pub struct BuiltEntityClone(Common<DynamicClone>);
unsafe impl DynamicBundle for &'_ BuiltEntityClone {
fn has<T: Component>(&self) -> bool {
self.0.has::<T>()
}
fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
f(&self.0.ids)
}
fn type_info(&self) -> Vec<TypeInfo> {
self.0.info.iter().map(|x| x.0).collect()
}
unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
for &(_, offset, clone) in &self.0.info {
let ptr = self.0.storage.as_ptr().add(offset);
(clone.func)(ptr, &mut f);
}
}
}
unsafe impl DynamicBundleClone for &'_ BuiltEntityClone {
unsafe fn put_with_clone(self, mut f: impl FnMut(*mut u8, TypeInfo, DynamicClone)) {
for &(_, offset, clone) in &self.0.info {
let ptr = self.0.storage.as_ptr().add(offset);
(clone.func)(ptr, &mut |src, ty| f(src, ty, clone));
}
}
}
impl From<EntityBuilderClone> for BuiltEntityClone {
fn from(mut x: EntityBuilderClone) -> Self {
x.inner.info.sort_unstable_by_key(|y| y.0);
x.inner.ids.extend(x.inner.info.iter().map(|y| y.0.id()));
Self(x.inner)
}
}
impl From<BuiltEntityClone> for EntityBuilderClone {
fn from(mut x: BuiltEntityClone) -> Self {
x.0.ids.clear();
EntityBuilderClone { inner: x.0 }
}
}
struct Common<M> {
storage: NonNull<u8>,
layout: Layout,
cursor: usize,
info: Vec<(TypeInfo, usize, M)>,
ids: Vec<TypeId>,
indices: TypeIdMap<usize>,
}
impl<M> Common<M> {
fn has<T: Component>(&self) -> bool {
self.indices.contains_key(&TypeId::of::<T>())
}
fn get<'a, T: ComponentRefShared<'a>>(&'a self) -> Option<T> {
let index = self.indices.get(&TypeId::of::<T::Component>())?;
let (_, offset, _) = self.info[*index];
unsafe {
let storage = self.storage.as_ptr().add(offset).cast::<T::Component>();
Some(T::from_raw(storage))
}
}
fn get_mut<'a, T: ComponentRef<'a>>(&'a self) -> Option<T> {
let index = self.indices.get(&TypeId::of::<T::Component>())?;
let (_, offset, _) = self.info[*index];
unsafe {
let storage = self.storage.as_ptr().add(offset).cast::<T::Component>();
Some(T::from_raw(storage))
}
}
fn component_types(&self) -> impl Iterator<Item = TypeId> + '_ {
self.info.iter().map(|(info, _, _)| info.id())
}
unsafe fn grow(
min_size: usize,
cursor: usize,
align: usize,
storage: NonNull<u8>,
) -> (NonNull<u8>, Layout) {
let layout = Layout::from_size_align(min_size.next_power_of_two().max(64), align).unwrap();
let new_storage = NonNull::new_unchecked(alloc(layout));
ptr::copy_nonoverlapping(storage.as_ptr(), new_storage.as_ptr(), cursor);
(new_storage, layout)
}
fn clear(&mut self) {
self.ids.clear();
self.indices.clear();
self.cursor = 0;
unsafe {
for (ty, offset, _) in self.info.drain(..) {
ty.drop(self.storage.as_ptr().add(offset));
}
}
}
unsafe fn add(&mut self, ptr: *mut u8, ty: TypeInfo, meta: M) {
match self.indices.entry(ty.id()) {
Entry::Occupied(occupied) => {
let index = *occupied.get();
let (ty, offset, _) = self.info[index];
let storage = self.storage.as_ptr().add(offset);
ty.drop(storage);
ptr::copy_nonoverlapping(ptr, storage, ty.layout().size());
}
Entry::Vacant(vacant) => {
let offset = align(self.cursor, ty.layout().align());
let end = offset + ty.layout().size();
if end > self.layout.size() || ty.layout().align() > self.layout.align() {
let new_align = self.layout.align().max(ty.layout().align());
let (new_storage, new_layout) =
Self::grow(end, self.cursor, new_align, self.storage);
if self.layout.size() != 0 {
dealloc(self.storage.as_ptr(), self.layout);
}
self.storage = new_storage;
self.layout = new_layout;
}
let addr = self.storage.as_ptr().add(offset);
ptr::copy_nonoverlapping(ptr, addr, ty.layout().size());
vacant.insert(self.info.len());
self.info.push((ty, offset, meta));
self.cursor = end;
}
}
}
}
unsafe impl<M> Send for Common<M> {}
unsafe impl<M> Sync for Common<M> {}
impl<M> Drop for Common<M> {
fn drop(&mut self) {
self.clear();
if self.layout.size() != 0 {
unsafe {
dealloc(self.storage.as_ptr(), self.layout);
}
}
}
}
impl<M> Default for Common<M> {
fn default() -> Self {
Self {
storage: NonNull::dangling(),
layout: Layout::from_size_align(0, 8).unwrap(),
cursor: 0,
info: Vec::new(),
ids: Vec::new(),
indices: Default::default(),
}
}
}
impl Clone for Common<DynamicClone> {
fn clone(&self) -> Self {
unsafe {
let result = Common {
storage: NonNull::new_unchecked(alloc(self.layout)),
layout: self.layout,
cursor: self.cursor,
info: self.info.clone(),
ids: self.ids.clone(),
indices: self.indices.clone(),
};
for &(_, offset, ref clone) in &self.info {
(clone.func)(self.storage.as_ptr().add(offset), &mut |src, ty| {
result
.storage
.as_ptr()
.add(offset)
.copy_from_nonoverlapping(src, ty.layout().size())
});
}
result
}
}
}