1use core::ops::{Add, AddAssign, Sub, SubAssign};
4
5use crate::divide::div_rem;
6use crate::{NANOS_PER_MICRO, NANOS_PER_MILLI, NANOS_PER_SEC};
7
8#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct Duration(u64);
18
19impl Duration {
20 pub const ZERO: Self = Self(0);
22 pub const MAX: Self = Self(u64::MAX);
25
26 #[must_use]
28 pub const fn from_nanos(nanos: u64) -> Self {
29 Self(nanos)
30 }
31
32 #[must_use]
34 pub const fn from_micros(micros: u64) -> Self {
35 Self(micros.saturating_mul(NANOS_PER_MICRO))
36 }
37
38 #[must_use]
40 pub const fn from_millis(millis: u64) -> Self {
41 Self(millis.saturating_mul(NANOS_PER_MILLI))
42 }
43
44 #[must_use]
46 pub const fn from_secs(secs: u64) -> Self {
47 Self(secs.saturating_mul(NANOS_PER_SEC))
48 }
49
50 #[must_use]
52 pub const fn try_from_micros(micros: u64) -> Option<Self> {
53 match micros.checked_mul(NANOS_PER_MICRO) {
54 Some(nanos) => Some(Self(nanos)),
55 None => None,
56 }
57 }
58
59 #[must_use]
61 pub const fn try_from_millis(millis: u64) -> Option<Self> {
62 match millis.checked_mul(NANOS_PER_MILLI) {
63 Some(nanos) => Some(Self(nanos)),
64 None => None,
65 }
66 }
67
68 #[must_use]
70 pub const fn try_from_secs(secs: u64) -> Option<Self> {
71 match secs.checked_mul(NANOS_PER_SEC) {
72 Some(nanos) => Some(Self(nanos)),
73 None => None,
74 }
75 }
76
77 #[must_use]
79 pub const fn as_nanos(self) -> u64 {
80 self.0
81 }
82
83 #[must_use]
85 pub const fn is_zero(self) -> bool {
86 self.0 == 0
87 }
88
89 #[must_use]
91 pub const fn as_micros(self) -> u64 {
92 div_rem(self.0, NANOS_PER_MICRO).0
93 }
94
95 #[must_use]
97 pub const fn as_millis(self) -> u64 {
98 div_rem(self.0, NANOS_PER_MILLI).0
99 }
100
101 #[must_use]
103 pub const fn as_secs(self) -> u64 {
104 div_rem(self.0, NANOS_PER_SEC).0
105 }
106
107 #[must_use]
109 pub const fn checked_add(self, other: Self) -> Option<Self> {
110 match self.0.checked_add(other.0) {
111 Some(nanos) => Some(Self(nanos)),
112 None => None,
113 }
114 }
115
116 #[must_use]
118 pub const fn saturating_add(self, other: Self) -> Self {
119 Self(self.0.saturating_add(other.0))
120 }
121
122 #[must_use]
124 pub const fn checked_sub(self, other: Self) -> Option<Self> {
125 match self.0.checked_sub(other.0) {
126 Some(nanos) => Some(Self(nanos)),
127 None => None,
128 }
129 }
130
131 #[must_use]
133 pub const fn saturating_sub(self, other: Self) -> Self {
134 Self(self.0.saturating_sub(other.0))
135 }
136
137 #[must_use]
139 pub const fn checked_mul(self, factor: u32) -> Option<Self> {
140 match self.0.checked_mul(factor as u64) {
141 Some(nanos) => Some(Self(nanos)),
142 None => None,
143 }
144 }
145
146 #[must_use]
148 pub const fn saturating_mul(self, factor: u32) -> Self {
149 Self(self.0.saturating_mul(factor as u64))
150 }
151
152 #[must_use]
155 pub const fn min(self, other: Self) -> Self {
156 if self.0 <= other.0 {
157 self
158 } else {
159 other
160 }
161 }
162
163 #[must_use]
166 pub const fn max(self, other: Self) -> Self {
167 if self.0 >= other.0 {
168 self
169 } else {
170 other
171 }
172 }
173
174 #[must_use]
181 pub const fn checked_rem(self, divisor: Self) -> Option<Self> {
182 if divisor.0 == 0 {
183 None
184 } else {
185 Some(Self(div_rem(self.0, divisor.0).1))
186 }
187 }
188}
189
190impl Add for Duration {
191 type Output = Self;
192
193 fn add(self, rhs: Self) -> Self {
195 self.saturating_add(rhs)
196 }
197}
198
199impl AddAssign for Duration {
200 fn add_assign(&mut self, rhs: Self) {
202 *self = self.saturating_add(rhs);
203 }
204}
205
206impl Sub for Duration {
207 type Output = Self;
208
209 fn sub(self, rhs: Self) -> Self {
211 self.saturating_sub(rhs)
212 }
213}
214
215impl SubAssign for Duration {
216 fn sub_assign(&mut self, rhs: Self) {
218 *self = self.saturating_sub(rhs);
219 }
220}