1use std::{ffi::c_void, marker::PhantomData, num::NonZeroU32, ops, ptr::addr_of_mut};
2
3use crate::{bind, Result, Sdl, SdlError};
4
5mod ticks;
6
7pub use ticks::*;
8
9pub trait TimerCallback<'callback>: FnMut() -> u32 + 'callback {}
11
12pub struct Timer<'sdl, T> {
14 id: NonZeroU32,
15 callback: T,
16 _phantom: PhantomData<&'sdl Sdl>,
17}
18
19impl<T> std::fmt::Debug for Timer<'_, T> {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 f.debug_struct("Timer")
22 .field("id", &self.id)
23 .finish_non_exhaustive()
24 }
25}
26
27impl<'sdl, 'callback, T: TimerCallback<'callback>> Timer<'sdl, T> {
28 pub fn new(sdl: &'sdl Sdl, interval: u32, mut callback: T) -> Result<Self> {
36 let ret = unsafe { bind::SDL_InitSubSystem(bind::SDL_INIT_TIMER) };
37 if ret != 0 {
38 Sdl::error_then_panic("Sdl timer");
39 }
40
41 let data = addr_of_mut!(callback);
42 let id =
43 unsafe { bind::SDL_AddTimer(interval, Some(timer_wrap_handler::<T>), data.cast()) };
44 if id == 0 {
45 Err(SdlError::Others { msg: Sdl::error() })
46 } else {
47 Ok(Self {
48 id: unsafe { NonZeroU32::new_unchecked(id as u32) },
49 callback,
50 _phantom: PhantomData,
51 })
52 }
53 }
54}
55
56extern "C" fn timer_wrap_handler<'callback, T: TimerCallback<'callback>>(
57 _: u32,
58 param: *mut c_void,
59) -> u32 {
60 let callback = unsafe { &mut *param.cast::<T>() };
61 callback()
62}
63
64impl<'sdl, T> Drop for Timer<'sdl, T> {
65 fn drop(&mut self) {
66 unsafe {
67 let _ = bind::SDL_RemoveTimer(self.id.get() as bind::SDL_TimerID);
68 bind::SDL_QuitSubSystem(bind::SDL_INIT_TIMER);
69 }
70 }
71}
72
73pub fn delay(ms: u32) {
75 unsafe { bind::SDL_Delay(ms) }
76}
77
78pub mod performance {
80 use crate::bind;
81
82 #[must_use]
84 pub fn counter() -> u64 {
85 unsafe { bind::SDL_GetPerformanceCounter() }
86 }
87
88 #[must_use]
90 pub fn frequency() -> u64 {
91 unsafe { bind::SDL_GetPerformanceFrequency() }
92 }
93}