1use crate::sys;
2use libc::c_void;
3use std::marker::PhantomData;
4use std::panic::catch_unwind;
5use std::process::abort;
6
7use crate::TimerSubsystem;
8
9impl TimerSubsystem {
10 #[must_use = "if unused the Timer will be dropped immediately"]
20 #[doc(alias = "SDL_AddTimer")]
21 pub fn add_timer(&self, delay: u32, callback: TimerCallback) -> Timer<'_> {
22 unsafe {
23 let mut callback = Box::new(callback);
24 let timer_id = sys::SDL_AddTimer(
25 delay,
26 Some(c_timer_callback),
27 &mut *callback as *mut TimerCallback as *mut c_void,
28 );
29
30 Timer {
31 callback: Some(callback),
32 raw: timer_id,
33 _marker: PhantomData,
34 }
35 }
36 }
37
38 #[doc(alias = "SDL_GetTicks")]
45 pub fn ticks(&self) -> u32 {
46 unsafe { sys::SDL_GetTicks() }
53 }
54
55 #[doc(alias = "SDL_GetTicks64")]
59 pub fn ticks64(&self) -> u64 {
60 unsafe { sys::SDL_GetTicks64() }
67 }
68
69 #[doc(alias = "SDL_Delay")]
73 pub fn delay(&self, ms: u32) {
74 unsafe { sys::SDL_Delay(ms) }
81 }
82
83 #[doc(alias = "SDL_GetPerformanceCounter")]
84 pub fn performance_counter(&self) -> u64 {
85 unsafe { sys::SDL_GetPerformanceCounter() }
86 }
87
88 #[doc(alias = "SDL_GetPerformanceFrequency")]
89 pub fn performance_frequency(&self) -> u64 {
90 unsafe { sys::SDL_GetPerformanceFrequency() }
91 }
92}
93
94pub type TimerCallback = Box<dyn FnMut() -> u32 + 'static + Send>;
95
96pub struct Timer<'a> {
97 callback: Option<Box<TimerCallback>>,
98 raw: sys::SDL_TimerID,
99 _marker: PhantomData<&'a ()>,
100}
101
102impl<'a> Timer<'a> {
103 pub fn into_inner(mut self) -> TimerCallback {
106 *self.callback.take().unwrap()
107 }
108}
109
110impl<'a> Drop for Timer<'a> {
111 #[inline]
112 #[doc(alias = "SDL_RemoveTimer")]
113 fn drop(&mut self) {
114 unsafe { sys::SDL_RemoveTimer(self.raw) };
118 }
119}
120
121unsafe extern "C" fn c_timer_callback(_interval: u32, param: *mut c_void) -> u32 {
122 match catch_unwind(|| {
123 let f = param.cast::<TimerCallback>();
124 unsafe { (*f)() }
125 }) {
126 Ok(ret) => ret,
127 Err(_) => abort(),
128 }
129}
130
131#[cfg(not(target_os = "macos"))]
132#[cfg(test)]
133mod test {
134 use std::sync::{Arc, Mutex};
135 use std::time::Duration;
136
137 #[test]
138 fn test_timer() {
139 test_timer_runs_multiple_times();
140 test_timer_runs_at_least_once();
141 test_timer_can_be_recreated();
142 }
143
144 fn test_timer_runs_multiple_times() {
145 let sdl_context = crate::sdl::init().unwrap();
146 let timer_subsystem = sdl_context.timer().unwrap();
147
148 let local_num = Arc::new(Mutex::new(0));
149 let timer_num = local_num.clone();
150
151 let _timer = timer_subsystem.add_timer(
152 20,
153 Box::new(move || {
154 let mut num = timer_num.lock().unwrap();
158 if *num < 9 {
159 *num += 1;
160 20
161 } else {
162 0
163 }
164 }),
165 );
166
167 ::std::thread::sleep(Duration::from_millis(250));
169 let num = local_num.lock().unwrap(); assert_eq!(*num, 9); }
172
173 fn test_timer_runs_at_least_once() {
174 let sdl_context = crate::sdl::init().unwrap();
175 let timer_subsystem = sdl_context.timer().unwrap();
176
177 let local_flag = Arc::new(Mutex::new(false));
178 let timer_flag = local_flag.clone();
179
180 let _timer = timer_subsystem.add_timer(
181 20,
182 Box::new(move || {
183 let mut flag = timer_flag.lock().unwrap();
184 *flag = true;
185 0
186 }),
187 );
188
189 ::std::thread::sleep(Duration::from_millis(50));
190 let flag = local_flag.lock().unwrap();
191 assert!(*flag);
192 }
193
194 fn test_timer_can_be_recreated() {
195 let sdl_context = crate::sdl::init().unwrap();
196 let timer_subsystem = sdl_context.timer().unwrap();
197
198 let local_num = Arc::new(Mutex::new(0));
199 let timer_num = local_num.clone();
200
201 let timer_1 = timer_subsystem.add_timer(
203 20,
204 Box::new(move || {
205 let mut num = timer_num.lock().unwrap();
206 *num += 1; 0 }),
209 );
210
211 ::std::thread::sleep(Duration::from_millis(50));
213 let closure = timer_1.into_inner();
214
215 let _timer_2 = timer_subsystem.add_timer(20, closure);
217 ::std::thread::sleep(Duration::from_millis(50));
218
219 let num = local_num.lock().unwrap();
221 assert_eq!(*num, 2);
222 }
223}