use std::collections::HashMap;
use std::sync::Mutex;
use std::time::Duration;
type TimerId = i64;
lazy_static! {
static ref TIMERS_INSTANCES: Mutex<HashMap<TimerId, TimerInstance>> =
Mutex::new(HashMap::new());
}
static mut TIMERS_ID: TimerId = 0;
#[derive(Clone)]
pub struct Timer {
id: TimerId,
}
#[allow(dead_code)]
impl Timer {
pub fn new(expiration_time: u64, start_active: bool) -> Timer {
unsafe {
TIMERS_ID += 1;
}
let timer = TimerInstance::new(expiration_time, start_active, unsafe { TIMERS_ID });
unsafe {
TIMERS_INSTANCES.lock().unwrap().insert(TIMERS_ID, timer);
}
Timer {
id: unsafe { TIMERS_ID },
}
}
pub fn reset(&self) {
TIMERS_INSTANCES
.lock()
.unwrap()
.get_mut(&self.id)
.unwrap()
.reset();
}
pub fn set_time(&self, expiration_time: u64, start_active: bool) {
TIMERS_INSTANCES
.lock()
.unwrap()
.get_mut(&self.id)
.unwrap()
.set_time(expiration_time, start_active);
}
pub fn active(&self) -> bool {
TIMERS_INSTANCES
.lock()
.unwrap()
.get(&self.id)
.unwrap()
.active()
}
pub fn expired(&self) -> bool {
TIMERS_INSTANCES
.lock()
.unwrap()
.get(&self.id)
.unwrap()
.expired()
}
pub fn elapsed(&self) -> Duration {
TIMERS_INSTANCES
.lock()
.unwrap()
.get(&self.id)
.unwrap()
.elapsed()
}
pub fn elapsed_as_millis(&self) -> u64 {
TIMERS_INSTANCES
.lock()
.unwrap()
.get(&self.id)
.unwrap()
.elapsed_as_millis()
}
}
impl Drop for Timer {
fn drop(&mut self) {
TIMERS_INSTANCES
.lock()
.unwrap()
.retain(|&t, _| t != self.id);
}
}
struct TimerInstance {
current_time: u64,
expiration_time: u64,
endless: bool,
pub id: TimerId,
}
#[allow(dead_code)]
impl TimerInstance {
pub fn new(expiration_time: u64, start_active: bool, id: TimerId) -> TimerInstance {
TimerInstance {
current_time: if start_active { 0 } else { expiration_time },
expiration_time,
endless: expiration_time == 0,
id,
}
}
pub fn reset(&mut self) {
self.current_time = 0;
}
pub fn set_time(&mut self, expiration_time: u64, start_active: bool) {
self.current_time = if start_active { 0 } else { expiration_time };
self.expiration_time = expiration_time;
self.endless = expiration_time == 0;
}
pub fn active(&self) -> bool {
if !self.endless {
return self.current_time < self.expiration_time;
}
true
}
pub fn expired(&self) -> bool {
!self.active()
}
pub fn elapsed(&self) -> Duration {
Duration::from_millis(self.elapsed_as_millis())
}
pub fn elapsed_as_millis(&self) -> u64 {
self.current_time
}
pub fn is_endless(&self) -> bool {
self.endless
}
pub fn set_endless(&mut self, endless: bool) {
self.endless = endless;
}
pub fn update(&mut self, elapsed_time: f64) {
let elapsed_time = (elapsed_time * 1000.0) as u64;
if self.active() {
self.current_time += elapsed_time;
} else {
self.current_time = self.expiration_time;
}
}
}
pub(crate) fn update_all(elapsed_time: f64) {
for timer in TIMERS_INSTANCES.lock().unwrap().values_mut() {
timer.update(elapsed_time);
}
}