1use self::sealed::{DefaultOutput, MultipleOf};
4
5macro_rules! stringify_outputs {
7 (@inner $first:ty) => {
8 concat!("or `", stringify!($first), "`")
9 };
10 (@inner $first:ty, $($t:ty),+) => {
11 concat!(stringify_outputs!($first), ", ", stringify_outputs!(@inner $($t),+))
12 };
13 ($first:ty) => {
14 concat!("`", stringify!($first), "`")
15 };
16 ($($t:ty),+) => {
17 stringify_outputs!(@inner $($t),+)
18 };
19}
20
21macro_rules! declare_types {
23 ($($t:ident ($str:literal))+) => {$(
24 #[doc = concat!("A unit of time representing exactly `N` ", $str, "s.")]
25 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
26 pub struct $t<const N: u128 = 1>;
27 )+};
28}
29
30macro_rules! impl_per {
32 ($($t:ident per {$(
33 $larger:ident : [$default_output:ty]
34
35 $($int_output:ty)|+ = $int_value:expr;
36 $($float_output:ty)|+ = $float_value:expr;
37 )+})*) => {$(
38 impl $t<1> {
39 #[doc = concat!("Obtain the number of times `", stringify!($t), "` can fit into `T`.")]
40 #[doc = concat!("If `T` is smaller than `", stringify!($t), "`, the code will fail to")]
41 $(#[doc = concat!(
47 " - `", stringify!($t), "::per(", stringify!($larger), ")` (returns `",
48 stringify!($default_output), "`)"
49 )])+
50 #[inline]
51 pub const fn per<T>(_larger: T) -> <T as DefaultOutput<Self>>::Output
52 where
53 T: MultipleOf<Self, T::Output> + DefaultOutput<Self> + Copy,
54 {
55 T::VALUE
56 }
57
58 #[doc = concat!("Obtain the number of times `", stringify!($t), "` can fit into `T`.")]
59 #[doc = concat!("If `T` is smaller than `", stringify!($t), "`, the code will fail to")]
60 $(#[doc = concat!(
65 " - `", stringify!($t), "::per(", stringify!($larger), ")` (returns ",
66 stringify_outputs!($($int_output),+ , $($float_output),+), ")"
67 )])+
68 #[inline]
69 pub const fn per_t<Output>(larger: impl MultipleOf<Self, Output> + Copy) -> Output {
70 multiple_of_value(larger)
71 }
72 }
73
74 $(
75 $(impl MultipleOf<$t, $int_output> for $larger {
76 const VALUE: $int_output = $int_value;
77 })+
78
79 $(impl MultipleOf<$t, $float_output> for $larger {
80 const VALUE: $float_output = $float_value;
81 })+
82
83 impl DefaultOutput<$t> for $larger {
84 type Output = $default_output;
85 }
86 )+
87 )*};
88}
89
90macro_rules! impl_partial_eq_ord {
92 ($($self:ident {
93 $(> $($bigger:ident)+;)?
94 $(< $($smaller:ident)+;)?
95 })*) => {$(
96 $($(
97 impl<const N: u128> PartialEq<$bigger<N>> for $self<N> {
98 #[inline]
99 fn eq(&self, _: &$bigger<N>) -> bool {
100 false
101 }
102 }
103
104 impl<const N: u128> PartialOrd<$bigger<N>> for $self<N> {
105 #[inline]
106 fn partial_cmp(&self, _: &$bigger<N>) -> Option<core::cmp::Ordering> {
107 Some(core::cmp::Ordering::Greater)
108 }
109 }
110 )+)?
111
112 $($(
113 impl<const N: u128> PartialEq<$smaller<N>> for $self<N> {
114 #[inline]
115 fn eq(&self, _: &$smaller<N>) -> bool {
116 false
117 }
118 }
119
120 impl<const N: u128> PartialOrd<$smaller<N>> for $self<N> {
121 #[inline]
122 fn partial_cmp(&self, _: &$smaller<N>) -> Option<core::cmp::Ordering> {
123 Some(core::cmp::Ordering::Less)
124 }
125 }
126 )+)?
127 )*};
128}
129
130macro_rules! impl_partial_eq_ord_for_unit {
132 ($($ty:ident)+) => {$(
133 impl<const N: u128> PartialEq<$ty<N>> for Unit<N> {
134 #[inline]
135 fn eq(&self, _: &$ty<N>) -> bool {
136 *self == Self::$ty
137 }
138 }
139
140 impl<const N: u128> PartialEq<Unit<N>> for $ty<N> {
141 #[inline]
142 fn eq(&self, other: &Unit<N>) -> bool {
143 *other == Unit::$ty
144 }
145 }
146
147 impl<const N: u128> PartialOrd<$ty<N>> for Unit<N> {
148 #[inline]
149 fn partial_cmp(&self, _: &$ty<N>) -> Option<core::cmp::Ordering> {
150 self.partial_cmp(&Unit::$ty)
151 }
152 }
153
154 impl<const N: u128> PartialOrd<Unit<N>> for $ty<N> {
155 #[inline]
156 fn partial_cmp(&self, other: &Unit<N>) -> Option<core::cmp::Ordering> {
157 Unit::$ty.partial_cmp(other)
158 }
159 }
160 )+};
161}
162
163mod sealed {
164 #[diagnostic::on_unimplemented(message = "`{Self}` is not an integer multiple of `{T}`")]
168 pub trait MultipleOf<T, Output> {
169 const VALUE: Output;
171 }
172
173 pub trait DefaultOutput<T> {
175 type Output;
177 }
178}
179
180const fn multiple_of_value<T, U, Output>(_: T) -> Output
183where
184 T: MultipleOf<U, Output> + Copy,
185{
186 T::VALUE
187}
188
189declare_types! {
190 Nanosecond ("nanosecond")
191 Microsecond ("microsecond")
192 Millisecond ("millisecond")
193 Second ("second")
194 Minute ("minute")
195 Hour ("hour")
196 Day ("day")
197 Week ("week")
198}
199
200impl_per! {
201 Nanosecond per {
202 Nanosecond: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 1; f32|f64 = 1.;
203 Microsecond: [u16] u16|u32|u64|u128|usize|i16|i32|i64|i128|isize = 1_000; f32|f64 = 1_000.;
204 Millisecond: [u32] u32|u64|u128|usize|i32|i64|i128|isize = 1_000_000; f32|f64 = 1_000_000.;
205 Second:
206 [u32] u32|u64|u128|usize|i32|i64|i128|isize = 1_000_000_000; f32|f64 = 1_000_000_000.;
207 Minute: [u64] u64|u128|i64|i128 = 60_000_000_000; f32|f64 = 60_000_000_000.;
208 Hour: [u64] u64|u128|i64|i128 = 3_600_000_000_000; f32|f64 = 3_600_000_000_000.;
209 Day: [u64] u64|u128|i64|i128 = 86_400_000_000_000; f32|f64 = 86_400_000_000_000.;
210 Week: [u64] u64|u128|i64|i128 = 604_800_000_000_000; f32|f64 = 604_800_000_000_000.;
211 }
212 Microsecond per {
213 Microsecond: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 1; f32|f64 = 1.;
214 Millisecond: [u16] u16|u32|u64|u128|usize|i16|i32|i64|i128|isize = 1_000; f32|f64 = 1_000.;
215 Second: [u32] u32|u64|u128|usize|i32|i64|i128|isize = 1_000_000; f32|f64 = 1_000_000.;
216 Minute: [u32] u32|u64|u128|usize|i32|i64|i128|isize = 60_000_000; f32|f64 = 60_000_000.;
217 Hour: [u32] u32|u64|u128|i64|i128 = 3_600_000_000; f32|f64 = 3_600_000_000.;
218 Day: [u64] u64|u128|i64|i128 = 86_400_000_000; f32|f64 = 86_400_000_000.;
219 Week: [u64] u64|u128|i64|i128 = 604_800_000_000; f32|f64 = 604_800_000_000.;
220 }
221 Millisecond per {
222 Millisecond: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 1; f32|f64 = 1.;
223 Second: [u16] u16|u32|u64|u128|usize|i16|i32|i64|i128|isize = 1_000; f32|f64 = 1_000.;
224 Minute: [u16] u16|u32|u64|u128|usize|i32|i64|i128|isize = 60_000; f32|f64 = 60_000.;
225 Hour: [u32] u32|u64|u128|usize|i32|i64|i128|isize = 3_600_000; f32|f64 = 3_600_000.;
226 Day: [u32] u32|u64|u128|usize|i32|i64|i128|isize = 86_400_000; f32|f64 = 86_400_000.;
227 Week: [u32] u32|u64|u128|usize|i32|i64|i128|isize = 604_800_000; f32|f64 = 604_800_000.;
228 }
229 Second per {
230 Second: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 1; f32|f64 = 1.;
231 Minute: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 60; f32|f64 = 60.;
232 Hour: [u16] u16|u32|u64|u128|usize|i16|i32|i64|i128|isize = 3_600; f32|f64 = 3_600.;
233 Day: [u32] u32|u64|u128|usize|i32|i64|i128|isize = 86_400; f32|f64 = 86_400.;
234 Week: [u32] u32|u64|u128|usize|i32|i64|i128|isize = 604_800; f32|f64 = 604_800.;
235 }
236 Minute per {
237 Minute: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 1; f32|f64 = 1.;
238 Hour: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 60; f32|f64 = 60.;
239 Day: [u16] u16|u32|u64|u128|usize|i16|i32|i64|i128|isize = 1_440; f32|f64 = 1_440.;
240 Week: [u16] u16|u32|u64|u128|usize|i16|i32|i64|i128|isize = 10_080; f32|f64 = 10_080.;
241 }
242 Hour per {
243 Hour: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 1; f32|f64 = 1.;
244 Day: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 24; f32|f64 = 24.;
245 Week: [u8] u8|u16|u32|u64|u128|usize|i16|i32|i64|i128|isize = 168; f32|f64 = 168.;
246 }
247 Day per {
248 Day: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 1; f32|f64 = 1.;
249 Week: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 7; f32|f64 = 7.;
250 }
251 Week per {
252 Week: [u8] u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize = 1; f32|f64 = 1.;
253 }
254}
255
256impl_partial_eq_ord! {
257 Nanosecond {
258 < Microsecond Millisecond Second Minute Hour Day Week;
259 }
260 Microsecond {
261 > Nanosecond;
262 < Millisecond Second Minute Hour Day Week;
263 }
264 Millisecond {
265 > Nanosecond Microsecond;
266 < Second Minute Hour Day Week;
267 }
268 Second {
269 > Nanosecond Microsecond Millisecond;
270 < Minute Hour Day Week;
271 }
272 Minute {
273 > Nanosecond Microsecond Millisecond Second;
274 < Hour Day Week;
275 }
276 Hour {
277 > Nanosecond Microsecond Millisecond Second Minute;
278 < Day Week;
279 }
280 Day {
281 > Nanosecond Microsecond Millisecond Second Minute Hour;
282 < Week;
283 }
284 Week {
285 > Nanosecond Microsecond Millisecond Second Minute Hour Day;
286 }
287}
288
289#[non_exhaustive]
291#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
292pub enum Unit<const N: u128 = 1> {
293 #[expect(missing_docs)]
294 Nanosecond,
295 #[expect(missing_docs)]
296 Microsecond,
297 #[expect(missing_docs)]
298 Millisecond,
299 #[expect(missing_docs)]
300 Second,
301 #[expect(missing_docs)]
302 Minute,
303 #[expect(missing_docs)]
304 Hour,
305 #[expect(missing_docs)]
306 Day,
307 #[expect(missing_docs)]
308 Week,
309}
310
311impl_partial_eq_ord_for_unit![Nanosecond Microsecond Millisecond Second Minute Hour Day Week];