diff --git a/.vscode/settings.json b/.vscode/settings.json index 4525406..2ed4801 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,13 @@ { - "cSpell.words": ["byteorder", "ftmemsim", "hemem", "itertools"] + "cSpell.words": [ + "byteorder", + "femto", + "FEMTOS", + "ftmemsim", + "hemem", + "itertools", + "optane", + "pico", + "PICOS" + ] } diff --git a/src/util.rs b/src/util.rs index b668a26..0d2c8de 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,11 @@ //! Utilities +// Modules +mod duration; + +// Exports +pub use duration::FemtoDuration; + // Imports use std::io; diff --git a/src/util/duration.rs b/src/util/duration.rs new file mode 100644 index 0000000..8833f4f --- /dev/null +++ b/src/util/duration.rs @@ -0,0 +1,64 @@ +//! Duration + +// Imports +use std::{fmt, writeln}; + +/// Duration with femto-second precision +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct FemtoDuration { + /// Whole seconds + secs: u64, + + /// femto seconds (0..FEMTOS_PER_SEC) + femto_secs: u64, +} + +impl FemtoDuration { + /// Number of femto-seconds per nano-second + pub const FEMTOS_PER_NANO: u64 = 1_000_000; + /// Number of nano-seconds per second + pub const NANOS_PER_SEC: u64 = 1_000_000_000; + /// Number of femto-seconds per second + pub const _FEMTOS_PER_SEC: u64 = 1_000_000_000_000_000; + + /// Creates a new duration from floating-point nanoseconds + // TODO: Deal with rounding better? + pub fn from_nanos_f64(nanos: f64) -> Self { + let secs = (nanos / Self::NANOS_PER_SEC as f64) as u64; + let femto_secs = ((nanos % Self::NANOS_PER_SEC as f64) * Self::FEMTOS_PER_NANO as f64) as u64; + + Self { secs, femto_secs } + } +} + + +impl fmt::Display for FemtoDuration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let secs = self.secs % 60; + let mins = self.secs / 60 % 60; + let hours = self.secs / 60 / 60; + + let femtos = self.femto_secs % 1000; + let picos = self.femto_secs / 1000 % 1000; + let nanos = self.femto_secs / 1000 / 1000 % 1000; + let micros = self.femto_secs / 1000 / 1000 / 1000 % 1000; + let millis = self.femto_secs / 1000 / 1000 / 1000 / 1000 % 1000; + + match (hours, mins, secs, millis, micros, nanos, picos, femtos) { + // If we have no hours, mins or secs, format in the smallest unit + (0, 0, 0, 0, 0, 0, 0, 0) => (), + (0, 0, 0, 0, 0, 0, 0, _) => writeln!(f, "{femtos}fs")?, + (0, 0, 0, 0, 0, 0, ..) => writeln!(f, "{picos}.{femtos}ps")?, + (0, 0, 0, 0, 0, ..) => writeln!(f, "{nanos}.{picos}{femtos}ns")?, + (0, 0, 0, 0, ..) => writeln!(f, "{micros}.{nanos}{picos}{femtos}µs")?, + (0, 0, 0, ..) => writeln!(f, "{millis}.{micros}{nanos}{picos}{femtos}ms")?, + + // Else format it as the decimal part + (0, 0, ..) => writeln!(f, "{secs}.{millis}{micros}{nanos}{picos}{femtos}s")?, + (0, ..) => writeln!(f, "{mins}m{secs}.{millis}{micros}{nanos}{picos}{femtos}s")?, + (..) => writeln!(f, "{hours}h{mins}m{secs}.{millis}{micros}{nanos}{picos}{femtos}s")?, + } + + Ok(()) + } +}