use std::alloc::Layout;
use crate::cache::WorldInfoCache;
use crate::*;
pub(crate) fn register_component_typed<T: 'static>(
world: *mut ecs_world_t,
name: Option<&str>,
) -> EntityId {
if let Some(comp_id) = WorldInfoCache::get_component_id_for_type::<T>(world) {
return comp_id;
}
let type_id = TypeId::of::<T>();
let layout = std::alloc::Layout::new::<T>();
let symbol = std::any::type_name::<T>().to_owned();
let name = if let Some(name) = name {
name.to_owned()
} else {
if symbol.contains('<') {
let mut nested_templates = Vec::new();
let mut read_idx = 0;
for (i, c) in symbol.chars().enumerate() {
if (c == '<' || c == '>') && read_idx != i {
nested_templates.push(symbol[read_idx..i].to_string());
read_idx = i + 1;
}
}
assert!(!nested_templates.is_empty());
let mut stripped_name = nested_templates.last().unwrap().to_owned();
for s in nested_templates.iter().rev().skip(1) {
let s = s.split("::").last().unwrap().to_owned();
stripped_name = s + "<" + &stripped_name + ">";
}
stripped_name
} else {
let s = symbol.replace("::", ".");
s.split('.').last().unwrap().to_owned()
}
};
let symbol = name.clone();
let comp_id =
register_component(world, ComponentDescriptor { symbol, name, custom_id: None, layout });
WorldInfoCache::register_component_id_for_type_id(world, comp_id, type_id);
comp_id
}
pub(crate) fn register_component_dynamic(
world: *mut ecs_world_t,
symbol: &'static str,
name: Option<&'static str>,
layout: Layout,
) -> EntityId {
if let Some(comp_info) = WorldInfoCache::get_component_id_for_symbol(world, symbol) {
return comp_info.id;
}
let comp_id = register_component(
world,
ComponentDescriptor {
symbol: symbol.to_owned(),
name: name.unwrap_or("").to_owned(),
custom_id: None,
layout,
},
);
WorldInfoCache::register_component_id_for_symbol(world, comp_id, symbol, layout.size());
comp_id
}
pub(crate) fn get_component_info(
world: *mut ecs_world_t,
comp_e: ecs_entity_t,
) -> Option<EcsComponent> {
let id = unsafe { FLECS_IDEcsComponentID_ };
let raw = unsafe { ecs_get_id(world, comp_e, id) };
if raw.is_null() {
return None;
}
let c = unsafe { (raw as *const EcsComponent).as_ref().unwrap() };
Some(*c)
}
#[derive(Debug)]
pub struct ComponentDescriptor {
pub symbol: String,
pub name: String,
pub custom_id: Option<u64>,
pub layout: std::alloc::Layout,
}
pub fn register_component(world: *mut ecs_world_t, desc: ComponentDescriptor) -> ecs_entity_t {
let name_c_str = std::ffi::CString::new(desc.name).unwrap();
let symbol_c_str = std::ffi::CString::new(desc.symbol).unwrap();
let sep = std::ffi::CString::new("::").unwrap();
let mut entity_desc: ecs_entity_desc_t = unsafe { MaybeUninit::zeroed().assume_init() };
if let Some(custom_id) = desc.custom_id {
entity_desc.id = custom_id;
}
entity_desc.name = name_c_str.as_ptr() as *const i8;
entity_desc.symbol = symbol_c_str.as_ptr() as *const i8;
entity_desc.sep = sep.as_ptr() as *const i8;
entity_desc.root_sep = sep.as_ptr() as *const i8;
let entity = unsafe { ecs_entity_init(world, &entity_desc) };
if desc.layout.size() > 0 {
let mut comp_desc: ecs_component_desc_t = unsafe { MaybeUninit::zeroed().assume_init() };
comp_desc.entity = entity;
comp_desc.type_.size = desc.layout.size() as ecs_size_t;
comp_desc.type_.alignment = desc.layout.align() as ecs_size_t;
let comp_entity = unsafe { ecs_component_init(world, &comp_desc) };
assert!(comp_entity == entity);
}
entity
}