#![deny(missing_docs, unsafe_code)]
#[cfg(not(feature = "f64"))]
pub type Seconds = f32;
#[cfg(feature = "f64")]
pub type Seconds = f64;
use std::time::{Duration, Instant};
pub trait ToDuration {
fn to_duration(&self) -> Duration;
}
impl ToDuration for Duration {
fn to_duration(&self) -> Duration {
*self
}
}
impl ToDuration for f32 {
fn to_duration(&self) -> Duration {
if self < &0.0 {
panic!("Attempted to convert negative f32 number to Duration");
}
let whole = *self as u64;
let fract = (self.fract() * 1e9) as u32;
Duration::new(whole, fract)
}
}
impl ToDuration for f64 {
fn to_duration(&self) -> Duration {
if self < &0.0 {
panic!("Attempted to convert negative f64 number to Duration");
}
let whole = *self as u64;
let fract = (self.fract() * 1e9) as u32;
Duration::new(whole, fract)
}
}
impl ToDuration for u8 {
fn to_duration(&self) -> Duration {
Duration::new(u64::from(*self), 0)
}
}
impl ToDuration for u16 {
fn to_duration(&self) -> Duration {
Duration::new(u64::from(*self), 0)
}
}
impl ToDuration for u32 {
fn to_duration(&self) -> Duration {
Duration::new(u64::from(*self), 0)
}
}
impl ToDuration for u64 {
fn to_duration(&self) -> Duration {
Duration::new(*self, 0)
}
}
impl ToDuration for u128 {
fn to_duration(&self) -> Duration {
Duration::new(*self as u64, 0)
}
}
impl ToDuration for usize {
fn to_duration(&self) -> Duration {
Duration::new(*self as u64, 0)
}
}
pub trait FromDuration {
fn from_duration(duration: Duration) -> Self;
}
impl FromDuration for Duration {
fn from_duration(duration: Duration) -> Self {
duration
}
}
impl FromDuration for u64 {
fn from_duration(duration: Duration) -> Self {
duration.as_secs()
}
}
impl FromDuration for u128 {
fn from_duration(duration: Duration) -> Self {
u128::from(duration.as_secs())
}
}
impl FromDuration for usize {
fn from_duration(duration: Duration) -> Self {
duration.as_secs() as usize
}
}
impl FromDuration for f32 {
fn from_duration(duration: Duration) -> Self {
duration.as_secs() as f32 + duration.subsec_nanos() as f32 / 1e9
}
}
impl FromDuration for f64 {
fn from_duration(duration: Duration) -> Self {
duration.as_secs() as f64 + f64::from(duration.subsec_nanos()) / 1e9
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Elapsed {
start: Instant,
}
impl Elapsed {
pub fn start() -> Elapsed {
Elapsed {
start: Instant::now(),
}
}
pub fn reset(&mut self) {
self.start = Instant::now();
}
pub fn seconds(self) -> Seconds {
Seconds::from_duration(self.duration())
}
pub fn duration(self) -> Duration {
Instant::now().duration_since(self.start)
}
pub fn started_at(self) -> Instant {
self.start
}
}
impl Default for Elapsed {
fn default() -> Self {
Elapsed::start()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Timer {
elapsed: Elapsed,
duration: Duration,
}
impl Timer {
pub fn set<D: ToDuration>(time: D) -> Timer {
Timer {
elapsed: Elapsed::start(),
duration: time.to_duration(),
}
}
pub fn reset(&mut self) {
self.elapsed = Elapsed::start();
}
pub fn duration_left(&self) -> Option<Duration> {
self.duration.checked_sub(self.elapsed.duration())
}
pub fn seconds_left(&self) -> Seconds {
Seconds::from_duration(self.duration) - self.elapsed.seconds()
}
pub fn is_ready(self) -> bool {
self.duration_left().is_none()
}
pub fn as_ready(self) -> Option<Seconds> {
if self.is_ready() {
Some(self.seconds())
} else {
None
}
}
pub fn max_duration(&self) -> Duration {
self.duration
}
pub fn max_seconds(&self) -> Seconds {
Seconds::from_duration(self.max_duration())
}
pub fn seconds(&self) -> Seconds {
self.elapsed.seconds()
}
pub fn duration(&self) -> Duration {
self.elapsed.duration()
}
pub fn started_at(&self) -> Instant {
self.elapsed.started_at()
}
pub fn ends_at(&self) -> Instant {
self.elapsed.started_at() + self.duration
}
pub fn tick<F, R>(&mut self, mut f: F) -> Option<R>
where
F: FnMut(Seconds) -> R,
{
self.as_ready().map(|dt| {
self.reset();
f(dt)
})
}
}
impl Default for Timer {
fn default() -> Self {
Timer::set(0.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Stopwatch {
last_start: Instant,
prev_dur: Duration,
paused: bool,
}
impl Stopwatch {
pub fn start() -> Stopwatch {
Stopwatch {
last_start: Instant::now(),
prev_dur: 0u64.to_duration(),
paused: false,
}
}
pub fn start_paused() -> Stopwatch {
Stopwatch {
last_start: Instant::now(),
prev_dur: 0u64.to_duration(),
paused: true,
}
}
pub fn reset(&mut self) {
self.last_start = Instant::now();
self.prev_dur = 0u64.to_duration();
}
pub fn seconds(&self) -> Seconds {
Seconds::from_duration(self.duration())
}
pub fn duration(&self) -> Duration {
if self.paused {
self.prev_dur
} else {
self.prev_dur + Instant::now().duration_since(self.last_start)
}
}
pub fn pause(&mut self) {
if !self.paused {
self.prev_dur += Instant::now().duration_since(self.last_start);
}
}
pub fn resume(&mut self) {
if self.paused {
self.last_start = Instant::now();
}
}
pub fn toggle(&mut self) {
if self.paused {
self.pause();
} else {
self.resume();
}
}
pub fn started_at(&self) -> Instant {
self.last_start
}
}
impl Default for Stopwatch {
fn default() -> Self {
Stopwatch::start()
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Default)]
pub struct TimedList<T> {
list: Vec<(Timer, T)>,
}
impl<T> TimedList<T> {
pub fn new() -> TimedList<T> {
TimedList { list: Vec::new() }
}
pub fn insert<D: ToDuration>(&mut self, element: T, time: D) {
self.list.push((Timer::set(time), element));
}
pub fn clean(&mut self) {
self.list.retain(|(timer, _)| !timer.is_ready());
}
pub fn clear(&mut self) {
self.list.clear();
}
pub fn len(&self) -> usize {
self.iter().count()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool,
{
self.list.retain(|(_, elem)| f(elem));
}
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> {
self.list.iter().filter_map(
|(timer, elem)| {
if timer.is_ready() {
None
} else {
Some(elem)
}
},
)
}
pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut T> {
self.clean();
self.list.iter_mut().filter_map(
|(timer, elem)| {
if timer.is_ready() {
None
} else {
Some(elem)
}
},
)
}
pub fn timer_iter(&self) -> impl DoubleEndedIterator<Item = (&T, Timer)> {
self.list.iter().filter_map(|(timer, elem)| {
if timer.is_ready() {
None
} else {
Some((elem, *timer))
}
})
}
pub fn timer_iter_mut(&mut self) -> impl DoubleEndedIterator<Item = (&mut T, Timer)> {
self.clean();
self.list.iter_mut().filter_map(|(timer, elem)| {
if timer.is_ready() {
None
} else {
Some((elem, *timer))
}
})
}
}
impl<T, D> std::iter::FromIterator<(T, D)> for TimedList<T>
where
D: ToDuration,
{
fn from_iter<I: IntoIterator<Item = (T, D)>>(iter: I) -> Self {
TimedList {
list: iter.into_iter().map(|(x, d)| (Timer::set(d), x)).collect(),
}
}
}
impl<T> IntoIterator for TimedList<T>
where
T: 'static,
{
type Item = T;
type IntoIter = Box<dyn DoubleEndedIterator<Item = T>>;
fn into_iter(mut self) -> Self::IntoIter {
self.clean();
Box::new(self.list.into_iter().filter_map(
|(timer, elem)| {
if timer.is_ready() {
None
} else {
Some(elem)
}
},
))
}
}
pub fn measure<F>(f: F) -> Seconds
where
F: FnOnce(),
{
let timer = Elapsed::start();
f();
timer.seconds()
}