use std::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8};
#[derive(Debug, Clone, Copy)]
pub struct EntityU16 {
content: NonZeroU16,
}
const LEAF_FLAG: u16 = 14;
const CHILDREN_COUNT: u16 = 9;
impl EntityU16 {
pub fn new_leaf(kind: u16) -> Self {
let content = kind;
if content & 1 << LEAF_FLAG != 0 {
panic!("too much types (first bit internally used)");
}
let content = content | 1 << LEAF_FLAG;
let content = NonZeroU16::new(content).unwrap();
Self { content }
}
pub fn new_node(children_count: u8, id: u16) -> Self {
if children_count >= 16 {
panic!("too much children");
}
assert_ne!(children_count, 0);
if id >= 1024 {
panic!("not enough ids");
}
let content = children_count - 1;
let content = content as u16;
let content = content << CHILDREN_COUNT;
let content = content | id;
let content = NonZeroU16::new(content).unwrap();
Self { content }
}
fn is_leaf(content: u16) -> bool {
content & 1 << LEAF_FLAG != 0
}
pub fn try_type(&self) -> Option<u16> {
let content = self.content.get();
if Self::is_leaf(content) {
Some(content & !(1 << LEAF_FLAG))
} else {
None
}
}
pub fn try_len(&self) -> Option<u8> {
let content = self.content.get();
if Self::is_leaf(content) {
None
} else {
let content = content & !(1 << LEAF_FLAG);
let content = (content >> CHILDREN_COUNT) as u8;
Some(content)
}
}
pub fn try_id(&self) -> Option<u16> {
let content = self.content.get();
if Self::is_leaf(content) {
None
} else {
let content = content & 0b111111111; Some(content)
}
}
fn as_u16(&self) -> u16 {
self.content.get()
}
}
enum LabelPlaceHolder<T> {
Label,
Other(T),
}
struct SmallData<const N: usize> {
kind: u16,
size: NonZeroU8,
height: u8,
children: [LabelPlaceHolder<EntityU16>; N],
}
#[derive(Debug, Clone, Copy)]
pub struct EntityU32 {
content: NonZeroU32,
}
const WRAP32_FLAG: u32 = 0xffff0000;
const MEDIUM_CHILD_FLAG: u32 = 31;
const MEDIUM_CHILDREN_COUNT: u32 = 24;
const STORE_OFFSET: u32 = 16;
impl EntityU32 {
fn wrap(small: EntityU16) -> Self {
Self {
content: NonZeroU32::new(small.as_u16() as u32).unwrap(),
}
}
pub fn new_node(children_count: u16, id: u16) -> Self {
assert_ne!(children_count, 0);
let content = children_count - 1;
let content = content as u32;
let content = NonZeroU32::new(content).unwrap();
Self { content }
}
fn is_wrap(content: u32) -> bool {
content & WRAP32_FLAG == 0
}
fn is_inline_length(content: u32) -> bool {
content & (1 << MEDIUM_CHILD_FLAG) != 0
}
pub fn try_unwrap(&self) -> Option<EntityU16> {
let content = self.content.get();
if Self::is_wrap(content) {
let content = (content & !WRAP32_FLAG) as u16;
let content = NonZeroU16::new(content).unwrap();
Some(EntityU16 { content })
} else {
None
}
}
pub fn try_len(&self) -> Option<u16> {
let content = self.content.get();
if Self::is_wrap(content) {
self.try_unwrap()
.unwrap()
.try_len()
.and_then(|x| Some(x as u16))
} else if Self::is_inline_length(content) {
let content = content & !(1 << MEDIUM_CHILD_FLAG);
let content = (content >> CHILDREN_COUNT) as u16;
Some(content)
} else {
None
}
}
pub fn try_store(&self) -> Option<u16> {
let content = self.content.get();
if Self::is_wrap(content) {
None
} else if Self::is_inline_length(content) {
let content = content & !(1 << MEDIUM_CHILD_FLAG);
let content = (content >> CHILDREN_COUNT) as u16;
let content = content as u16 & 0x00ff;
Some(content)
} else {
let content = content & !WRAP32_FLAG;
Some(content as u16)
}
}
pub fn try_id(&self) -> Option<u16> {
let content = self.content.get();
if Self::is_wrap(content) {
None
} else {
let content = content & !WRAP32_FLAG;
Some(content as u16)
}
}
fn as_u32(&self) -> u32 {
self.content.get()
}
}
struct MediumData<CS, H, LS, SS, RS> {
kind: u16,
size: NonZeroU16,
height: u16,
hash: H,
labels: LS,
spaces: SS,
children: CS,
refs: RS,
}
mod medium {
use super::*;
use crate::filter::Bloom;
use std::{collections::HashSet, marker::PhantomData};
struct Kind(u16);
struct Size(NonZeroU16);
struct Height(u16);
struct HStructLabel(u64);
struct HSyntax(u32);
struct CS0<const N: usize> {
children: [EntityU32; N],
}
struct CS {
children: [EntityU32],
}
struct LS {
starts: Box<[usize]>,
length: Box<[Option<NonZeroU16>]>,
}
struct RS0<T, const N: usize> {
bloom: Bloom<T, [u64; N]>,
_phantom: PhantomData<T>,
}
struct RS<T> {
set: HashSet<T>,
}
}
#[derive(Debug, Clone, Copy)]
pub struct EntityU64 {
content: NonZeroU64,
}
const WRAP64_FLAG: u64 = 0xffffffff00000000;
impl EntityU64 {
fn wrap(small: EntityU32) -> Self {
Self {
content: NonZeroU64::new(small.as_u32() as u64).unwrap(),
}
}
fn is_wrap(content: u64) -> bool {
content & WRAP64_FLAG == 0
}
pub fn try_unwrap(&self) -> Option<EntityU32> {
let content = self.content.get();
if Self::is_wrap(content) {
let content = (content & !WRAP64_FLAG) as u32;
let content = NonZeroU32::new(content).unwrap();
Some(EntityU32 { content })
} else {
None
}
}
}
mod large {
use std::marker::PhantomData;
use crate::filter::Bloom;
pub use super::medium::*;
use super::*;
struct CS0<const N: usize> {
children: [EntityU64; N],
}
struct CS {
children: [EntityU64],
}
struct RS0<T, const N: usize> {
bloom: Bloom<T, [u64; N]>,
_phantom: PhantomData<T>,
}
}
#[cfg(test)]
mod tests {
use std::mem::size_of;
use super::*;
#[test]
fn test() {
println!("{}", size_of::<EntityU16>());
println!("{}", size_of::<Option<EntityU16>>());
println!("{}", size_of::<EntityU32>());
println!("{}", size_of::<Option<EntityU32>>());
println!("{}", size_of::<EntityU64>());
println!("{}", size_of::<Option<EntityU64>>());
println!("{}", size_of::<Box<()>>());
println!("{}", size_of::<Box<[u8]>>());
println!("{}", size_of::<[u8; 1]>());
println!("{}", size_of::<&[u8]>());
}
}
const BLOCK_SIZE: u32 = 16;
const BLOCK_SIZE_USIZE: usize = BLOCK_SIZE as usize;
static NEXT_ENTITY: AtomicU32 = AtomicU32::new(BLOCK_SIZE);
#[derive(Debug)]
pub struct Allocate {
next: u32,
}
impl Allocate {
pub fn new() -> Self {
Self { next: 0 }
}
}
impl Default for Allocate {
fn default() -> Self {
Self::new()
}
}
impl<'a> Iterator for Allocate {
type Item = Entity;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.next % BLOCK_SIZE == 0 {
self.next = NEXT_ENTITY.fetch_add(BLOCK_SIZE, Ordering::Relaxed);
debug_assert_eq!(self.next % BLOCK_SIZE, 0);
}
let entity = unsafe {
debug_assert_ne!(self.next, 0);
Entity {
content: NonZeroU32::new_unchecked(self.next),
}
};
self.next += 1;
Some(entity)
}
}
type Entity = EntityU32;
use std::sync::atomic::AtomicU32;
use std::{
collections::HashMap,
mem,
ops::Range,
sync::atomic::{AtomicU64, Ordering},
};
use legion::query::LayoutFilter;
use legion::storage::{
Archetype, ArchetypeIndex, ArchetypeSource, ArchetypeWriter, Component, ComponentStorage,
ComponentTypeId,
};
use legion::storage::{Components, EntityLayout, SearchIndex};
use legion::world::{ComponentAccess, ComponentError, EntityAccessError};
pub trait ComponentSource: ArchetypeSource {
fn push_components<'a>(
&mut self,
writer: &mut ArchetypeWriter<'a>,
entities: impl Iterator<Item = Entity>,
);
}
pub trait KnownLength {
fn len(&self) -> usize;
}
pub trait IntoComponentSource {
type Source: ComponentSource;
fn into(self) -> Self::Source;
}
pub trait EntityStore {
fn id(&self) -> WorldId;
fn entry_ref(&self, entity: Entity) -> Result<EntryRef, EntityAccessError>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct WorldId(u64);
static WORLD_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
impl WorldId {
fn next() -> Self {
WorldId(WORLD_ID_COUNTER.fetch_add(1, Ordering::Relaxed))
}
}
impl Default for WorldId {
fn default() -> Self {
Self::next()
}
}
#[derive(Debug)]
pub struct World {
small: SmallWorld,
id: WorldId,
index: SearchIndex,
components: Components,
archetypes: Vec<Archetype>,
allocation_buffer: Vec<Entity>,
}
impl World {
pub fn extend(&mut self, components: impl IntoComponentSource) -> &[Entity] {
let mut self_alloc_buf = mem::take(&mut self.allocation_buffer);
self_alloc_buf.clear();
self.extend_out(components, &mut self_alloc_buf);
self.allocation_buffer = self_alloc_buf;
&self.allocation_buffer
}
pub fn extend_out<S, E>(&mut self, components: S, out: &mut E)
where
S: IntoComponentSource,
E: for<'a> Extend<&'a Entity>,
{
let replaced = {
let mut components = components.into();
let arch_index = self.get_archetype_for_components(&mut components);
let archetype = &mut self.archetypes[arch_index.0 as usize];
let mut writer =
ArchetypeWriter::new(arch_index, archetype, self.components.get_multi_mut());
todo!();
components.push_components(&mut writer, Allocate::new());
let (base, entities) = writer.inserted();
};
}
pub fn components(&self) -> &Components {
&self.components
}
pub(crate) fn archetypes(&self) -> &[Archetype] {
&self.archetypes
}
pub(crate) fn get_archetype_for_components<T: ArchetypeSource>(
&mut self,
components: &mut T,
) -> ArchetypeIndex {
let index = self.index.search(&components.filter()).next();
if let Some(index) = index {
index
} else {
self.insert_archetype(components.layout())
}
}
fn insert_archetype(&mut self, layout: EntityLayout) -> ArchetypeIndex {
let arch_index = ArchetypeIndex(self.archetypes.len() as u32);
todo!();
arch_index
}
}
pub struct EntryRef<'a> {
pub(crate) location: EntityLocation,
pub(crate) components: &'a Components,
pub(crate) archetype: &'a Archetype,
pub(crate) allowed_components: ComponentAccess<'a>,
}
#[derive(Clone, Copy)]
pub struct EntityLocation {
index: u16,
}
pub struct ComponentIndex(pub(crate) usize);
impl EntityLocation {
pub fn new(index: u16) -> Self {
EntityLocation { index }
}
pub fn component(&self) -> ComponentIndex {
ComponentIndex(self.index as usize)
}
}
impl<'a> EntryRef<'a> {
pub(crate) fn new(
location: EntityLocation,
components: &'a Components,
archetype: &'a Archetype,
allowed_components: ComponentAccess<'a>,
) -> Self {
Self {
location,
components,
archetype,
allowed_components,
}
}
pub fn archetype(&self) -> &Archetype {
&self.archetype
}
pub fn location(&self) -> EntityLocation {
self.location
}
pub fn into_component<T: Component>(self) -> Result<&'a T, ComponentError> {
let component_type = ComponentTypeId::of::<T>();
if !self.allowed_components.allows_read(component_type) {
return Err(ComponentError::Denied {
component_type,
component_name: std::any::type_name::<T>(),
});
}
let component = self.location.component();
let archetype = self.archetype();
todo!();
}
pub fn get_component<T: Component>(&self) -> Result<&T, ComponentError> {
todo!()
}
}
#[derive(Debug)]
struct SmallWorld {}
impl SmallWorld {
fn archetype(&self, len: u8) -> &Archetype {
todo!()
}
fn leaf_archetype(&self) -> &Archetype {
todo!()
}
}
impl EntityStore for World {
fn entry_ref(&self, entity: Entity) -> Result<EntryRef, EntityAccessError> {
entity
.try_store()
.map(|x| {
EntryRef::new(
EntityLocation::new(entity.try_id().unwrap()),
&self.components,
&self.archetypes[x as usize],
ComponentAccess::All,
)
})
.or_else(|| {
let unwrapped = entity.try_unwrap().unwrap();
unwrapped
.try_len()
.map(|len| {
let small = self.small.archetype(len);
EntryRef::new(
EntityLocation::new(unwrapped.try_id().unwrap()),
&self.components,
small,
ComponentAccess::All,
)
})
.or_else(|| {
let small = self.small.leaf_archetype();
unwrapped.try_type().map(|x| {
EntryRef::new(
EntityLocation::new(x),
&self.components,
small,
ComponentAccess::All,
)
})
})
})
.ok_or(EntityAccessError::EntityNotFound)
}
fn id(&self) -> WorldId {
self.id
}
}