use std::{ffi::c_void, marker::PhantomData, num::NonZeroU32, ops, ptr::addr_of_mut};
use crate::{bind, Result, Sdl, SdlError};
mod ticks;
pub use ticks::*;
pub trait TimerCallback<'callback>: FnMut() -> u32 + 'callback {}
pub struct Timer<'sdl, T> {
id: NonZeroU32,
callback: T,
_phantom: PhantomData<&'sdl Sdl>,
}
impl<T> std::fmt::Debug for Timer<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Timer")
.field("id", &self.id)
.finish_non_exhaustive()
}
}
impl<'sdl, 'callback, T: TimerCallback<'callback>> Timer<'sdl, T> {
pub fn new(sdl: &'sdl Sdl, interval: u32, mut callback: T) -> Result<Self> {
let ret = unsafe { bind::SDL_InitSubSystem(bind::SDL_INIT_TIMER) };
if ret != 0 {
Sdl::error_then_panic("Sdl timer");
}
let data = addr_of_mut!(callback);
let id =
unsafe { bind::SDL_AddTimer(interval, Some(timer_wrap_handler::<T>), data.cast()) };
if id == 0 {
Err(SdlError::Others { msg: Sdl::error() })
} else {
Ok(Self {
id: unsafe { NonZeroU32::new_unchecked(id as u32) },
callback,
_phantom: PhantomData,
})
}
}
}
extern "C" fn timer_wrap_handler<'callback, T: TimerCallback<'callback>>(
_: u32,
param: *mut c_void,
) -> u32 {
let callback = unsafe { &mut *param.cast::<T>() };
callback()
}
impl<'sdl, T> Drop for Timer<'sdl, T> {
fn drop(&mut self) {
unsafe {
let _ = bind::SDL_RemoveTimer(self.id.get() as bind::SDL_TimerID);
bind::SDL_QuitSubSystem(bind::SDL_INIT_TIMER);
}
}
}
pub fn delay(ms: u32) {
unsafe { bind::SDL_Delay(ms) }
}
pub mod performance {
use crate::bind;
#[must_use]
pub fn counter() -> u64 {
unsafe { bind::SDL_GetPerformanceCounter() }
}
#[must_use]
pub fn frequency() -> u64 {
unsafe { bind::SDL_GetPerformanceFrequency() }
}
}