1use crate::{Duration, ExtAny, _core::fmt};
31
32#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
43 pub y: Y,
45 pub mo: MO,
47 pub d: D,
49 pub h: H,
51 pub m: M,
53 pub s: S,
55 pub ms: MS,
57 pub us: US,
59 pub ns: NS,
61}
62
63pub type TimeSplitNorm = TimeSplit<u64, u8, u8, u8, u8, u8, u16, u16, u16>;
67
68pub type TimeSplitYearDay<Y, MO, D> = TimeSplit<Y, MO, D, (), (), (), (), (), ()>;
70pub type TimeSplitYearDayNorm = TimeSplit<u64, u8, u8, (), (), (), (), (), ()>;
72
73pub type TimeSplitYearSec<Y, MO, D, H, M, S> = TimeSplit<Y, MO, D, H, M, S, (), (), ()>;
75pub type TimeSplitYearSecNorm = TimeSplit<u64, u8, u8, u8, u8, u8, (), (), ()>;
77
78pub type TimeSplitHourSec<H, M, S> = TimeSplit<(), (), (), H, M, S, (), (), ()>;
80pub type TimeSplitHourSecNorm = TimeSplit<(), (), (), u64, u8, u8, (), (), ()>;
82
83pub type TimeSplitHourNano<H, M, S, MS, US, NS> = TimeSplit<(), (), (), H, M, S, MS, US, NS>;
85pub type TimeSplitHourNanoNorm = TimeSplit<(), (), (), u64, u8, u8, u16, u16, u16>;
87
88pub type TimeSplitMilliNano<MS, US, NS> = TimeSplit<(), (), (), (), (), (), MS, US, NS>;
90pub type TimeSplitMilliNanoNorm = TimeSplit<(), (), (), (), (), (), u16, u16, u16>;
92
93impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
96 #[allow(clippy::too_many_arguments)]
98 pub const fn new(y: Y, mo: MO, d: D, h: H, m: M, s: S, ms: MS, us: US, ns: NS) -> Self {
99 Self { y, mo, d, h, m, s, ms, us, ns }
100 }
101}
102impl TimeSplitNorm {
103 pub const fn from_duration(duration: Duration) -> Self {
107 let secs = duration.as_secs();
108 let total_days = secs / 86400;
109 let y = total_days / 365;
110 let days_remaining = total_days % 365;
111 let mo = (days_remaining / 30) as u8;
112 let d = (days_remaining % 30) as u8;
113 let h = ((secs % 86400) / 3600) as u8;
114 let m = ((secs % 3600) / 60) as u8;
115 let s = (secs % 60) as u8;
116 let nanos = duration.subsec_nanos();
117 let ms = (nanos / 1_000_000) as u16;
118 let us = ((nanos % 1_000_000) / 1_000) as u16;
119 let ns = (nanos % 1_000) as u16;
120 TimeSplit { y, mo, d, h, m, s, ms, us, ns }
121 }
122}
123
124impl<Y, MO, D> TimeSplitYearDay<Y, MO, D> {
125 pub const fn new_year_day(y: Y, mo: MO, d: D) -> Self {
127 Self::new(y, mo, d, (), (), (), (), (), ())
128 }
129}
130impl TimeSplitYearDayNorm {
131 pub const fn from_duration(duration: Duration) -> Self {
135 let days = duration.as_secs() / 86400;
136 let y = days / 365;
137 let days_rem = days % 365;
138 let mo = (days_rem / 30) as u8;
139 let d = (days_rem % 30) as u8;
140 Self::new_year_day(y, mo, d)
141 }
142}
143
144impl<Y, MO, D, H, M, S> TimeSplitYearSec<Y, MO, D, H, M, S> {
145 pub const fn new_year_sec(y: Y, mo: MO, d: D, h: H, m: M, s: S) -> Self {
147 Self::new(y, mo, d, h, m, s, (), (), ())
148 }
149}
150impl TimeSplitYearSecNorm {
151 pub const fn from_duration(duration: Duration) -> Self {
155 let secs = duration.as_secs();
156 let total_days = secs / 86400;
157 let y = total_days / 365;
158 let days_remaining = total_days % 365;
159 let mo = (days_remaining / 30) as u8;
160 let d = (days_remaining % 30) as u8;
161 let h = ((secs % 86400) / 3600) as u8;
162 let m = ((secs % 3600) / 60) as u8;
163 let s = (secs % 60) as u8;
164 Self::new_year_sec(y, mo, d, h, m, s)
165 }
166}
167
168impl<H, M, S> TimeSplitHourSec<H, M, S> {
169 pub const fn new_hour_sec(h: H, m: M, s: S) -> Self {
171 Self::new((), (), (), h, m, s, (), (), ())
172 }
173}
174impl TimeSplitHourSecNorm {
175 pub const fn from_duration(duration: Duration) -> Self {
179 let secs = duration.as_secs();
180 let h = secs / 3600;
181 let m = ((secs % 3600) / 60) as u8;
182 let s = (secs % 60) as u8;
183 Self::new_hour_sec(h, m, s)
184 }
185}
186
187impl<MS, US, NS> TimeSplitMilliNano<MS, US, NS> {
188 pub const fn new_milli_nano(ms: MS, us: US, ns: NS) -> Self {
190 Self::new((), (), (), (), (), (), ms, us, ns)
191 }
192}
193impl TimeSplitMilliNanoNorm {
194 pub const fn from_duration(duration: Duration) -> Self {
199 let nanos = duration.subsec_nanos();
200 let ms = (nanos / 1_000_000) as u16;
201 let us = ((nanos % 1_000_000) / 1_000) as u16;
202 let ns = (nanos % 1_000) as u16;
203 Self::new_milli_nano(ms, us, ns)
204 }
205}
206
207impl<H, M, S, MS, US, NS> TimeSplitHourNano<H, M, S, MS, US, NS> {
208 pub const fn new_hour_nano(h: H, m: M, s: S, ms: MS, us: US, ns: NS) -> Self {
210 Self::new((), (), (), h, m, s, ms, us, ns)
211 }
212}
213impl TimeSplitHourNano<u64, u8, u8, u16, u16, u16> {
214 pub const fn from_duration(duration: Duration) -> Self {
216 let secs = duration.as_secs();
217 let h = (secs % 86400) / 3600;
218 let m = ((secs % 3600) / 60) as u8;
219 let s = (secs % 60) as u8;
220 let nanos = duration.subsec_nanos();
221 let ms = (nanos / 1_000_000) as u16;
222 let us = ((nanos % 1_000_000) / 1_000) as u16;
223 let ns = (nanos % 1_000) as u16;
224 Self::new_hour_nano(h, m, s, ms, us, ns)
225 }
226}
227
228impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
230 pub const Y: bool = size_of::<Y>() != 0;
232 pub const MO: bool = size_of::<MO>() != 0;
234 pub const D: bool = size_of::<D>() != 0;
236 pub const H: bool = size_of::<H>() != 0;
238 pub const M: bool = size_of::<M>() != 0;
240 pub const S: bool = size_of::<S>() != 0;
242 pub const MS: bool = size_of::<MS>() != 0;
244 pub const US: bool = size_of::<US>() != 0;
246 pub const NS: bool = size_of::<NS>() != 0;
248
249 pub const Y_D: bool = Self::Y && Self::MO && Self::D;
251 pub const H_S: bool = Self::H && Self::M && Self::S;
253 pub const MS_NS: bool = Self::MS && Self::US && Self::NS;
255
256 pub const Y_S: bool = Self::Y_D && Self::H_S;
258 pub const H_NS: bool = Self::H_S && Self::MS_NS;
260
261 pub const Y_NS: bool = Self::Y_D && Self::H_S && Self::MS_NS;
263
264 pub const IS_YEAR_DAY: bool = Self::Y_D && !Self::H_NS;
266 pub const IS_HOUR_SEC: bool = Self::H_S && !Self::Y_D && !Self::MS_NS;
268 pub const IS_MILLI_NANO: bool = Self::MS_NS && !Self::Y_S;
270
271 pub const IS_YEAR_SEC: bool = Self::Y_S && !Self::MS_NS;
273 pub const IS_HOUR_NANO: bool = Self::H_NS && !Self::Y_D;
275
276 pub const IS_YEAR_NANO: bool = Self::Y_NS;
278}
279
280#[rustfmt::skip]
282impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
283 pub const fn has_y(&self) -> bool { Self::Y }
285 pub const fn has_mo(&self) -> bool { Self::MO }
287 pub const fn has_d(&self) -> bool { Self::D }
289 pub const fn has_h(&self) -> bool { Self::H }
291 pub const fn has_s(&self) -> bool { Self::S }
293 pub const fn has_ms(&self) -> bool { Self::MS }
295 pub const fn has_us(&self) -> bool { Self::US }
297 pub const fn has_ns(&self) -> bool { Self::NS }
299
300 pub const fn has_y_d(&self) -> bool { Self::Y_D }
302 pub const fn has_h_s(&self) -> bool { Self::H_S }
304 pub const fn has_ms_ns(&self) -> bool { Self::MS_NS }
306
307 pub const fn has_y_s(&self) -> bool { Self::Y_S }
309 pub const fn has_h_ns(&self) -> bool { Self::H_NS }
311
312 pub const fn has_y_ns(&self) -> bool { Self::Y_NS }
314
315 pub const fn is_year_day(&self) -> bool { Self::IS_YEAR_DAY }
317 pub const fn is_hour_sec(&self) -> bool { Self::IS_HOUR_SEC }
319 pub const fn is_milli_nano(&self) -> bool { Self::IS_MILLI_NANO }
321
322 pub const fn is_year_sec(&self) -> bool { Self::IS_YEAR_SEC }
324 pub const fn is_hour_nano(&self) -> bool { Self::IS_HOUR_NANO }
326
327 pub const fn is_year_nano(&self) -> bool { Self::IS_YEAR_NANO }
329}
330
331#[rustfmt::skip]
332#[allow(clippy::if_then_some_else_none)]
333impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
334 pub fn as_tuple(self) -> (Y, MO, D, H, M, S, MS, US, NS) {
336 (self.y, self.mo, self.d, self.h, self.m, self.s, self.ms, self.us, self.ns)
337 }
338 pub const fn to_tuple(&self) -> (Y, MO, D, H, M, S, MS, US, NS)
340 where Y: Copy, MO: Copy, D: Copy, H: Copy, M: Copy, S: Copy, MS: Copy, US: Copy, NS: Copy {
341 (self.y, self.mo, self.d, self.h, self.m, self.s, self.ms, self.us, self.ns)
342 }
343
344 pub fn as_tuple_y_d(self) -> Option<(Y, MO, D)> {
346 if self.has_y_d() { Some((self.y, self.mo, self.d)) } else { None }
347 }
348 pub const fn to_tuple_y_d(&self) -> Option<(Y, MO, D)>
350 where Y: Copy, MO: Copy, D: Copy {
351 if self.has_y_d() { Some((self.y, self.mo, self.d)) } else { None }
352 }
353
354 pub fn as_tuple_h_s(self) -> Option<(H, M, S)> {
356 if self.has_h_s() { Some((self.h, self.m, self.s)) } else { None }
357 }
358 pub const fn to_tuple_h_s(&self) -> Option<(H, M, S)>
360 where H: Copy, M: Copy, S: Copy {
361 if self.has_h_s() { Some((self.h, self.m, self.s)) } else { None }
362 }
363
364 pub fn as_tuple_ms_ns(self) -> Option<(MS, US, NS)> {
366 if self.has_ms_ns() { Some((self.ms, self.us, self.ns)) } else { None }
367 }
368 pub const fn to_tuple_ms_ns(&self) -> Option<(MS, US, NS)>
370 where MS: Copy, US: Copy, NS: Copy {
371 if self.has_ms_ns() { Some((self.ms, self.us, self.ns)) } else { None }
372 }
373
374 pub fn as_tuple_y_s(self) -> Option<(Y, MO, D, H, M, S)> {
376 if self.has_y_s() { Some((self.y, self.mo, self.d, self.h, self.m, self.s)) } else { None }
377 }
378 pub const fn to_tuple_y_s(&self) -> Option<(Y, MO, D, H, M, S)>
380 where Y: Copy, MO: Copy, D: Copy, H: Copy, M: Copy, S: Copy {
381 if self.has_y_s() { Some((self.y, self.mo, self.d, self.h, self.m, self.s)) } else { None }
382 }
383
384 pub fn as_tuple_h_ns(self) -> Option<(H, M, S, MS, US, NS)> {
386 if self.has_h_ns() { Some((self.h, self.m, self.s, self.ms, self.us, self.ns))
387 } else { None }
388 }
389 pub const fn to_tuple_h_ns(&self) -> Option<(H, M, S, MS, US, NS)>
391 where H: Copy, M: Copy, S: Copy, MS: Copy, US: Copy, NS: Copy {
392 if self.has_h_ns() { Some((self.h, self.m, self.s, self.ms, self.us, self.ns))
393 } else { None }
394 }
395
396 #[allow(clippy::type_complexity)]
398 pub fn as_tuple_y_ns(self) -> Option<(Y, MO, D, H, M, S, MS, US, NS)> {
399 if self.has_y_ns() {
400 Some((self.y, self.mo, self.d, self.h, self.m, self.s, self.ms, self.us, self.ns))
401 } else { None }
402 }
403 #[allow(clippy::type_complexity)]
405 pub const fn to_tuple_y_ns(&self) -> Option<(Y, MO, D, H, M, S, MS, US, NS)>
406 where Y: Copy, MO: Copy, D: Copy, H: Copy, M: Copy, S: Copy, MS: Copy, US: Copy, NS: Copy {
407 if self.has_y_ns() {
408 Some((self.y, self.mo, self.d, self.h, self.m, self.s, self.ms, self.us, self.ns))
409 } else { None }
410 }
411}
412
413#[rustfmt::skip]
414impl<Y, MO, D, H, M, S, MS, US, NS> fmt::Debug for TimeSplit<Y, MO, D, H, M, S, MS, US, NS>
415where
416 Y: 'static + fmt::Debug, MO: 'static + fmt::Debug, D: 'static + fmt::Debug,
417 H: 'static + fmt::Debug, M: 'static + fmt::Debug, S: 'static + fmt::Debug,
418 MS: 'static + fmt::Debug, US: 'static + fmt::Debug, NS: 'static + fmt::Debug,
419{
420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421 let notime = ().type_of();
422 let mut debug_struct = f.debug_struct("TimeSplit");
423 if Y::type_id() != notime { debug_struct.field("y", &self.mo); }
424 if MO::type_id() != notime { debug_struct.field("mo", &self.mo); }
425 if D::type_id() != notime { debug_struct.field("d", &self.d); }
426 if H::type_id() != notime { debug_struct.field("h", &self.h); }
427 if M::type_id() != notime { debug_struct.field("m", &self.m); }
428 if S::type_id() != notime { debug_struct.field("s", &self.s); }
429 if MS::type_id() != notime { debug_struct.field("ms", &self.ms); }
430 if US::type_id() != notime { debug_struct.field("us", &self.us); }
431 if NS::type_id() != notime { debug_struct.field("ns", &self.ns); }
432 debug_struct.finish()
433 }
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439 use crate::format_buf;
440
441 #[test]
442 fn split_debug() {
443 let mut buf = [0; 32];
444 let _str = format_buf![&mut buf, "{:?}", TimeSplit::new_hour_sec(1, 2, 3)].unwrap();
445 assert_eq!["TimeSplit { h: 1, m: 2, s: 3 }", _str];
446 }
447
448 #[test]
449 fn split_size() {
450 assert_eq!(0, size_of::<TimeSplit<(), (), (), (), (), (), (), (), ()>>());
451
452 assert_eq!(24, size_of::<TimeSplitNorm>()); assert_eq!(16, size_of::<TimeSplitYearDayNorm>()); assert_eq![16, size_of::<TimeSplitHourSecNorm>()]; assert_eq![6, size_of::<TimeSplitMilliNanoNorm>()]; assert_eq!(16, size_of::<TimeSplitYearSecNorm>()); assert_eq!(16, size_of::<TimeSplitHourNanoNorm>()); }
461}