diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..b2802bc --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:20.04 + +WORKDIR /home/ + +COPY . . + +RUN bash ./setup.sh + +ENV PATH="/root/.cargo/bin:$PATH" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..bb121aa --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,18 @@ +{ + "name": "rust-stopwatch", + "extensions": [ + "matklad.rust-analyzer", + "bungcip.better-toml" + ], + "dockerFile": "Dockerfile", + "containerEnv": { + "GIT_EDITOR": "code --wait" + }, + "onCreateCommand": "cargo build", + "settings": { + "editor.formatOnSave": true, + "files.exclude": { + "**/LICENSE.txt": true + } + } +} \ No newline at end of file diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh new file mode 100755 index 0000000..3d9a06e --- /dev/null +++ b/.devcontainer/setup.sh @@ -0,0 +1,13 @@ +apt-get update +apt-get install -y \ + curl \ + git \ + gnupg2 \ + jq \ + sudo \ + build-essential \ + openssl + +curl https://sh.rustup.rs -sSf | sh -s -- -y +source "$HOME/.cargo/env" +rustup component add clippy rustfmt diff --git a/Cargo.toml b/Cargo.toml index 3bd1a72..9a84a0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] - name = "stopwatch" version = "0.0.7" +edition = "2021" authors = ["Chucky Ellison "] description = "A stopwatch library for timing things." @@ -11,4 +11,4 @@ keywords = ["stopwatch", "timing"] license = "MIT" [dependencies] -num = "0.1.32" +num-traits = "0.2.15" diff --git a/src/lib.rs b/src/lib.rs index fc7fcc3..821c50b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,118 +4,113 @@ use std::time::{Duration, Instant}; #[derive(Clone, Copy)] pub struct Stopwatch { - /// The time the stopwatch was started last, if ever. - start_time: Option, - /// The time the stopwatch was split last, if ever. - split_time: Option, - /// The time elapsed while the stopwatch was running (between start() and stop()). - elapsed: Duration, + /// The time the stopwatch was started last, if ever. + start_time: Option, + /// The time the stopwatch was split last, if ever. + split_time: Option, + /// The time elapsed while the stopwatch was running (between start() and stop()). + elapsed: Duration, } impl Default for Stopwatch { - fn default() -> Stopwatch { - Stopwatch { - start_time: None, - split_time: None, - elapsed: Duration::from_secs(0), - } - } + fn default() -> Stopwatch { + Stopwatch { + start_time: None, + split_time: None, + elapsed: Duration::from_secs(0), + } + } } impl fmt::Display for Stopwatch { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - return write!(f, "{}ms", self.elapsed_ms()); - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + return write!(f, "{}ms", self.elapsed_ms()); + } } impl Stopwatch { - /// Returns a new stopwatch. - pub fn new() -> Stopwatch { - let sw: Stopwatch = Default::default(); - return sw; - } + /// Returns a new stopwatch. + pub fn new() -> Stopwatch { + return Stopwatch::default(); + } - /// Returns a new stopwatch which will immediately be started. - pub fn start_new() -> Stopwatch { - let mut sw = Stopwatch::new(); - sw.start(); - return sw; - } + /// Returns a new stopwatch which will immediately be started. + pub fn start_new() -> Stopwatch { + let mut sw = Stopwatch::new(); + sw.start(); + return sw; + } - /// Starts the stopwatch. - pub fn start(&mut self) { - self.start_time = Some(Instant::now()); - } + /// Starts the stopwatch. + pub fn start(&mut self) { + self.start_time = Some(Instant::now()); + } - /// Stops the stopwatch. - pub fn stop(&mut self) { - self.elapsed = self.elapsed(); - self.start_time = None; - self.split_time = None; - } + /// Stops the stopwatch. + pub fn stop(&mut self) { + self.elapsed = self.elapsed(); + self.start_time = None; + self.split_time = None; + } - /// Resets all counters and stops the stopwatch. - pub fn reset(&mut self) { - self.elapsed = Duration::from_secs(0); - self.start_time = None; - self.split_time = None; - } + /// Resets all counters and stops the stopwatch. + pub fn reset(&mut self) { + self.elapsed = Duration::from_secs(0); + self.start_time = None; + self.split_time = None; + } - /// Resets and starts the stopwatch again. - pub fn restart(&mut self) { - self.reset(); - self.start(); - } + /// Resets and starts the stopwatch again. + pub fn restart(&mut self) { + self.reset(); + self.start(); + } - /// Returns whether the stopwatch is running. - pub fn is_running(&self) -> bool { - return self.start_time.is_some(); - } + /// Returns whether the stopwatch is running. + pub fn is_running(&self) -> bool { + self.start_time.is_some() + } - /// Returns the elapsed time since the start of the stopwatch. - pub fn elapsed(&self) -> Duration { - match self.start_time { - // stopwatch is running - Some(t1) => { - return t1.elapsed() + self.elapsed; - } - // stopwatch is not running - None => { - return self.elapsed; - } - } - } + /// Returns the elapsed time since the start of the stopwatch. + pub fn elapsed(&self) -> Duration { + match self.start_time { + // stopwatch is running + Some(t1) => t1.elapsed() + self.elapsed, + // stopwatch is not running + None => self.elapsed, + } + } - /// Returns the elapsed time since the start of the stopwatch in milliseconds. - pub fn elapsed_ms(&self) -> i64 { - let dur = self.elapsed(); - return (dur.as_secs() * 1000 + (dur.subsec_nanos() / 1000000) as u64) as i64; - } + /// Returns the elapsed time since the start of the stopwatch in milliseconds. + pub fn elapsed_ms(&self) -> i64 { + let dur = self.elapsed(); + return (dur.as_secs() * 1000 + dur.subsec_millis() as u64) as i64; + } - /// Returns the elapsed time since last split or start/restart. - /// - /// If the stopwatch is in stopped state this will always return a zero Duration. - pub fn elapsed_split(&mut self) -> Duration { - match self.start_time { - // stopwatch is running - Some(start) => { - let res = match self.split_time { - Some(split) => split.elapsed(), - None => start.elapsed(), - }; - self.split_time = Some(Instant::now()); - res - } - // stopwatch is not running - None => Duration::from_secs(0), - } - } + /// Returns the elapsed time since last split or start/restart. + /// + /// If the stopwatch is in stopped state this will always return a zero Duration. + pub fn elapsed_split(&mut self) -> Duration { + match self.start_time { + // stopwatch is running + Some(start) => { + let res = match self.split_time { + Some(split) => split.elapsed(), + None => start.elapsed(), + }; + self.split_time = Some(Instant::now()); + return res; + } + // stopwatch is not running + None => Duration::from_secs(0), + } + } - /// Returns the elapsed time since last split or start/restart in milliseconds. - /// - /// If the stopwatch is in stopped state this will always return zero. - pub fn elapsed_split_ms(&mut self) -> i64 { - let dur = self.elapsed_split(); - return (dur.as_secs() * 1000 + (dur.subsec_nanos() / 1_000_000) as u64) as i64; - } + /// Returns the elapsed time since last split or start/restart in milliseconds. + /// + /// If the stopwatch is in stopped state this will always return zero. + pub fn elapsed_split_ms(&mut self) -> i64 { + let dur = self.elapsed_split(); + return (dur.as_secs() * 1000 + dur.subsec_millis() as u64) as i64; + } } diff --git a/tests/lib.rs b/tests/lib.rs index 3a95e40..292c38b 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,172 +1,167 @@ -extern crate num; -extern crate stopwatch; - use std::time::Duration; -use stopwatch::{Stopwatch}; +use stopwatch::Stopwatch; static SLEEP_MS: i64 = 50; static TOLERANCE_PERCENTAGE: f64 = 0.3; #[test] fn repeated_stops() { - let mut sw = Stopwatch::start_new(); - for _ in 0..1000i32 { - sw.stop(); - sw.start(); - } - assert_sw_near(sw, 0); + let mut sw = Stopwatch::start_new(); + for _ in 0..1000i32 { + sw.stop(); + sw.start(); + } + assert_sw_near(sw, 0); } #[test] fn elapsed_none() { - let sw = Stopwatch::new(); - assert_eq!(sw.elapsed_ms(), 0); + let sw = Stopwatch::new(); + assert_eq!(sw.elapsed_ms(), 0); } #[test] fn elapsed_ms() { - let sw = Stopwatch::start_new(); - sleep_ms(SLEEP_MS); - assert_sw_near(sw, SLEEP_MS); + let sw = Stopwatch::start_new(); + sleep_ms(SLEEP_MS); + assert_sw_near(sw, SLEEP_MS); } #[test] fn stop() { - let mut sw = Stopwatch::start_new(); - sleep_ms(SLEEP_MS); - sw.stop(); - assert_sw_near(sw, SLEEP_MS); + let mut sw = Stopwatch::start_new(); + sleep_ms(SLEEP_MS); + sw.stop(); + assert_sw_near(sw, SLEEP_MS); - sleep_ms(SLEEP_MS); - assert_sw_near(sw, SLEEP_MS); + sleep_ms(SLEEP_MS); + assert_sw_near(sw, SLEEP_MS); } #[test] fn resume_once() { - let mut sw = Stopwatch::start_new(); - sleep_ms(SLEEP_MS); - sw.stop(); - assert_sw_near(sw, SLEEP_MS); - sw.start(); - sleep_ms(SLEEP_MS); - assert_sw_near(sw, 2 * SLEEP_MS); + let mut sw = Stopwatch::start_new(); + sleep_ms(SLEEP_MS); + sw.stop(); + assert_sw_near(sw, SLEEP_MS); + sw.start(); + sleep_ms(SLEEP_MS); + assert_sw_near(sw, 2 * SLEEP_MS); } #[test] fn resume_twice() { - let mut sw = Stopwatch::start_new(); - sleep_ms(SLEEP_MS); - sw.stop(); - assert_sw_near(sw, SLEEP_MS); - sw.start(); - sleep_ms(SLEEP_MS); - sw.stop(); - assert_sw_near(sw, 2 * SLEEP_MS); - sw.start(); - sleep_ms(SLEEP_MS); - assert_sw_near(sw, 3 * SLEEP_MS); + let mut sw = Stopwatch::start_new(); + sleep_ms(SLEEP_MS); + sw.stop(); + assert_sw_near(sw, SLEEP_MS); + sw.start(); + sleep_ms(SLEEP_MS); + sw.stop(); + assert_sw_near(sw, 2 * SLEEP_MS); + sw.start(); + sleep_ms(SLEEP_MS); + assert_sw_near(sw, 3 * SLEEP_MS); } #[test] fn is_running() { - let mut sw = Stopwatch::new(); - assert!(!sw.is_running()); - sw.start(); - assert!(sw.is_running()); - sw.stop(); - assert!(!sw.is_running()); + let mut sw = Stopwatch::new(); + assert!(!sw.is_running()); + sw.start(); + assert!(sw.is_running()); + sw.stop(); + assert!(!sw.is_running()); } #[test] fn restart() { - let mut sw = Stopwatch::start_new(); - sleep_ms(SLEEP_MS); - sw.restart(); - sleep_ms(SLEEP_MS); - assert_sw_near(sw, SLEEP_MS); + let mut sw = Stopwatch::start_new(); + sleep_ms(SLEEP_MS); + sw.restart(); + sleep_ms(SLEEP_MS); + assert_sw_near(sw, SLEEP_MS); } #[test] fn reset() { - let mut sw = Stopwatch::start_new(); - sleep_ms(SLEEP_MS); - sw.reset(); - assert!(!sw.is_running()); - assert_eq!(sw.elapsed_ms(), 0); + let mut sw = Stopwatch::start_new(); + sleep_ms(SLEEP_MS); + sw.reset(); + assert!(!sw.is_running()); + assert_eq!(sw.elapsed_ms(), 0); } #[test] fn split_on_started_watch() { - let mut sw = Stopwatch::start_new(); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, SLEEP_MS); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, SLEEP_MS); + let mut sw = Stopwatch::start_new(); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, SLEEP_MS); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, SLEEP_MS); - assert_sw_near(sw, 2 * SLEEP_MS); + assert_sw_near(sw, 2 * SLEEP_MS); } #[test] fn split_on_resumed_watch() { - let mut sw = Stopwatch::new(); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, 0); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, 0); - sw.start(); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, SLEEP_MS); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, SLEEP_MS); - sw.stop(); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, 0); - - assert_sw_near(sw, 2 * SLEEP_MS); + let mut sw = Stopwatch::new(); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, 0); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, 0); + sw.start(); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, SLEEP_MS); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, SLEEP_MS); + sw.stop(); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, 0); + + assert_sw_near(sw, 2 * SLEEP_MS); } #[test] fn split_after_reset() { - let mut sw = Stopwatch::start_new(); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, SLEEP_MS); - sw.reset(); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, 0); + let mut sw = Stopwatch::start_new(); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, SLEEP_MS); + sw.reset(); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, 0); } #[test] fn split_after_restart() { - let mut sw = Stopwatch::start_new(); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, SLEEP_MS); - sw.restart(); - sleep_ms(SLEEP_MS); - assert_split_near(&mut sw, SLEEP_MS); + let mut sw = Stopwatch::start_new(); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, SLEEP_MS); + sw.restart(); + sleep_ms(SLEEP_MS); + assert_split_near(&mut sw, SLEEP_MS); } - - /////////////// helpers fn sleep_ms(ms: i64) { - use num::ToPrimitive; - std::thread::sleep(Duration::from_millis(ms.to_u64().unwrap())) + use num_traits::ToPrimitive; + return std::thread::sleep(Duration::from_millis(ms.to_u64().unwrap())); } fn assert_near(x: i64, y: i64, tolerance: i64) { - let diff = (x - y).abs(); - if diff > tolerance { - panic!("Expected {:?}, got {:?}", x, y); - } + let diff = (x - y).abs(); + if diff > tolerance { + panic!("Expected {:?}, got {:?}", x, y); + } } fn assert_sw_near(sw: Stopwatch, elapsed: i64) { - let tolerance_value = (TOLERANCE_PERCENTAGE * elapsed as f64) as i64; - assert_near(elapsed, sw.elapsed_ms(), tolerance_value); + let tolerance_value = (TOLERANCE_PERCENTAGE * elapsed as f64) as i64; + assert_near(elapsed, sw.elapsed_ms(), tolerance_value); } fn assert_split_near(sw: &mut Stopwatch, elapsed: i64) { - let tolerance_value = (TOLERANCE_PERCENTAGE * elapsed as f64) as i64; - assert_near(elapsed, sw.elapsed_split_ms(), tolerance_value); -} \ No newline at end of file + let tolerance_value = (TOLERANCE_PERCENTAGE * elapsed as f64) as i64; + assert_near(elapsed, sw.elapsed_split_ms(), tolerance_value); +}