#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::{Measurement, PhysicalQuantity, UnitOfMeasure};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(C)]
pub enum DurationUnit {
Seconds,
}
impl UnitOfMeasure<u32> for DurationUnit {
fn quantity() -> PhysicalQuantity {
PhysicalQuantity::Duration
}
fn si() -> Self {
Self::Seconds
}
fn symbol(&self) -> &'static str {
"s"
}
fn from_si(value: u32, _: &Self) -> u32 {
value
}
fn to_si(&self, value: &u32) -> u32 {
*value
}
}
pub type Duration = Measurement<u32, DurationUnit>;
impl Duration {
pub fn s(value: u32) -> Self {
Measurement {
value,
unit: DurationUnit::Seconds,
}
}
pub fn m(value: u32) -> Self {
Self::s(value * 60)
}
pub fn hours(&self) -> u32 {
self.value / 3600 % 24
}
pub fn minutes(&self) -> u32 {
self.value / 60 % 60
}
pub fn seconds(&self) -> u32 {
self.value % 60
}
pub fn round(&self) -> Self {
let s = self.seconds();
let rounded_value = if s >= 30 {
self.value - s + 60
} else {
self.value - s
};
Self::s(rounded_value)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_seconds() {
let duration = Duration::s(3661);
assert_eq!(duration.hours(), 1);
assert_eq!(duration.minutes(), 1);
assert_eq!(duration.seconds(), 1);
}
#[test]
fn from_minutes() {
let duration = Duration::m(4);
assert_eq!(*duration.value(), 240);
assert_eq!(duration.hours(), 0);
assert_eq!(duration.minutes(), 4);
assert_eq!(duration.seconds(), 0);
}
#[test]
fn sum_durations() {
let sum = Duration::m(60) + Duration::s(60) + Duration::s(1);
assert_eq!(sum.hours(), 1);
assert_eq!(sum.minutes(), 1);
assert_eq!(sum.seconds(), 1);
}
#[test]
fn round() {
let duration = Duration::s(29);
assert_eq!(duration.round().minutes(), 0);
let duration = Duration::s(30);
assert_eq!(duration.round().minutes(), 1);
}
}