1use core::ops::{Add, AddAssign, Sub};
12use core::time::Duration;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
20pub struct Time(Duration);
21
22impl Time {
23 pub const ZERO: Time = Time(Duration::ZERO);
25
26 pub const MAX: Time = Time(Duration::MAX);
29
30 pub const fn from_offset(offset: Duration) -> Self {
32 Time(offset)
33 }
34
35 pub const fn from_nanos(nanos: u64) -> Self {
36 Time(Duration::from_nanos(nanos))
37 }
38
39 pub const fn from_micros(micros: u64) -> Self {
40 Time(Duration::from_micros(micros))
41 }
42
43 pub const fn from_millis(millis: u64) -> Self {
44 Time(Duration::from_millis(millis))
45 }
46
47 pub const fn from_secs(secs: u64) -> Self {
48 Time(Duration::from_secs(secs))
49 }
50
51 pub const fn as_offset(self) -> Duration {
53 self.0
54 }
55
56 pub const fn as_nanos(self) -> u128 {
58 self.0.as_nanos()
59 }
60
61 pub const fn as_millis(self) -> u128 {
63 self.0.as_millis()
64 }
65
66 pub fn saturating_since(self, earlier: Time) -> Duration {
68 self.0.saturating_sub(earlier.0)
69 }
70
71 pub fn saturating_add(self, d: Duration) -> Time {
73 Time(self.0.saturating_add(d))
74 }
75}
76
77impl Add<Duration> for Time {
78 type Output = Time;
79 fn add(self, d: Duration) -> Time {
80 self.saturating_add(d)
81 }
82}
83
84impl AddAssign<Duration> for Time {
85 fn add_assign(&mut self, d: Duration) {
86 *self = self.saturating_add(d);
87 }
88}
89
90impl Sub<Time> for Time {
91 type Output = Duration;
92 fn sub(self, earlier: Time) -> Duration {
93 self.saturating_since(earlier)
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn constructed_at_an_arbitrary_value() {
103 assert_eq!(Time::from_nanos(42).as_nanos(), 42);
105 assert_eq!(Time::from_millis(3).as_nanos(), 3_000_000);
106 assert_eq!(Time::from_nanos(5_500_000).as_millis(), 5);
107 assert_eq!(Time::from_secs(2), Time::from_millis(2_000));
108 assert_eq!(Time::from_offset(Duration::from_micros(7)).as_nanos(), 7_000);
109 }
110
111 #[test]
112 fn orders_by_offset() {
113 assert!(Time::ZERO < Time::from_nanos(1));
114 assert!(Time::from_millis(2) > Time::from_millis(1));
115 assert_eq!(Time::ZERO, Time::from_nanos(0));
116 assert!(Time::MAX > Time::from_secs(u32::MAX as u64));
117
118 let mut v = [Time::from_nanos(3), Time::from_nanos(1), Time::from_nanos(2)];
119 v.sort();
120 assert_eq!(v, [Time::from_nanos(1), Time::from_nanos(2), Time::from_nanos(3)]);
121 }
122
123 #[test]
124 fn adds_a_duration() {
125 assert_eq!(Time::ZERO + Duration::from_millis(5), Time::from_millis(5));
126 assert_eq!(Time::from_nanos(10) + Duration::from_nanos(7), Time::from_nanos(17));
127
128 let mut t = Time::ZERO;
129 t += Duration::from_millis(4);
130 t += Duration::from_millis(6);
131 assert_eq!(t, Time::from_millis(10));
132 }
133
134 #[test]
135 fn subtracts_to_a_duration() {
136 assert_eq!(Time::from_millis(9) - Time::from_millis(4), Duration::from_millis(5));
137 }
138
139 #[test]
140 fn saturates_rather_than_wrapping() {
141 assert_eq!(Time::MAX + Duration::from_secs(1), Time::MAX);
143 assert_eq!(Time::from_millis(1) - Time::from_millis(9), Duration::ZERO);
144 assert_eq!(Time::ZERO.saturating_add(Duration::MAX), Time::MAX);
145 }
146
147 #[test]
148 fn the_range_exceeds_a_u64_of_nanoseconds() {
149 let beyond_u64_nanos = Time::from_secs(600 * 365 * 24 * 60 * 60);
151 assert!(beyond_u64_nanos.as_nanos() > u64::MAX as u128);
152 assert!(beyond_u64_nanos < Time::MAX);
153 }
154}