Skip to main content

waremax_core/
time.rs

1//! Simulation time type with sub-second precision
2
3use rkyv::{Archive, Deserialize, Serialize};
4use std::fmt;
5use std::ops::{Add, AddAssign, Sub, SubAssign};
6
7/// Simulation time in seconds (f64 for sub-second precision)
8#[derive(Archive, Deserialize, Serialize, Clone, Copy, PartialEq, Default)]
9#[rkyv(compare(PartialEq))]
10pub struct SimTime(pub f64);
11
12impl SimTime {
13    /// Zero time constant
14    pub const ZERO: SimTime = SimTime(0.0);
15
16    /// Maximum time constant (for sentinel values)
17    pub const MAX: SimTime = SimTime(f64::MAX);
18
19    /// Create from seconds
20    #[inline]
21    pub fn from_seconds(s: f64) -> Self {
22        SimTime(s)
23    }
24
25    /// Create from minutes
26    #[inline]
27    pub fn from_minutes(m: f64) -> Self {
28        SimTime(m * 60.0)
29    }
30
31    /// Create from hours
32    #[inline]
33    pub fn from_hours(h: f64) -> Self {
34        SimTime(h * 3600.0)
35    }
36
37    /// Get time as seconds
38    #[inline]
39    pub fn as_seconds(&self) -> f64 {
40        self.0
41    }
42
43    /// Get time as minutes
44    #[inline]
45    pub fn as_minutes(&self) -> f64 {
46        self.0 / 60.0
47    }
48
49    /// Get time as hours
50    #[inline]
51    pub fn as_hours(&self) -> f64 {
52        self.0 / 3600.0
53    }
54
55    /// Check if time is zero
56    #[inline]
57    pub fn is_zero(&self) -> bool {
58        self.0 == 0.0
59    }
60}
61
62impl Add for SimTime {
63    type Output = SimTime;
64
65    #[inline]
66    fn add(self, rhs: SimTime) -> SimTime {
67        SimTime(self.0 + rhs.0)
68    }
69}
70
71impl Sub for SimTime {
72    type Output = SimTime;
73
74    #[inline]
75    fn sub(self, rhs: SimTime) -> SimTime {
76        SimTime(self.0 - rhs.0)
77    }
78}
79
80impl AddAssign for SimTime {
81    #[inline]
82    fn add_assign(&mut self, rhs: SimTime) {
83        self.0 += rhs.0;
84    }
85}
86
87impl SubAssign for SimTime {
88    #[inline]
89    fn sub_assign(&mut self, rhs: SimTime) {
90        self.0 -= rhs.0;
91    }
92}
93
94impl PartialOrd for SimTime {
95    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
96        self.0.partial_cmp(&other.0)
97    }
98}
99
100impl fmt::Debug for SimTime {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        write!(f, "SimTime({:.3}s)", self.0)
103    }
104}
105
106impl fmt::Display for SimTime {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        if self.0 >= 3600.0 {
109            write!(f, "{:.2}h", self.as_hours())
110        } else if self.0 >= 60.0 {
111            write!(f, "{:.2}m", self.as_minutes())
112        } else {
113            write!(f, "{:.2}s", self.0)
114        }
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn test_time_conversions() {
124        let t = SimTime::from_minutes(1.5);
125        assert_eq!(t.as_seconds(), 90.0);
126        assert_eq!(t.as_minutes(), 1.5);
127    }
128
129    #[test]
130    fn test_time_arithmetic() {
131        let t1 = SimTime::from_seconds(10.0);
132        let t2 = SimTime::from_seconds(5.0);
133        assert_eq!((t1 + t2).as_seconds(), 15.0);
134        assert_eq!((t1 - t2).as_seconds(), 5.0);
135    }
136}