#![doc(hidden)]
use core::{ffi::c_void, mem::MaybeUninit, ptr};
use crate::core::*;
use crate::sys;
#[cfg(feature = "std")]
extern crate std;
extern crate alloc;
use alloc::boxed::Box;
use flecs_ecs_derive::extern_abi;
#[expect(dead_code, reason = "possibly used in the future")]
#[derive(Default)]
pub(crate) struct RegistersPanicHooks {
pub(crate) ctor: bool,
pub(crate) copy: bool,
}
#[expect(dead_code, reason = "possibly used in the future")]
#[extern_abi]
pub(crate) unsafe fn register_panic_hooks_free_ctx(ctx: *mut c_void) {
let _box = unsafe { Box::from_raw(ctx as *mut RegistersPanicHooks) };
}
pub fn register_lifecycle_actions<T>(type_hooks: &mut sys::ecs_type_hooks_t) {
type_hooks.dtor = Some(dtor::<T>);
type_hooks.move_dtor = Some(move_dtor::<T>);
type_hooks.ctor_move_dtor = Some(ctor_move_dtor::<T>);
}
pub fn register_ctor_lifecycle_actions<T: Default>(type_hooks: &mut sys::ecs_type_hooks_t) {
type_hooks.ctor = Some(ctor::<T>);
}
pub fn register_ctor_panic_lifecycle_actions<T>(type_hooks: &mut sys::ecs_type_hooks_t) {
type_hooks.ctor = Some(panic_ctor::<T>);
}
pub fn register_copy_lifecycle_action<T: Clone>(type_hooks: &mut sys::ecs_type_hooks_t) {
type_hooks.copy = Some(copy::<T>);
type_hooks.copy_ctor = Some(copy_ctor::<T>); }
pub fn register_copy_panic_lifecycle_action<T>(type_hooks: &mut sys::ecs_type_hooks_t) {
type_hooks.copy = Some(panic_copy::<T>);
type_hooks.copy_ctor = Some(panic_copy::<T>); }
pub fn register_partial_ord_lifecycle_action<T: core::cmp::PartialOrd>(
type_hooks: &mut sys::ecs_type_hooks_t,
) {
type_hooks.cmp = Some(compare::<T>);
}
pub fn register_partial_ord_panic_lifecycle_action<T>(type_hooks: &mut sys::ecs_type_hooks_t) {
type_hooks.cmp = Some(panic_compare::<T>);
}
pub fn register_partial_eq_lifecycle_action<T: core::cmp::PartialEq>(
type_hooks: &mut sys::ecs_type_hooks_t,
) {
type_hooks.equals = Some(equals::<T>);
}
pub fn register_partial_eq_panic_lifecycle_action<T>(type_hooks: &mut sys::ecs_type_hooks_t) {
type_hooks.equals = Some(panic_equals::<T>);
}
#[extern_abi]
fn ctor<T: Default>(ptr: *mut c_void, count: i32, _type_info: *const sys::ecs_type_info_t) {
let size = const { core::mem::size_of::<T>() };
if size == 0 {
return;
}
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let arr = ptr as *mut MaybeUninit<T>;
for i in 0..count as usize {
unsafe {
MaybeUninit::write(&mut *arr.add(i), T::default());
}
}
}
#[extern_abi]
fn dtor<T>(ptr: *mut c_void, count: i32, _type_info: *const sys::ecs_type_info_t) {
let size = const { core::mem::size_of::<T>() };
if size == 0 {
let arr = ptr as *mut u8; for i in 0..count as isize {
unsafe {
let item = arr.offset(i);
ptr::drop_in_place(item as *mut T);
}
}
} else {
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let arr = ptr as *mut T;
for i in 0..count as isize {
unsafe {
let item = arr.offset(i);
ptr::drop_in_place(item);
}
}
}
}
#[extern_abi]
fn copy<T: Clone>(
dst_ptr: *mut c_void,
src_ptr: *const c_void,
count: i32,
_type_info: *const sys::ecs_type_info_t,
) {
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let dst_arr = dst_ptr as *mut T;
let src_arr = src_ptr as *const T;
for i in 0..count as isize {
unsafe {
let src_value = &*(src_arr.offset(i)); let dst_value = dst_arr.offset(i); core::ptr::drop_in_place(dst_value); core::ptr::write(dst_value, src_value.clone()); }
}
}
#[extern_abi]
fn copy_ctor<T: Clone>(
dst_ptr: *mut c_void,
src_ptr: *const c_void,
count: i32,
_type_info: *const sys::ecs_type_info_t,
) {
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let dst_arr = dst_ptr as *mut T;
let src_arr = src_ptr as *const T;
for i in 0..count as isize {
unsafe {
let src_value = &*(src_arr.offset(i)); let dst_value = dst_arr.offset(i); core::ptr::write(dst_value, src_value.clone()); }
}
}
#[extern_abi]
fn panic_ctor<T>(_dst_ptr: *mut c_void, _count: i32, _type_info: *const sys::ecs_type_info_t) {
panic!(
"Default is not implemented for type {} which requires drop and it's being used in an operation which calls the constructor",
core::any::type_name::<T>()
);
}
#[extern_abi]
fn panic_copy<T>(
_dst_ptr: *mut c_void,
_src_ptr: *const c_void,
_count: i32,
_type_info: *const sys::ecs_type_info_t,
) {
panic!(
"Clone is not implemented for type {} and it's being used in a copy / duplicate operation such as component overriding or duplicating entities / components or prefab copying",
core::any::type_name::<T>()
);
}
#[extern_abi]
fn move_dtor<T>(
dst_ptr: *mut c_void,
src_ptr: *mut c_void,
count: i32,
_type_info: *const sys::ecs_type_info_t,
) {
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let dst_arr = dst_ptr as *mut T;
let src_arr = src_ptr as *mut T;
for i in 0..count as isize {
unsafe {
let src_value = src_arr.offset(i); let dst_value = dst_arr.offset(i);
core::ptr::copy_nonoverlapping(src_value, dst_value, 1);
}
}
}
#[extern_abi]
fn move_dtor_impls_default<T: Default>(
dst_ptr: *mut c_void,
src_ptr: *mut c_void,
count: i32,
_type_info: *const sys::ecs_type_info_t,
) {
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let dst_arr = dst_ptr as *mut T;
let src_arr = src_ptr as *mut T;
for i in 0..count as isize {
unsafe {
let src_value = src_arr.offset(i); let dst_value = dst_arr.offset(i);
core::ptr::drop_in_place(dst_value);
core::ptr::copy_nonoverlapping(src_value, dst_value, 1);
}
}
}
#[extern_abi]
fn move_ctor<T>(
dst_ptr: *mut c_void,
src_ptr: *mut c_void,
count: i32,
_type_info: *const sys::ecs_type_info_t,
) {
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let dst_arr = dst_ptr as *mut T;
let src_arr = src_ptr as *mut T;
for i in 0..count as isize {
unsafe {
core::ptr::copy_nonoverlapping(src_arr.offset(i), dst_arr.offset(i), 1);
}
}
}
#[extern_abi]
fn ctor_move_dtor<T>(
dst_ptr: *mut c_void,
src_ptr: *mut c_void,
count: i32,
_type_info: *const sys::ecs_type_info_t,
) {
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let dst_arr = dst_ptr as *mut T;
let src_arr = src_ptr as *mut T;
for i in 0..count as isize {
unsafe {
core::ptr::copy_nonoverlapping(src_arr.offset(i), dst_arr.offset(i), 1);
}
}
}
#[extern_abi]
fn compare<T: core::cmp::PartialOrd>(
a: *const c_void,
b: *const c_void,
_type_info: *const sys::ecs_type_info_t,
) -> i32 {
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let lhs = unsafe { &*(a as *const T) };
let rhs = unsafe { &*(b as *const T) };
if lhs == rhs {
0
} else if lhs < rhs {
-1 } else {
1 }
}
#[extern_abi]
fn panic_compare<T>(
_a: *const c_void,
_b: *const c_void,
_type_info: *const sys::ecs_type_info_t,
) -> i32 {
panic!(
"PartialOrd is not implemented for type {} and it's being used in a comparison operation",
core::any::type_name::<T>()
);
}
#[extern_abi]
fn equals<T: core::cmp::PartialEq>(
a: *const c_void,
b: *const c_void,
_type_info: *const sys::ecs_type_info_t,
) -> bool {
ecs_assert!(
check_type_info::<T>(_type_info),
FlecsErrorCode::InternalError
);
let lhs = unsafe { &*(a as *const T) };
let rhs = unsafe { &*(b as *const T) };
lhs == rhs
}
#[extern_abi]
fn panic_equals<T>(
_a: *const c_void,
_b: *const c_void,
_type_info: *const sys::ecs_type_info_t,
) -> bool {
panic!(
"PartialEq is not implemented for type {} and it's being used in an equality operation",
core::any::type_name::<T>()
);
}
fn check_type_info<T>(_type_info: *const sys::ecs_type_info_t) -> bool {
if !_type_info.is_null() {
unsafe { (*_type_info).size == core::mem::size_of::<T>() as i32 }
} else {
true
}
}