use ::alloc::boxed::Box;
use ::core::{ffi::c_void, ptr::NonNull, time::Duration};
use bevy_ecs::{
component::Component,
schedule::{IntoScheduleConfigs, Schedule},
system::ScheduleSystem,
world::World,
};
use lightvgl_sys::lv_timer_t;
use crate::info;
#[allow(dead_code)]
#[derive(Component)]
#[component(storage = "SparseSet")]
pub struct Timer {
raw: NonNull<lv_timer_t>,
schedule: Schedule,
}
impl Drop for Timer {
fn drop(&mut self) {
unsafe {
info!("Dropping Timer");
lightvgl_sys::lv_timer_delete(self.raw.as_ptr());
}
}
}
unsafe impl Send for Timer {}
unsafe impl Sync for Timer {}
impl Timer {
pub fn new(world: &mut World, period: Duration) -> Option<Self> {
let mut schedule = Schedule::default();
unsafe {
let timer = lightvgl_sys::lv_timer_create(
Some(timer_trampoline),
period.as_millis() as u32,
Box::into_raw(Box::new((&mut schedule, world))) as *mut _,
);
let ptr = NonNull::new(timer);
Some(Self {
raw: ptr?,
schedule,
})
}
}
pub fn add_systems<M>(&mut self, system: impl IntoScheduleConfigs<ScheduleSystem, M>) {
self.schedule.add_systems(system);
}
}
unsafe extern "C" fn timer_trampoline(timer: *mut lv_timer_t) {
unsafe {
let (schedule, world) = &mut *((*timer).user_data as *mut (&mut Schedule, &mut World));
schedule.run(world);
}
}
pub(crate) fn lv_async_call<F>(callback: F)
where
F: FnMut() + 'static,
{
unsafe {
lightvgl_sys::lv_async_call(
Some(async_call_trampoline::<F>),
Box::into_raw(Box::new(callback)) as *mut _,
);
}
}
unsafe extern "C" fn async_call_trampoline<F>(obj: *mut c_void)
where
F: FnMut() + 'static,
{
unsafe {
let callback = &mut *((obj) as *mut F);
callback();
}
}
static mut TICK_CALLBACK: Option<Box<dyn FnMut() -> u32>> = None;
pub(crate) fn lv_tick_set_cb<F>(callback: F)
where
F: FnMut() -> u32 + 'static,
{
unsafe {
TICK_CALLBACK = Some(Box::new(callback));
lightvgl_sys::lv_tick_set_cb(Some(tick_callback_trampoline));
}
}
#[allow(static_mut_refs)]
unsafe extern "C" fn tick_callback_trampoline() -> u32 {
unsafe { (*TICK_CALLBACK.as_mut().unwrap())() }
}