use core::ffi::CStr;
use flecs_ecs::core::*;
use flecs_ecs::sys;
#[cfg(feature = "std")]
extern crate std;
extern crate alloc;
use alloc::{borrow::ToOwned, string::String};
#[repr(C)]
pub struct Script<'a> {
script: *mut sys::ecs_script_t,
ast: *mut core::ffi::c_char,
_phantom: core::marker::PhantomData<&'a ()>,
}
impl Drop for Script<'_> {
fn drop(&mut self) {
if !self.ast.is_null() {
unsafe {
sys::ecs_os_api.free_.expect("os api is missing")(
self.ast as *mut core::ffi::c_void,
);
}
}
if !self.script.is_null() {
unsafe { sys::ecs_script_free(self.script) }
}
}
}
impl<'a> Script<'a> {
pub fn parse(
world: impl WorldProvider<'a>,
name: &str,
code: &str,
desc: Option<sys::ecs_script_eval_desc_t>,
) -> Option<Script<'a>> {
let name = compact_str::format_compact!("{}\0", name);
let code = compact_str::format_compact!("{}\0", code);
let world_ptr = world.world_ptr_mut();
let ptr = unsafe {
if let Some(desc) = desc {
sys::ecs_script_parse(
world_ptr,
name.as_ptr() as *const _,
code.as_ptr() as *const _,
&desc,
core::ptr::null_mut(),
)
} else {
sys::ecs_script_parse(
world_ptr,
name.as_ptr() as *const _,
code.as_ptr() as *const _,
core::ptr::null(),
core::ptr::null_mut(),
)
}
};
if ptr.is_null() {
None
} else {
Some(Script {
script: ptr,
ast: core::ptr::null_mut(),
_phantom: core::marker::PhantomData::<&'a ()>,
})
}
}
pub fn eval(&self, desc: Option<sys::ecs_script_eval_desc_t>) -> bool {
if let Some(desc) = desc {
unsafe { sys::ecs_script_eval(self.script, &desc, core::ptr::null_mut()) == 0 }
} else {
unsafe {
sys::ecs_script_eval(self.script, core::ptr::null(), core::ptr::null_mut()) == 0
}
}
}
pub fn destroy(self) {
}
pub fn run_code(world: impl WorldProvider<'a>, name: &str, code: &str) -> bool {
let name = compact_str::format_compact!("{}\0", name);
let code = compact_str::format_compact!("{}\0", code);
let world_ptr = world.world_ptr_mut();
unsafe {
sys::ecs_script_run(
world_ptr,
name.as_ptr() as *const _,
code.as_ptr() as *const _,
core::ptr::null_mut(),
) == 0
}
}
pub fn run_file(world: impl WorldProvider<'a>, filename: &str) -> bool {
let filename = compact_str::format_compact!("{}\0", filename);
let world_ptr = world.world_ptr_mut();
unsafe { sys::ecs_script_run_file(world_ptr, filename.as_ptr() as *const _) == 0 }
}
pub fn ast(&mut self) -> Option<String> {
let ast = unsafe { sys::ecs_script_ast_to_str(self.script, false) };
if !ast.is_null() {
if self.ast.is_null() {
self.ast = ast;
} else {
ecs_assert!(
false,
FlecsErrorCode::InvalidOperation,
"Script AST already exists"
);
unsafe {
sys::ecs_os_api.free_.expect("os api is missing")(
ast as *mut core::ffi::c_void,
);
}
}
let c_str = unsafe { CStr::from_ptr(ast) };
let str = c_str.to_str().unwrap().to_owned();
unsafe {
sys::ecs_os_api.free_.expect("os api is missing")(ast as *mut core::ffi::c_void);
};
Some(str)
} else {
None
}
}
pub unsafe fn to_expr<T: IntoEntity>(
world: impl WorldProvider<'a>,
id_of_value: T,
value: *const T::CastType,
) -> String {
let world = world.world();
let id = *id_of_value.into_entity(world);
let world = world.world_ptr_mut();
let expr = unsafe { sys::ecs_ptr_to_expr(world, id, value as *const core::ffi::c_void) };
let c_str = unsafe { CStr::from_ptr(expr) };
let str = c_str.to_str().unwrap().to_owned();
unsafe {
sys::ecs_os_api.free_.expect("os api is missing")(expr as *mut core::ffi::c_void);
};
str
}
pub fn get_const_var(world: impl WorldProvider<'a>, name: &str) -> Option<sys::ecs_value_t> {
let world_ptr = world.world_ptr();
let name = compact_str::format_compact!("{}\0", name);
let v = unsafe {
sys::ecs_lookup_path_w_sep(
world_ptr,
0,
name.as_ptr() as *const _,
SEPARATOR.as_ptr(),
SEPARATOR.as_ptr(),
false,
)
};
if v == 0 {
None
} else {
let value = unsafe { sys::ecs_const_var_get(world_ptr, v) };
if value.ptr.is_null() {
None
} else {
Some(value)
}
}
}
pub fn get_const_numeric<T: ConstNumeric>(
world: impl WorldProvider<'a>,
value: sys::ecs_value_t,
) -> T::ConstType {
let world_ptr = world.world_ptr();
let cur = unsafe { sys::ecs_meta_cursor(world_ptr, value.type_, value.ptr) };
if T::IS_INT {
let cur_value = unsafe { sys::ecs_meta_get_int(&cur) };
unsafe { *(&cur_value as *const i64 as *const T::ConstType) }
} else if T::IS_UINT {
let cur_value = unsafe { sys::ecs_meta_get_uint(&cur) };
unsafe { *(&cur_value as *const u64 as *const T::ConstType) }
} else
{
let cur_value = unsafe { sys::ecs_meta_get_float(&cur) };
unsafe { *(&cur_value as *const f64 as *const T::ConstType) }
}
}
pub fn get_const_char(
world: impl WorldProvider<'a>,
value: sys::ecs_value_t,
) -> core::ffi::c_char {
let world_ptr = world.world_ptr();
let cur = unsafe { sys::ecs_meta_cursor(world_ptr, value.type_, value.ptr) };
let cur_value = unsafe { sys::ecs_meta_get_char(&cur) };
cur_value as core::ffi::c_char
}
pub fn get_const_str(world: impl WorldProvider<'a>, value: sys::ecs_value_t) -> String {
let world_ptr = world.world_ptr();
let cur = unsafe { sys::ecs_meta_cursor(world_ptr, value.type_, value.ptr) };
let c_str = unsafe { sys::ecs_meta_get_string(&cur) };
unsafe { CStr::from_ptr(c_str) }
.to_str()
.unwrap()
.to_owned()
}
}
pub trait ConstNumeric: Sized {
type ConstType: Sized + Copy;
const IS_INT: bool;
const IS_UINT: bool;
const IS_FLOAT: bool;
}
impl ConstNumeric for i8 {
type ConstType = i8;
const IS_INT: bool = true;
const IS_UINT: bool = false;
const IS_FLOAT: bool = false;
}
impl ConstNumeric for i16 {
type ConstType = i16;
const IS_INT: bool = true;
const IS_UINT: bool = false;
const IS_FLOAT: bool = false;
}
impl ConstNumeric for i32 {
type ConstType = i32;
const IS_INT: bool = true;
const IS_UINT: bool = false;
const IS_FLOAT: bool = false;
}
impl ConstNumeric for i64 {
type ConstType = i64;
const IS_INT: bool = true;
const IS_UINT: bool = false;
const IS_FLOAT: bool = false;
}
impl ConstNumeric for u8 {
type ConstType = u8;
const IS_INT: bool = false;
const IS_UINT: bool = true;
const IS_FLOAT: bool = false;
}
impl ConstNumeric for u16 {
type ConstType = u16;
const IS_INT: bool = false;
const IS_UINT: bool = true;
const IS_FLOAT: bool = false;
}
impl ConstNumeric for u32 {
type ConstType = u32;
const IS_INT: bool = false;
const IS_UINT: bool = true;
const IS_FLOAT: bool = false;
}
impl ConstNumeric for u64 {
type ConstType = u64;
const IS_INT: bool = false;
const IS_UINT: bool = true;
const IS_FLOAT: bool = false;
}
impl ConstNumeric for f32 {
type ConstType = f32;
const IS_INT: bool = false;
const IS_UINT: bool = false;
const IS_FLOAT: bool = true;
}
impl ConstNumeric for f64 {
type ConstType = f64;
const IS_INT: bool = false;
const IS_UINT: bool = false;
const IS_FLOAT: bool = true;
}