use my_ecs_macros::repeat_macro;
use my_utils::ds::{unimpl_clone, unimpl_default, ATypeId, FnCloneRaw, FnDefaultRaw, TypeInfo};
pub trait Component: Send + Sync + Sized + 'static {
const IS_SEND: bool = true; const IS_SYNC: bool = true;
const IS_DEFAULT: bool = false; const FN_DEFAULT: FnDefaultRaw = unimpl_default; const IS_CLONE: bool = false; const FN_CLONE: FnCloneRaw = unimpl_clone;
fn key() -> ComponentKey {
ComponentKey::of::<Self>()
}
fn type_info() -> TypeInfo {
TypeInfo::new::<Self>(
Self::IS_SEND,
Self::IS_SYNC,
Self::IS_DEFAULT.then_some(Self::FN_DEFAULT),
Self::IS_CLONE.then_some(Self::FN_CLONE),
)
}
}
pub trait Components: 'static {
type Keys: AsRef<[ComponentKey]>;
type Infos: AsRef<[TypeInfo]>;
const LEN: usize;
fn keys() -> Self::Keys;
fn infos() -> Self::Infos;
fn sorted_keys() -> Self::Keys;
}
macro_rules! impl_components {
($n:expr, $($i:expr),*) => {const _: () = {
#[allow(unused_imports)]
use $crate::{
utils::ds::TypeInfo,
ecs::ent::component::{Component, Components, ComponentKey},
};
use paste::paste;
paste! {
#[allow(unused_parens)]
impl<$([<A $i>]: Component),*> Components for ( $([<A $i>]),* ) {
type Keys = [ComponentKey; $n];
type Infos = [TypeInfo; $n];
const LEN: usize = $n;
fn keys() -> Self::Keys {
[ $( [<A $i>]::key() ),* ]
}
fn infos() -> Self::Infos {
[ $( [<A $i>]::type_info() ),* ]
}
fn sorted_keys() -> Self::Keys {
let mut keys = [ $( [<A $i>]::key() ),* ];
keys.sort_unstable();
keys
}
}
}
};};
}
repeat_macro!(impl_components, ..=32);
pub type ComponentKey = ATypeId<ComponentKey_>;
pub struct ComponentKey_;
#[cfg(test)]
mod tests {
use super::*;
use crate as my_ecs;
use my_ecs_macros::Component;
use my_utils::ds::{NotClone, NotDefault};
#[test]
fn test_component_detect_impls() {
#![allow(dead_code)]
#[derive(Component, Clone)]
struct CloneA([u8; 1]);
#[derive(Component, Clone)]
struct CloneB([u8; 2]);
#[derive(Component)]
struct NonCloneA([u8; 1]);
#[derive(Component)]
struct NonCloneB([u8; 2]);
assert!(is_clone_fn_eq::<NonCloneA, NonCloneB>());
assert!(is_clone_fn_ne::<CloneA, CloneB>());
assert!(is_clone_fn_ne::<CloneA, NonCloneA>());
assert!(is_clone_fn_ne::<CloneB, NonCloneA>());
fn is_clone_fn_eq<Ca: Component, Cb: Component>() -> bool {
let clone_a = Ca::FN_CLONE as usize;
let clone_b = Cb::FN_CLONE as usize;
clone_a == clone_b
}
fn is_clone_fn_ne<Ca: Component, Cb: Component>() -> bool {
let clone_a = Ca::FN_CLONE as usize;
let clone_b = Cb::FN_CLONE as usize;
clone_a != clone_b
}
}
}