turbo_tasks/
small_duration.rs1use std::{
2 fmt::{Debug, Display},
3 time::Duration,
4};
5
6#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
12pub struct SmallDuration<const P: u64>(u32);
13
14impl<const P: u64> SmallDuration<P> {
15 pub const ZERO: SmallDuration<P> = SmallDuration(0);
16 pub const MIN: SmallDuration<P> = SmallDuration(1);
18 pub const MAX: SmallDuration<P> = SmallDuration(u32::MAX);
19
20 pub const fn from_nanos(nanos: u64) -> Self {
21 if nanos == 0 {
22 return SmallDuration::ZERO;
23 }
24 if nanos <= P {
25 return SmallDuration::MIN;
26 }
27 let value = nanos / P;
28 if value > u32::MAX as u64 {
29 return SmallDuration::MAX;
30 }
31 SmallDuration(value as u32)
32 }
33
34 pub const fn from_micros(micros: u64) -> Self {
35 if micros == 0 {
36 return SmallDuration::ZERO;
37 }
38 let micros_precision = P / 1_000;
39 if micros <= micros_precision {
40 return SmallDuration::MIN;
41 }
42 let value = micros * 1_000 / P;
43 if value > u32::MAX as u64 {
44 return SmallDuration::MAX;
45 }
46 SmallDuration(value as u32)
47 }
48
49 pub const fn from_millis(millis: u64) -> Self {
50 if millis == 0 {
51 return SmallDuration::ZERO;
52 }
53 let millis_precision = P / 1_000_000;
54 if millis <= millis_precision {
55 return SmallDuration::MIN;
56 }
57 let value = millis * 1_000_000 / P;
58 if value > u32::MAX as u64 {
59 return SmallDuration::MAX;
60 }
61 SmallDuration(value as u32)
62 }
63
64 pub const fn from_secs(secs: u64) -> Self {
65 if secs == 0 {
66 return SmallDuration::ZERO;
67 }
68 let secs_precision = P / 1_000_000_000;
69 if secs <= secs_precision {
70 return SmallDuration::MIN;
71 }
72 let value = secs * 1_000_000_000 / P;
73 if value > u32::MAX as u64 {
74 return SmallDuration::MAX;
75 }
76 SmallDuration(value as u32)
77 }
78
79 pub(self) fn to_duration(self) -> Duration {
80 Duration::from_nanos(self.0 as u64 * P)
81 }
82}
83
84impl<const P: u64> From<Duration> for SmallDuration<P> {
85 fn from(duration: Duration) -> Self {
86 if duration.is_zero() {
87 return SmallDuration::ZERO;
88 }
89 let nanos = duration.as_nanos();
90 if nanos <= P as u128 {
91 return SmallDuration::MIN;
92 }
93 (nanos / P as u128)
94 .try_into()
95 .map_or(SmallDuration::MAX, SmallDuration)
96 }
97}
98
99impl<const P: u64> From<SmallDuration<P>> for Duration {
100 fn from(duration: SmallDuration<P>) -> Self {
101 duration.to_duration()
102 }
103}
104
105impl<const P: u64> Display for SmallDuration<P> {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 let duration = Duration::from(*self);
108 duration.fmt(f)
109 }
110}
111
112impl<const P: u64> Debug for SmallDuration<P> {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 let duration = Duration::from(*self);
115 duration.fmt(f)
116 }
117}
118
119impl<const P: u64> PartialEq<Duration> for SmallDuration<P> {
120 fn eq(&self, other: &Duration) -> bool {
121 self.to_duration() == *other
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use std::time::Duration;
128
129 use super::SmallDuration;
130
131 #[test]
132 fn test_1_nano() {
133 type Sd = SmallDuration<1>;
134
135 assert_eq!(Sd::from_nanos(1), Duration::from_nanos(1));
136 assert_eq!(Sd::from_nanos(42), Duration::from_nanos(42));
137
138 assert_eq!(Sd::from_micros(1), Duration::from_micros(1));
139 assert_eq!(Sd::from_micros(42), Duration::from_micros(42));
140
141 assert_eq!(Sd::from_millis(1), Duration::from_millis(1));
142 assert_eq!(Sd::from_millis(42), Duration::from_millis(42));
143
144 assert_eq!(Sd::from_secs(1), Duration::from_secs(1));
145
146 assert_eq!(Sd::from_secs(4), Duration::from_secs(4));
148 assert_eq!(Sd::from_secs(5), Sd::MAX);
149 }
150
151 #[test]
152 fn test_1_micro() {
153 type Sd = SmallDuration<1_000>;
154
155 assert_eq!(Sd::from_nanos(1), Sd::MIN);
157 assert_eq!(Sd::from_nanos(42), Sd::MIN);
158
159 assert_eq!(Sd::from_micros(1), Duration::from_micros(1));
160 assert_eq!(Sd::from_micros(42), Duration::from_micros(42));
161
162 assert_eq!(Sd::from_millis(1), Duration::from_millis(1));
163 assert_eq!(Sd::from_millis(42), Duration::from_millis(42));
164
165 assert_eq!(Sd::from_secs(1), Duration::from_secs(1));
166 assert_eq!(Sd::from_secs(42), Duration::from_secs(42));
167
168 assert_eq!(Sd::from_secs(4_000), Duration::from_secs(4_000));
170 assert_eq!(Sd::from_secs(5_000), Sd::MAX);
171 }
172
173 #[test]
174 fn test_1_milli() {
175 type Sd = SmallDuration<1_000_000>;
176
177 assert_eq!(Sd::from_nanos(1), Sd::MIN);
179 assert_eq!(Sd::from_nanos(42), Sd::MIN);
180 assert_eq!(Sd::from_micros(1), Sd::MIN);
181 assert_eq!(Sd::from_micros(42), Sd::MIN);
182
183 assert_eq!(Sd::from_millis(1), Duration::from_millis(1));
184 assert_eq!(Sd::from_millis(42), Duration::from_millis(42));
185
186 assert_eq!(Sd::from_secs(1), Duration::from_secs(1));
187 assert_eq!(Sd::from_secs(42), Duration::from_secs(42));
188
189 assert_eq!(Sd::from_secs(4_000_000), Duration::from_secs(4_000_000));
191 assert_eq!(Sd::from_secs(5_000_000), Sd::MAX);
192 }
193
194 #[test]
195 fn test_1_sec() {
196 type Sd = SmallDuration<1_000_000_000>;
197
198 assert_eq!(Sd::from_nanos(1), Sd::MIN);
200 assert_eq!(Sd::from_nanos(42), Sd::MIN);
201 assert_eq!(Sd::from_micros(1), Sd::MIN);
202 assert_eq!(Sd::from_micros(42), Sd::MIN);
203 assert_eq!(Sd::from_millis(1), Sd::MIN);
204 assert_eq!(Sd::from_millis(42), Sd::MIN);
205
206 assert_eq!(Sd::from_secs(1), Duration::from_secs(1));
207 assert_eq!(Sd::from_secs(42), Duration::from_secs(42));
208
209 assert_eq!(
211 Sd::from_secs(4_000_000_000),
212 Duration::from_secs(4_000_000_000)
213 );
214 assert_eq!(Sd::from_secs(5_000_000_000), Sd::MAX);
215 }
216}