use crate::{
archetype,
component::Component,
entity,
registry,
registry::{
sealed::Length,
Registry,
},
};
use alloc::{
vec,
vec::Vec,
};
pub enum Contained {}
pub enum NotContained {}
pub enum Null {}
pub trait Canonical<E, P>: Registry + Sized {
#[must_use]
fn create_archetype_identifier() -> archetype::Identifier<Self>;
unsafe fn populate_archetype_identifier(identifier: &mut [u8], length: usize);
}
impl Canonical<entity::Null, Null> for registry::Null {
fn create_archetype_identifier() -> archetype::Identifier<Self> {
unsafe { archetype::Identifier::new(Vec::new()) }
}
unsafe fn populate_archetype_identifier(_identifier: &mut [u8], _length: usize) {}
}
impl<C, E, P, R> Canonical<(C, E), (Contained, P)> for (C, R)
where
C: Component,
R: Canonical<E, P>,
{
fn create_archetype_identifier() -> archetype::Identifier<Self> {
let mut raw_identifier = vec![0; (Self::LEN + 7) / 8];
unsafe {
<Self as Canonical<(C, E), (Contained, P)>>::populate_archetype_identifier(
&mut raw_identifier,
Self::LEN - 1,
);
archetype::Identifier::new(raw_identifier)
}
}
unsafe fn populate_archetype_identifier(identifier: &mut [u8], length: usize) {
*unsafe { identifier.get_unchecked_mut((length - R::LEN) / 8) } |=
1 << ((length - R::LEN) % 8);
unsafe {
R::populate_archetype_identifier(identifier, length);
}
}
}
impl<C, E, P, R> Canonical<E, (NotContained, P)> for (C, R)
where
C: Component,
R: Canonical<E, P>,
{
fn create_archetype_identifier() -> archetype::Identifier<Self> {
let mut raw_identifier = vec![0; (Self::LEN + 7) / 8];
unsafe {
<Self as Canonical<E, (NotContained, P)>>::populate_archetype_identifier(
&mut raw_identifier,
Self::LEN - 1,
);
archetype::Identifier::new(raw_identifier)
}
}
unsafe fn populate_archetype_identifier(identifier: &mut [u8], length: usize) {
unsafe {
R::populate_archetype_identifier(identifier, length);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
archetype,
entity,
Registry,
};
use alloc::vec::Vec;
struct A;
struct B;
struct C;
struct D;
struct E;
struct F;
struct G;
struct H;
struct I;
type Registry = Registry!(A, B, C, D, E, F, G, H, I);
#[test]
fn create_archetype_identifier_empty_registry() {
type Registry = Registry!();
assert_eq!(Registry::create_archetype_identifier(), unsafe {
archetype::Identifier::<Registry>::new(Vec::new())
});
}
#[test]
fn create_archetype_identifier_all_components() {
assert_eq!(
<Registry as Canonical<(A, (B, (C, (D, (E, (F, (G, (H, (I, entity::Null))))))))), _>>::create_archetype_identifier(),
unsafe {archetype::Identifier::<Registry>::new(vec![255, 1])}
);
}
#[test]
fn create_archetype_identifier_first_component_present() {
assert_eq!(
<Registry as Canonical<(A, (C, (D, entity::Null))), _>>::create_archetype_identifier(),
unsafe { archetype::Identifier::<Registry>::new(vec![13, 0]) }
);
}
#[test]
fn create_archetype_identifier_first_component_not_present() {
assert_eq!(
<Registry as Canonical<(B, (E, (I, entity::Null))), _>>::create_archetype_identifier(),
unsafe { archetype::Identifier::<Registry>::new(vec![18, 1]) }
);
}
}