oxedyne/fe2o3/fe2o3_core/src/time.rs
3.1 KiB, 26 runs
created by r1870400018:126, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | use crate::{ |
| 2 | prelude::*, |
| 3 | }; |
| 4 | |
| 5 | use std::time::Duration; |
| 6 | #[cfg(not(target_arch = "wasm32"))] |
| 7 | use std::{ |
| 8 | time::Instant, |
| 9 | thread, |
| 10 | }; |
| 11 | |
| 12 | /// Waits for the given boolean function to become true, or for the maximum duration to be reached. |
| 13 | /// Returns the starting `Instant` and whether the operation timed out. Returns an error if the |
| 14 | /// given `Duration`s are inconsistent. |
| 15 | #[cfg(not(target_arch = "wasm32"))] |
| 16 | pub fn wait_for_true( |
| 17 | check_interval: Duration, |
| 18 | max_wait: Duration, |
| 19 | fn_true: impl Fn() -> bool, |
| 20 | ) |
| 21 | -> Outcome<(Instant, bool)> |
| 22 | { |
| 23 | if check_interval > max_wait { |
| 24 | return Err(err!( |
| 25 | "The given check interval, {:?}, should not be larger than the \ |
| 26 | given max wait, {:?}.", check_interval, max_wait; |
| 27 | Invalid, Input)); |
| 28 | } |
| 29 | let start = Instant::now(); |
| 30 | loop { |
| 31 | if fn_true() { |
| 32 | return Ok((start, false)); |
| 33 | } else { |
| 34 | thread::sleep(check_interval); |
| 35 | } |
| 36 | if start.elapsed() > max_wait { |
| 37 | return Ok((start, true)); |
| 38 | } |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | #[cfg(target_arch = "wasm32")] |
| 43 | pub fn wait_for_true( |
| 44 | _check_interval: Duration, |
| 45 | _max_wait: Duration, |
| 46 | _fn_true: impl Fn() -> bool, |
| 47 | ) |
| 48 | -> Outcome<(std::time::Instant, bool)> |
| 49 | { |
| 50 | Err(err!( |
| 51 | "wait_for_true blocks the calling thread and is unavailable on the \ |
| 52 | wasm32 target; use an asynchronous wait instead."; |
| 53 | Unimplemented)) |
| 54 | } |
| 55 | |
| 56 | /// A simple system clock stopwatch. |
| 57 | #[derive(Debug, PartialEq, Copy, Clone)] |
| 58 | pub struct Timer { |
| 59 | #[cfg(not(target_arch = "wasm32"))] |
| 60 | t0: Instant, |
| 61 | #[cfg(target_arch = "wasm32")] |
| 62 | t0: f64, |
| 63 | last: usize, |
| 64 | } |
| 65 | |
| 66 | impl Timer { |
| 67 | #[cfg(not(target_arch = "wasm32"))] |
| 68 | pub fn new() -> Self { |
| 69 | Self { |
| 70 | t0: Instant::now(), |
| 71 | last: 0, |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | #[cfg(target_arch = "wasm32")] |
| 76 | pub fn new() -> Self { |
| 77 | Self { |
| 78 | t0: crate::wasm::now_ms(), |
| 79 | last: 0, |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | #[cfg(not(target_arch = "wasm32"))] |
| 84 | pub fn reset(&mut self) { |
| 85 | self.t0 = Instant::now(); |
| 86 | self.last = 0; |
| 87 | } |
| 88 | |
| 89 | #[cfg(target_arch = "wasm32")] |
| 90 | pub fn reset(&mut self) { |
| 91 | self.t0 = crate::wasm::now_ms(); |
| 92 | self.last = 0; |
| 93 | } |
| 94 | |
| 95 | #[cfg(not(target_arch = "wasm32"))] |
| 96 | pub fn split_micros(&mut self) -> Outcome<usize> { |
| 97 | self.last = try_sub!(self.t0.elapsed().as_micros() as usize, self.last); |
| 98 | Ok(self.last) |
| 99 | } |
| 100 | |
| 101 | #[cfg(target_arch = "wasm32")] |
| 102 | pub fn split_micros(&mut self) -> Outcome<usize> { |
| 103 | let elapsed = ((crate::wasm::now_ms() - self.t0) * 1_000.0) as usize; |
| 104 | self.last = try_sub!(elapsed, self.last); |
| 105 | Ok(self.last) |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | #[cfg(test)] |
| 110 | mod tests { |
| 111 | use super::*; |
| 112 | use std::thread::sleep; |
| 113 | |
| 114 | #[test] |
| 115 | fn test_timer() -> Outcome<()> { |
| 116 | let mut t0 = Timer::new(); |
| 117 | sleep(Duration::from_micros(1000)); |
| 118 | let mut t = res!(t0.split_micros()); |
| 119 | msg!("timer split: {}", t); |
| 120 | sleep(Duration::from_micros(2000)); |
| 121 | t = res!(t0.split_micros()); |
| 122 | msg!("timer split: {}", t); |
| 123 | Ok(()) |
| 124 | } |
| 125 | } |