use core::ffi::{CStr, c_void};
use flecs_ecs::prelude::*;
use flecs_ecs::sys;
#[cfg(feature = "std")]
extern crate std;
extern crate alloc;
use alloc::{format, string::String, vec::Vec};
use crate::addons::meta::ecs_serializer::EcsSerializer;
macro_rules! generate_vec_meta_registration {
($world:ident, $($t:ty),*) => {
$(
{
let id = id!($world, Vec<$t>);
$world
.component_named_ext::<Vec<$t>>(id, format!("vector::{}", stringify!($t)).as_str())
.opaque_func_id::<_, $t>(id, meta_register_vector_default::<$t>);
}
)*
};
}
pub(crate) fn meta_init_builtin(world: &World) {
world
.component_named::<String>("flecs::rust::String")
.opaque_func(std_string_support);
use core::any::TypeId;
let map = world.components_map();
map.insert(TypeId::of::<bool>(), ECS_BOOL_T);
map.insert(TypeId::of::<char>(), ECS_CHAR_T);
map.insert(TypeId::of::<u8>(), ECS_U8_T);
map.insert(TypeId::of::<u16>(), ECS_U16_T);
map.insert(TypeId::of::<u32>(), ECS_U32_T);
map.insert(TypeId::of::<u64>(), ECS_U64_T);
map.insert(TypeId::of::<usize>(), ECS_UPTR_T);
map.insert(TypeId::of::<i8>(), ECS_I8_T);
map.insert(TypeId::of::<i16>(), ECS_I16_T);
map.insert(TypeId::of::<i32>(), ECS_I32_T);
map.insert(TypeId::of::<i64>(), ECS_I64_T);
map.insert(TypeId::of::<isize>(), ECS_IPTR_T);
map.insert(TypeId::of::<f32>(), ECS_F32_T);
map.insert(TypeId::of::<f64>(), ECS_F64_T);
map.insert(TypeId::of::<Entity>(), ECS_ENTITY_T);
map.insert(TypeId::of::<flecs::meta::Bool>(), ECS_BOOL_T);
map.insert(TypeId::of::<flecs::meta::Char>(), ECS_CHAR_T);
map.insert(TypeId::of::<flecs::meta::Byte>(), ECS_BYTE_T);
map.insert(TypeId::of::<flecs::meta::U8>(), ECS_U8_T);
map.insert(TypeId::of::<flecs::meta::U16>(), ECS_U16_T);
map.insert(TypeId::of::<flecs::meta::U32>(), ECS_U32_T);
map.insert(TypeId::of::<flecs::meta::U64>(), ECS_U64_T);
map.insert(TypeId::of::<flecs::meta::UPtr>(), ECS_UPTR_T);
map.insert(TypeId::of::<flecs::meta::I8>(), ECS_I8_T);
map.insert(TypeId::of::<flecs::meta::I16>(), ECS_I16_T);
map.insert(TypeId::of::<flecs::meta::I32>(), ECS_I32_T);
map.insert(TypeId::of::<flecs::meta::I64>(), ECS_I64_T);
map.insert(TypeId::of::<flecs::meta::IPtr>(), ECS_IPTR_T);
map.insert(TypeId::of::<flecs::meta::F32>(), ECS_F32_T);
map.insert(TypeId::of::<flecs::meta::F64>(), ECS_F64_T);
map.insert(TypeId::of::<flecs::meta::String>(), ECS_STRING_T);
map.insert(TypeId::of::<flecs::meta::Entity>(), ECS_ENTITY_T);
map.insert(TypeId::of::<flecs::meta::Id>(), ECS_ID_T);
map.insert(TypeId::of::<flecs::Constant>(), ECS_CONSTANT);
map.insert(TypeId::of::<flecs::meta::Quantity>(), ECS_QUANTITY);
map.insert(TypeId::of::<flecs::meta::EcsOpaque>(), ECS_OPAQUE);
generate_vec_meta_registration!(
world, String, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, bool, char, usize, isize
);
}
fn std_string_support(world: WorldRef) -> Opaque<String> {
let mut ts = Opaque::<String>::new(world);
ts.as_type(flecs::meta::String);
ts.serialize(|s: &Serializer, data: &String| {
let data = compact_str::format_compact!("{}\0", data);
unsafe {
s.value_id(
flecs::meta::String,
&data.as_ptr() as *const *const u8 as *const core::ffi::c_void,
)
}
});
ts.assign_string(|data: &mut String, value: *const core::ffi::c_char| {
*data = unsafe { CStr::from_ptr(value).to_string_lossy().into_owned() }
});
ts
}
pub fn meta_ser_stringify_type_debug<T: core::fmt::Debug>(world: WorldRef) -> Opaque<T> {
let mut ts = Opaque::<T>::new(world);
ts.as_type(flecs::meta::String);
ts.serialize(|s: &Serializer, data: &T| {
let data = format!("{data:?}");
let data = compact_str::format_compact!("{data}\0");
unsafe {
s.value_id(
flecs::meta::String,
&data.as_ptr() as *const *const u8 as *const core::ffi::c_void,
)
}
});
ts
}
pub fn meta_ser_stringify_type_display<T: core::fmt::Display>(world: WorldRef) -> Opaque<T> {
let mut ts = Opaque::<T>::new(world);
ts.as_type(flecs::meta::String);
ts.serialize(|s: &Serializer, data: &T| {
let data = format!("{data}");
let data = compact_str::format_compact!("{data}\0");
unsafe {
s.value_id(
flecs::meta::String,
&data.as_ptr() as *const *const u8 as *const core::ffi::c_void,
)
}
});
ts
}
pub fn meta_register_vector_default<T: Default>(world: WorldRef) -> Opaque<Vec<T>, T> {
let mut ts = Opaque::<Vec<T>, T>::new(world);
ts.as_type(world.vector::<T>());
ts.serialize(|s: &Serializer, data: &Vec<T>| {
let world = unsafe { WorldRef::from_ptr(s.world as *mut sys::ecs_world_t) };
let id = id!(world, T);
for el in data.iter() {
unsafe { s.value_id(id, el as *const T as *const core::ffi::c_void) };
}
0
});
ts.count(|data: &mut Vec<T>| data.len());
fn ensure_generic_element<T: Default>(data: &mut Vec<T>, elem: usize) -> &mut T {
if data.len() <= elem {
data.resize_with(elem + 1, || T::default());
}
&mut data[elem]
}
fn resize_generic_vec<T: Default>(data: &mut Vec<T>, new_size: usize) {
data.resize_with(new_size, || T::default());
}
ts.ensure_element(ensure_generic_element::<T>);
ts.resize(resize_generic_vec::<T>);
ts
}
pub fn flecs_entity_support<'a>(world: impl WorldProvider<'a>) -> Opaque<'a, Entity> {
let mut opaque = Opaque::<Entity>::new(world);
opaque.as_type(flecs::meta::Entity::ID);
opaque.serialize(|ser: &Serializer, data: &Entity| {
let id: Id = <Entity as Into<Id>>::into(*data);
let id: u64 = *id;
unsafe { ser.value_id(flecs::meta::Entity::ID, &id as *const u64 as *const c_void) }
});
opaque.assign_entity(|dst: &mut Entity, _world: WorldRef<'a>, e: Entity| {
*dst = e;
});
opaque
}