use libc::uint32_t;
use libc::c_void;
use std::marker::PhantomData;
use std::mem;
use crate::sys;
use crate::TimerSubsystem;
impl TimerSubsystem {
#[must_use = "if unused the Timer will be dropped immediately"]
pub fn add_timer<'b, 'c>(&'b self, delay: u32, callback: TimerCallback<'c>) -> Timer<'b, 'c> {
unsafe {
let callback = Box::new(callback);
let timer_id = sys::SDL_AddTimer(delay,
Some(c_timer_callback),
mem::transmute_copy(&callback));
Timer {
callback: Some(callback),
raw: timer_id,
_marker: PhantomData
}
}
}
pub fn ticks(&mut self) -> u32 {
unsafe { sys::SDL_GetTicks() }
}
pub fn delay(&mut self, ms: u32) {
unsafe { sys::SDL_Delay(ms) }
}
pub fn performance_counter(&self) -> u64 {
unsafe { sys::SDL_GetPerformanceCounter() }
}
pub fn performance_frequency(&self) -> u64 {
unsafe { sys::SDL_GetPerformanceFrequency() }
}
}
pub type TimerCallback<'a> = Box<FnMut() -> u32+'a+Sync>;
pub struct Timer<'b, 'a> {
callback: Option<Box<TimerCallback<'a>>>,
raw: sys::SDL_TimerID,
_marker: PhantomData<&'b ()>
}
impl<'b, 'a> Timer<'b, 'a> {
pub fn into_inner(mut self) -> TimerCallback<'a> {
*self.callback.take().unwrap()
}
}
impl<'b, 'a> Drop for Timer<'b, 'a> {
#[inline]
fn drop(&mut self) {
unsafe { sys::SDL_RemoveTimer(self.raw) };
}
}
extern "C" fn c_timer_callback(_interval: u32, param: *mut c_void) -> uint32_t {
unsafe {
let f: *mut Box<Fn() -> u32> = mem::transmute(param);
(*f)() as uint32_t
}
}
#[cfg(not(target_os = "macos"))]
#[cfg(test)]
mod test {
use std::sync::{Arc, Mutex};
use std::time::Duration;
#[test]
fn test_timer() {
test_timer_runs_multiple_times();
test_timer_runs_at_least_once();
test_timer_can_be_recreated();
}
fn test_timer_runs_multiple_times() {
let sdl_context = crate::sdl::init().unwrap();
let timer_subsystem = sdl_context.timer().unwrap();
let local_num = Arc::new(Mutex::new(0));
let timer_num = local_num.clone();
let _timer = timer_subsystem.add_timer(20, Box::new(|| {
let mut num = timer_num.lock().unwrap();
if *num < 9 {
*num += 1;
20
} else { 0 }
}));
::std::thread::sleep(Duration::from_millis(250));
let num = local_num.lock().unwrap(); assert_eq!(*num, 9); }
fn test_timer_runs_at_least_once() {
let sdl_context = crate::sdl::init().unwrap();
let timer_subsystem = sdl_context.timer().unwrap();
let local_flag = Arc::new(Mutex::new(false));
let timer_flag = local_flag.clone();
let _timer = timer_subsystem.add_timer(20, Box::new(|| {
let mut flag = timer_flag.lock().unwrap();
*flag = true; 0
}));
::std::thread::sleep(Duration::from_millis(50));
let flag = local_flag.lock().unwrap();
assert_eq!(*flag, true);
}
fn test_timer_can_be_recreated() {
let sdl_context = crate::sdl::init().unwrap();
let timer_subsystem = sdl_context.timer().unwrap();
let local_num = Arc::new(Mutex::new(0));
let timer_num = local_num.clone();
let timer_1 = timer_subsystem.add_timer(20, Box::new(move|| {
let mut num = timer_num.lock().unwrap();
*num += 1; 0 }));
::std::thread::sleep(Duration::from_millis(50));
let closure = timer_1.into_inner();
let _timer_2 = timer_subsystem.add_timer(20, closure);
::std::thread::sleep(Duration::from_millis(50));
let num = local_num.lock().unwrap();
assert_eq!(*num, 2);
}
}