1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/**
 * adi_clock - Aldaron's Device Interface - Clock - "timer.rs"
 * Copyright 2017 (c) Jeron Lau - Licensed under the MIT LICENSE
**/

use clock::Clock;

#[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))]
mod ffi {
	use Clock;

	type LazyPointer = usize;

	pub struct Timer {
		timeout: f32,
		clock: Clock,
		ticks: f32,
	}

	#[repr(C)]
	#[derive(Copy, Clone)]
	pub struct TimeVal {
		sec: isize,
		usec: isize,
	}

	extern {
		fn nanosleep(req: *const TimeVal, rem: LazyPointer) -> i32;
	}

	impl Timer {
		pub fn create(secs: f32) -> Timer {
			Timer{ timeout:secs, ticks:secs, clock:Clock::create() }
		}

		pub fn wait(&mut self) -> () {
			let passed = self.clock.since();
			let delay = self.ticks - passed;

			if delay > 0.0 {
				let fsec = delay as isize;
				let usec = ((delay % 1.0) * 1_000_000_000.0)
					as isize;
				let timeout = TimeVal { sec: fsec, usec: usec };

				unsafe {
					nanosleep(&timeout, 0);
				}
			}
			self.ticks += self.timeout;
		}
	}
}

#[cfg(target_os = "windows")]
mod ffi {
	type Handle = usize;
	type LazyPointer = usize;
	type Bool = i32;
	type Long = i32;
	type DWord = u32;

	pub struct Timer {
		timer: Handle,
	}

	#[repr(C)]
	pub struct LargeInt {
		a: i64,
		b: i64,
	}
	
	#[link(name = "winmm")]
	#[link(name = "gdi32")]
	extern "system" {
		fn CreateWaitableTimerW(timer_attrib: LazyPointer,
			manual_reset: Bool, name: LazyPointer) -> Handle;
		fn SetWaitableTimer(timer: Handle, due_time: *const LargeInt,
			period: Long, routine: LazyPointer, crarg: LazyPointer,
			resume: Bool) -> Bool;
		fn WaitForSingleObject(timer: Handle, ms: DWord) -> DWord;
		fn CloseHandle(timer: Handle) -> Bool;
	}

	#[cfg(feature = "checks")]
	fn checks(timer: Handle) -> () {
		if timer == 0 {
			panic!("Failed to create Timer.");
		} else {
			println!("Successfully created Timer.");
		}
	}

	#[cfg(not(feature = "checks"))]
	fn checks(_: Handle) {}

	impl Timer {
		pub fn create(secs: f32) -> Timer {
			let timer = unsafe { CreateWaitableTimerW(0, 0, 0) };
			checks(timer);
			let time = (secs * -10000000.0) as i64;
			let millis = (secs * 1000.0) as Long;
			let time = LargeInt { a: time, b: time };
			let r = unsafe { SetWaitableTimer(timer, &time, millis, 0, 0, 0) };
			if r != 1 {
				panic!("Timer: Failed to create.");
			}
			Timer { timer: timer }
		}

		pub fn wait(&self) -> () {
			unsafe { WaitForSingleObject(self.timer, 0xffffffff); }
		}
	}
	
	impl Drop for Timer {
		fn drop(&mut self) {
			unsafe { CloseHandle(self.timer); }
		}
	}
}

/// Timer represents a High Precision Event Timer (HPET) or equivalent device.
/// It is used for precise sleeping.
pub struct Timer {
	timer: ffi::Timer,
	clock: Clock,
}

impl Timer {
	/// Create a new repeating timer with an interval of secs seconds.
	pub fn create(secs: f32) -> Timer {
		Timer{ timer: ffi::Timer::create(secs), clock: Clock::create() }
	}

	/// Wait until timer self goes off. Returns the number of seconds since
	/// self was initialized (or since Timer::new() was called).
	pub fn wait(&mut self) -> f32 {
		self.timer.wait();
		self.clock.since()
	}

	/// Sleep (wait) for secs seconds. Returns the number of seconds passed
	/// while sleeping.
	pub fn sleep(secs: f32) -> f32 {
		Timer::create(secs).wait()
	}
}