devela/phys/time/
split.rs

1// devela::phys::time::split
2//
3//! Splitting and decomposing time.
4//
5// IDEAS
6// - … enum Granularity? Seconds, Millis, Nanos?
7// - less types (now 6) and integrate using () more commonly?
8//   - will have to CHECK for downsides and UNDERSTAND DESIGNS
9//
10// TODO
11// - normalize fn
12//
13// - differentiate between normalized saturated and overflowing
14//   e.g. u64,u8,u8 vs u8,u8,u8
15//
16// - [ ] methods to construct duration from? to_duration
17// - generic conversion to standard form?
18//   (avoiding monomorphization by nesting non-inline fn into?)
19//
20// - conversion from/to strings
21//
22// - Address scenarios where ms, µs, or ns could sum to more than a second?
23//
24// - support addition, subtraction, scaling.
25//
26// - is_past | future | is_equal
27//
28// - [ ] impl Display (or custom formatter)
29
30use crate::{Duration, ExtAny, _core::fmt};
31
32/// A full time split from years to nanoseconds.
33///
34/// See also the related aliases:
35/// - [`TimeSplitNorm`][TimeSplitNorm],
36///   [`TimeSplitYearDay`]`/`[`Norm`][TimeSplitYearDayNorm],
37///   [`TimeSplitYearSec`]`/`[`Norm`][TimeSplitYearSecNorm],
38///   [`TimeSplitHourSec`]`/`[`Norm`][TimeSplitHourSecNorm],
39///   [`TimeSplitHourNano`]`/`[`Norm`][TimeSplitHourNanoNorm],
40///   [`TimeSplitMilliNano`]`/`[`Norm`][TimeSplitMilliNanoNorm].
41#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
43    /// Years.
44    pub y: Y,
45    /// Months.
46    pub mo: MO,
47    /// Days.
48    pub d: D,
49    /// Hours.
50    pub h: H,
51    /// Minutes.
52    pub m: M,
53    /// Seconds.
54    pub s: S,
55    /// Milliseconds.
56    pub ms: MS,
57    /// Microseconds.
58    pub us: US,
59    /// Nanoseconds.
60    pub ns: NS,
61}
62
63/* aliases */
64
65/// A time split from years to nanoseconds, normalized *(192b size, 152b payload)*.
66pub type TimeSplitNorm = TimeSplit<u64, u8, u8, u8, u8, u8, u16, u16, u16>;
67
68/// A time split from years to days.
69pub type TimeSplitYearDay<Y, MO, D> = TimeSplit<Y, MO, D, (), (), (), (), (), ()>;
70/// A time split from years to days, normalized *(128b size, 80b payload)*.
71pub type TimeSplitYearDayNorm = TimeSplit<u64, u8, u8, (), (), (), (), (), ()>;
72
73/// A time split from years to seconds.
74pub type TimeSplitYearSec<Y, MO, D, H, M, S> = TimeSplit<Y, MO, D, H, M, S, (), (), ()>;
75/// A time split from years to seconds, normalized *(128b size, 104b payload)*.
76pub type TimeSplitYearSecNorm = TimeSplit<u64, u8, u8, u8, u8, u8, (), (), ()>;
77
78/// A time split from hours to seconds.
79pub type TimeSplitHourSec<H, M, S> = TimeSplit<(), (), (), H, M, S, (), (), ()>;
80/// A time split from hours to seconds, normalized *(128b size, 80b payload)*.
81pub type TimeSplitHourSecNorm = TimeSplit<(), (), (), u64, u8, u8, (), (), ()>;
82
83/// A time split from hours to nanoseconds.
84pub type TimeSplitHourNano<H, M, S, MS, US, NS> = TimeSplit<(), (), (), H, M, S, MS, US, NS>;
85/// A time split from hours to seconds, normalized *(128b size & payload)*.
86pub type TimeSplitHourNanoNorm = TimeSplit<(), (), (), u64, u8, u8, u16, u16, u16>;
87
88/// A time split from milliseconds to nanoseconds.
89pub type TimeSplitMilliNano<MS, US, NS> = TimeSplit<(), (), (), (), (), (), MS, US, NS>;
90/// A time split from milliseconds to nanoseconds, normalized *(48b size & payload)*.
91pub type TimeSplitMilliNanoNorm = TimeSplit<(), (), (), (), (), (), u16, u16, u16>;
92
93/* constructors */
94
95impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
96    /// Returns a new [`TimeSplit`].
97    #[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    /// Converts a `Duration` into a full [`TimeSplit`].
104    ///
105    /// It assumes non-leap years and 30-day months for simplicity in calendar calculations.
106    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    /// Returns a new [`TimeSplitYearDay`].
126    pub const fn new_year_day(y: Y, mo: MO, d: D) -> Self {
127        Self::new(y, mo, d, (), (), (), (), (), ())
128    }
129}
130impl TimeSplitYearDayNorm {
131    /// Converts a `Duration` into a [`TimeSplitYearDay`].
132    ///
133    /// This method assumes 365 days per year and 30 days per month for simplicity.
134    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    /// Returns a new [`TimeSplitYearSec`].
146    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    /// Converts a `Duration` into a [`TimeSplitYearSec`].
152    ///
153    /// It assumes non-leap years and 30-day months for simplicity in calendar calculations.
154    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    /// Returns a new [`TimeSplitHourSec`].
170    pub const fn new_hour_sec(h: H, m: M, s: S) -> Self {
171        Self::new((), (), (), h, m, s, (), (), ())
172    }
173}
174impl TimeSplitHourSecNorm {
175    /// Converts a `Duration` into a [`TimeSplitHourSec`].
176    ///
177    /// Excess days or longer periods are converted into additional hours.
178    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    /// Returns a new [`TimeSplitMilliNano`].
189    pub const fn new_milli_nano(ms: MS, us: US, ns: NS) -> Self {
190        Self::new((), (), (), (), (), (), ms, us, ns)
191    }
192}
193impl TimeSplitMilliNanoNorm {
194    /// Converts a `Duration`'s sub-second component into a compact time split representation.
195    ///
196    /// Extracts and segments the nanosecond portion of a `Duration`
197    /// into milliseconds, microseconds, and nanoseconds.
198    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    /// Returns a new `TimeSplitHourNano`.
209    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    /// Converts a `Duration` into a time split representation from Hours down to nanoseconds.
215    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
228/// # Structural introspection
229impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
230    /// Indicates whether the [`y`][Self::y] field is enabled.
231    pub const Y: bool = size_of::<Y>() != 0;
232    /// Indicates whether the [`mo`][Self::mo] field is enabled.
233    pub const MO: bool = size_of::<MO>() != 0;
234    /// Indicates whether the [`d`][Self::d] field is enabled.
235    pub const D: bool = size_of::<D>() != 0;
236    /// Indicates whether the [`h`][Self::h] field is enabled.
237    pub const H: bool = size_of::<H>() != 0;
238    /// Indicates whether the [`m`][Self::m] field is enabled.
239    pub const M: bool = size_of::<M>() != 0;
240    /// Indicates whether the [`s`][Self::s] field is enabled.
241    pub const S: bool = size_of::<S>() != 0;
242    /// Indicates whether the [`ms`][Self::ms] field is enabled.
243    pub const MS: bool = size_of::<MS>() != 0;
244    /// Indicates whether the [`us`][Self::us] field is enabled.
245    pub const US: bool = size_of::<US>() != 0;
246    /// Indicates whether the [`ns`][Self::ns] field is enabled.
247    pub const NS: bool = size_of::<NS>() != 0;
248
249    /// Indicates whether the 3 fields from [`y`][Self::y] to [`d`][Self::d] are enabled.
250    pub const Y_D: bool = Self::Y && Self::MO && Self::D;
251    /// Indicates whether the 3 fields from [`h`][Self::h] to [`s`][Self::s] are enabled.
252    pub const H_S: bool = Self::H && Self::M && Self::S;
253    /// Indicates whether the 3 fields from [`ms`][Self::ms] to [`ns`][Self::ns] are enabled.
254    pub const MS_NS: bool = Self::MS && Self::US && Self::NS;
255
256    /// Indicates whether the 6 fields from [`y`][Self::y] to [`s`][Self::s] are enabled.
257    pub const Y_S: bool = Self::Y_D && Self::H_S;
258    /// Indicates whether the 6 fields from [`h`][Self::h] to [`ns`][Self::ns] are enabled.
259    pub const H_NS: bool = Self::H_S && Self::MS_NS;
260
261    /// Indicates whether all the 9 fields from [`y`][Self::y] to [`ns`][Self::ns] are enabled.
262    pub const Y_NS: bool = Self::Y_D && Self::H_S && Self::MS_NS;
263
264    /// Indicates whether *only* the 3 fields from [`y`][Self::y] to [`d`][Self::d] are enabled.
265    pub const IS_YEAR_DAY: bool = Self::Y_D && !Self::H_NS;
266    /// Indicates whether *only* the 3 fields from [`h`][Self::h] to [`s`][Self::s] are enabled.
267    pub const IS_HOUR_SEC: bool = Self::H_S && !Self::Y_D && !Self::MS_NS;
268    /// Indicates whether the 3 fields from [`ms`][Self::ms] to [`ns`][Self::ns] are enabled.
269    pub const IS_MILLI_NANO: bool = Self::MS_NS && !Self::Y_S;
270
271    /// Indicates whether *only* the 6 fields from [`y`][Self::y] to [`s`][Self::s] are enabled.
272    pub const IS_YEAR_SEC: bool = Self::Y_S && !Self::MS_NS;
273    /// Indicates whether *only* the 6 fields from [`h`][Self::h] to [`ns`][Self::ns] are enabled.
274    pub const IS_HOUR_NANO: bool = Self::H_NS && !Self::Y_D;
275
276    /// Indicates whether all the 9 fields from [`y`][Self::y] to [`ns`][Self::ns] are enabled.
277    pub const IS_YEAR_NANO: bool = Self::Y_NS;
278}
279
280/// # Instance introspection
281#[rustfmt::skip]
282impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
283    /// Indicates whether the [`y`][Self::y] field is enabled.
284    pub const fn has_y(&self) -> bool { Self::Y }
285    /// Indicates whether the [`mo`][Self::mo] field is enabled.
286    pub const fn has_mo(&self) -> bool { Self::MO }
287    /// Indicates whether the [`d`][Self::d] field is enabled.
288    pub const fn has_d(&self) -> bool { Self::D }
289    /// Indicates whether the [`h`][Self::h] field is enabled.
290    pub const fn has_h(&self) -> bool { Self::H }
291    /// Indicates whether the [`s`][Self::s] field is enabled.
292    pub const fn has_s(&self) -> bool { Self::S }
293    /// Indicates whether the [`ms`][Self::ms] field is enabled.
294    pub const fn has_ms(&self) -> bool { Self::MS }
295    /// Indicates whether the [`us`][Self::us] field is enabled.
296    pub const fn has_us(&self) -> bool { Self::US }
297    /// Indicates whether the [`ns`][Self::ns] field is enabled.
298    pub const fn has_ns(&self) -> bool { Self::NS }
299
300    /// Indicates whether the 3 fields from [`y`][Self::y] to [`d`][Self::d] are enabled.
301    pub const fn has_y_d(&self) -> bool { Self::Y_D }
302    /// Indicates whether the 3 fields from [`h`][Self::h] to [`s`][Self::s] are enabled.
303    pub const fn has_h_s(&self) -> bool { Self::H_S }
304    /// Indicates whether the 3 fields from [`ms`][Self::ms] to [`ns`][Self::ns] are enabled.
305    pub const fn has_ms_ns(&self) -> bool { Self::MS_NS }
306
307    /// Indicates whether the 6 fields from [`y`][Self::y] to [`s`][Self::s] are enabled.
308    pub const fn has_y_s(&self) -> bool { Self::Y_S }
309    /// Indicates whether the 6 fields from [`h`][Self::h] to [`ns`][Self::ns] are enabled.
310    pub const fn has_h_ns(&self) -> bool { Self::H_NS }
311
312    /// Indicates whether all the 9 fields from [`y`][Self::y] to [`ns`][Self::ns] are enabled.
313    pub const fn has_y_ns(&self) -> bool { Self::Y_NS }
314
315    /// Indicates whether *only* the 3 fields from [`y`][Self::y] to [`d`][Self::d] are enabled.
316    pub const fn is_year_day(&self) -> bool { Self::IS_YEAR_DAY }
317    /// Indicates whether *only* the 3 fields from [`h`][Self::h] to [`s`][Self::s] are enabled.
318    pub const fn is_hour_sec(&self) -> bool { Self::IS_HOUR_SEC }
319    /// Indicates whether the 3 fields from [`ms`][Self::ms] to [`ns`][Self::ns] are enabled.
320    pub const fn is_milli_nano(&self) -> bool { Self::IS_MILLI_NANO }
321
322    /// Indicates whether *only* the 6 fields from [`y`][Self::y] to [`s`][Self::s] are enabled.
323    pub const fn is_year_sec(&self) -> bool { Self::IS_YEAR_SEC }
324    /// Indicates whether *only* the 6 fields from [`h`][Self::h] to [`ns`][Self::ns] are enabled.
325    pub const fn is_hour_nano(&self) -> bool { Self::IS_HOUR_NANO }
326
327    /// Indicates whether all the 9 fields from [`y`][Self::y] to [`ns`][Self::ns] are enabled.
328    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    /// Returns a (9) tuple with all the elements.
335    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    /// Returns a (9) tuple with all the elements.
339    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    /// Returns a (3) tuple if the 3 fields from [`y`][Self::y] to [`d`][Self::d] are enabled.
345    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    /// Returns a (3) tuple if the 3 fields from [`y`][Self::y] to [`d`][Self::d] are enabled.
349    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    /// Returns a (3) tuple if the 3 fields from [`h`][Self::h] to [`s`][Self::s] are enabled.
355    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    /// Returns a (3) tuple if the 3 fields from [`h`][Self::h] to [`s`][Self::s] are enabled.
359    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    /// Returns a (3) tuple if the 3 fields from [`ms`][Self::ms] to [`ns`][Self::ns] are enabled.
365    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    /// Returns a (3) tuple if the 3 fields from [`ms`][Self::ms] to [`ns`][Self::ns] are enabled.
369    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    /// Returns a (6) tuple if the 6 fields from [`y`][Self::y] to [`s`][Self::s] are enabled.
375    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    /// Returns a (6) tuple if the 6 fields from [`y`][Self::y] to [`s`][Self::s] are enabled.
379    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    /// Returns a (6) tuple if the 6 fields from [`h`][Self::h] to [`ns`][Self::ns] are enabled.
385    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    /// Returns a (6) tuple if the 6 fields from [`h`][Self::h] to [`ns`][Self::ns] are enabled.
390    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    /// Returns a (9) tuple if the 9 fields from [`y`][Self::y] to [`ns`][Self::ns] are enabled.
397    #[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    /// Returns a (9) tuple if the 9 fields from [`y`][Self::y] to [`ns`][Self::ns] are enabled.
404    #[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        /* normalized inner reprs */
453
454        assert_eq!(24, size_of::<TimeSplitNorm>()); // 5 bytes padded
455        assert_eq!(16, size_of::<TimeSplitYearDayNorm>()); // 6 bytes padded
456        assert_eq![16, size_of::<TimeSplitHourSecNorm>()]; // 6 bytes padded
457        assert_eq![6, size_of::<TimeSplitMilliNanoNorm>()]; // 0 padding
458        assert_eq!(16, size_of::<TimeSplitYearSecNorm>()); // 3 bytes padded
459        assert_eq!(16, size_of::<TimeSplitHourNanoNorm>()); // 0 padding
460    }
461}