use flecs_ecs::prelude::*;
pub struct ComponentIdFetcher<T> {
pub phantom: core::marker::PhantomData<T>,
}
#[derive(Debug)]
pub struct FetchedId<T> {
pub id: u64,
phantom: core::marker::PhantomData<T>,
}
impl<T> Clone for FetchedId<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for FetchedId<T> {}
impl<T> From<FetchedId<T>> for u64 {
fn from(id: FetchedId<T>) -> u64 {
id.id
}
}
impl<T> From<FetchedId<T>> for Entity {
fn from(id: FetchedId<T>) -> Entity {
Entity::new(id.id())
}
}
impl<T> FetchedId<T> {
pub fn new(id: u64) -> Self {
Self {
id,
phantom: core::marker::PhantomData,
}
}
pub fn id(&self) -> u64 {
self.id
}
}
pub trait FlecsComponent<T> {
fn deref_id<'a>(&self, world: impl WorldProvider<'a>) -> FetchedId<T>;
}
pub trait ExternalComponent<T> {
fn deref_id<'a>(&self, world: impl WorldProvider<'a>) -> FetchedId<T>;
}
impl<T: ComponentId> FlecsComponent<T> for &&ComponentIdFetcher<T> {
fn deref_id<'a>(&self, world: impl WorldProvider<'a>) -> FetchedId<T> {
FetchedId::new(T::entity_id(world))
}
}
impl<T: 'static> ExternalComponent<T> for &ComponentIdFetcher<T> {
fn deref_id<'a>(&self, world: impl WorldProvider<'a>) -> FetchedId<T> {
let world = world.world();
let map = world.components_map();
let id = *(map.entry(core::any::TypeId::of::<T>()).or_insert_with(|| {
let type_name = get_type_name_without_scope_generic::<T>();
let name =
compact_str::format_compact!("external_components::{}\0", type_name.as_str());
external_register_component::<true, T>(world, name.as_ptr() as *const _)
}));
FetchedId::new(id)
}
}
#[macro_export]
macro_rules! id {
($world:expr, $type:ty) => {
(&&&flecs_ecs::addons::meta::ComponentIdFetcher::<$type> {
phantom: core::marker::PhantomData,
})
.deref_id($world)
};
}
pub use id;
#[cfg(test)]
mod tests {
use flecs_ecs::prelude::*;
#[test]
fn meta_id_macro_test() {
#[derive(Component)]
struct Position {
_x: f32,
_y: f32,
}
struct ExternalPosition {
_x: f32,
_y: f32,
}
let world = World::new();
let id = id!(&world, Position).id();
assert_eq!(id, world.component_id::<Position>());
let id_ext = id!(&world, ExternalPosition).id();
assert_ne!(id_ext, id);
let world_ref = world.real_world();
let id_world_ref = id!(world_ref, Position).id();
assert_eq!(id_world_ref, id);
let id_ext_world_ref = id!(world_ref, ExternalPosition).id();
assert_eq!(id_ext_world_ref, id_ext);
}
fn get_id_from_fetcher<T: 'static>(fetcher: FetchedId<T>) -> u64 {
fetcher.id()
}
#[test]
fn meta_id_macro_test_ref() {
#[derive(Component)]
struct Position {
_x: f32,
_y: f32,
}
struct ExternalPosition {
_x: f32,
_y: f32,
}
let world = World::new();
let fetcher = id!(&world, Position);
let id = get_id_from_fetcher(fetcher);
assert_eq!(id, world.component_id::<Position>());
let fetcher_ext = id!(&world, ExternalPosition);
let id_ext = get_id_from_fetcher(fetcher_ext);
assert_ne!(id_ext, id);
}
}