use crate::{Duration, ExtAny, _core::fmt};
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
pub y: Y,
pub mo: MO,
pub d: D,
pub h: H,
pub m: M,
pub s: S,
pub ms: MS,
pub us: US,
pub ns: NS,
}
pub type TimeSplitNorm = TimeSplit<u64, u8, u8, u8, u8, u8, u16, u16, u16>;
pub type TimeSplitYearDay<Y, MO, D> = TimeSplit<Y, MO, D, (), (), (), (), (), ()>;
pub type TimeSplitYearDayNorm = TimeSplit<u64, u8, u8, (), (), (), (), (), ()>;
pub type TimeSplitYearSec<Y, MO, D, H, M, S> = TimeSplit<Y, MO, D, H, M, S, (), (), ()>;
pub type TimeSplitYearSecNorm = TimeSplit<u64, u8, u8, u8, u8, u8, (), (), ()>;
pub type TimeSplitHourSec<H, M, S> = TimeSplit<(), (), (), H, M, S, (), (), ()>;
pub type TimeSplitHourSecNorm = TimeSplit<(), (), (), u64, u8, u8, (), (), ()>;
pub type TimeSplitHourNano<H, M, S, MS, US, NS> = TimeSplit<(), (), (), H, M, S, MS, US, NS>;
pub type TimeSplitHourNanoNorm = TimeSplit<(), (), (), u64, u8, u8, u16, u16, u16>;
pub type TimeSplitMilliNano<MS, US, NS> = TimeSplit<(), (), (), (), (), (), MS, US, NS>;
pub type TimeSplitMilliNanoNorm = TimeSplit<(), (), (), (), (), (), u16, u16, u16>;
impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
#[allow(clippy::too_many_arguments)]
pub const fn new(y: Y, mo: MO, d: D, h: H, m: M, s: S, ms: MS, us: US, ns: NS) -> Self {
Self { y, mo, d, h, m, s, ms, us, ns }
}
}
impl TimeSplitNorm {
pub const fn from_duration(duration: Duration) -> Self {
let secs = duration.as_secs();
let total_days = secs / 86400;
let y = total_days / 365;
let days_remaining = total_days % 365;
let mo = (days_remaining / 30) as u8;
let d = (days_remaining % 30) as u8;
let h = ((secs % 86400) / 3600) as u8;
let m = ((secs % 3600) / 60) as u8;
let s = (secs % 60) as u8;
let nanos = duration.subsec_nanos();
let ms = (nanos / 1_000_000) as u16;
let us = ((nanos % 1_000_000) / 1_000) as u16;
let ns = (nanos % 1_000) as u16;
TimeSplit { y, mo, d, h, m, s, ms, us, ns }
}
}
impl<Y, MO, D> TimeSplitYearDay<Y, MO, D> {
pub const fn new_year_day(y: Y, mo: MO, d: D) -> Self {
Self::new(y, mo, d, (), (), (), (), (), ())
}
}
impl TimeSplitYearDayNorm {
pub const fn from_duration(duration: Duration) -> Self {
let days = duration.as_secs() / 86400;
let y = days / 365;
let days_rem = days % 365;
let mo = (days_rem / 30) as u8;
let d = (days_rem % 30) as u8;
Self::new_year_day(y, mo, d)
}
}
impl<Y, MO, D, H, M, S> TimeSplitYearSec<Y, MO, D, H, M, S> {
pub const fn new_year_sec(y: Y, mo: MO, d: D, h: H, m: M, s: S) -> Self {
Self::new(y, mo, d, h, m, s, (), (), ())
}
}
impl TimeSplitYearSecNorm {
pub const fn from_duration(duration: Duration) -> Self {
let secs = duration.as_secs();
let total_days = secs / 86400;
let y = total_days / 365;
let days_remaining = total_days % 365;
let mo = (days_remaining / 30) as u8;
let d = (days_remaining % 30) as u8;
let h = ((secs % 86400) / 3600) as u8;
let m = ((secs % 3600) / 60) as u8;
let s = (secs % 60) as u8;
Self::new_year_sec(y, mo, d, h, m, s)
}
}
impl<H, M, S> TimeSplitHourSec<H, M, S> {
pub const fn new_hour_sec(h: H, m: M, s: S) -> Self {
Self::new((), (), (), h, m, s, (), (), ())
}
}
impl TimeSplitHourSecNorm {
pub const fn from_duration(duration: Duration) -> Self {
let secs = duration.as_secs();
let h = secs / 3600;
let m = ((secs % 3600) / 60) as u8;
let s = (secs % 60) as u8;
Self::new_hour_sec(h, m, s)
}
}
impl<MS, US, NS> TimeSplitMilliNano<MS, US, NS> {
pub const fn new_milli_nano(ms: MS, us: US, ns: NS) -> Self {
Self::new((), (), (), (), (), (), ms, us, ns)
}
}
impl TimeSplitMilliNanoNorm {
pub const fn from_duration(duration: Duration) -> Self {
let nanos = duration.subsec_nanos();
let ms = (nanos / 1_000_000) as u16;
let us = ((nanos % 1_000_000) / 1_000) as u16;
let ns = (nanos % 1_000) as u16;
Self::new_milli_nano(ms, us, ns)
}
}
impl<H, M, S, MS, US, NS> TimeSplitHourNano<H, M, S, MS, US, NS> {
pub const fn new_hour_nano(h: H, m: M, s: S, ms: MS, us: US, ns: NS) -> Self {
Self::new((), (), (), h, m, s, ms, us, ns)
}
}
impl TimeSplitHourNano<u64, u8, u8, u16, u16, u16> {
pub const fn from_duration(duration: Duration) -> Self {
let secs = duration.as_secs();
let h = (secs % 86400) / 3600;
let m = ((secs % 3600) / 60) as u8;
let s = (secs % 60) as u8;
let nanos = duration.subsec_nanos();
let ms = (nanos / 1_000_000) as u16;
let us = ((nanos % 1_000_000) / 1_000) as u16;
let ns = (nanos % 1_000) as u16;
Self::new_hour_nano(h, m, s, ms, us, ns)
}
}
impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
pub const Y: bool = size_of::<Y>() != 0;
pub const MO: bool = size_of::<MO>() != 0;
pub const D: bool = size_of::<D>() != 0;
pub const H: bool = size_of::<H>() != 0;
pub const M: bool = size_of::<M>() != 0;
pub const S: bool = size_of::<S>() != 0;
pub const MS: bool = size_of::<MS>() != 0;
pub const US: bool = size_of::<US>() != 0;
pub const NS: bool = size_of::<NS>() != 0;
pub const Y_D: bool = Self::Y && Self::MO && Self::D;
pub const H_S: bool = Self::H && Self::M && Self::S;
pub const MS_NS: bool = Self::MS && Self::US && Self::NS;
pub const Y_S: bool = Self::Y_D && Self::H_S;
pub const H_NS: bool = Self::H_S && Self::MS_NS;
pub const Y_NS: bool = Self::Y_D && Self::H_S && Self::MS_NS;
pub const IS_YEAR_DAY: bool = Self::Y_D && !Self::H_NS;
pub const IS_HOUR_SEC: bool = Self::H_S && !Self::Y_D && !Self::MS_NS;
pub const IS_MILLI_NANO: bool = Self::MS_NS && !Self::Y_S;
pub const IS_YEAR_SEC: bool = Self::Y_S && !Self::MS_NS;
pub const IS_HOUR_NANO: bool = Self::H_NS && !Self::Y_D;
pub const IS_YEAR_NANO: bool = Self::Y_NS;
}
#[rustfmt::skip]
impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
pub const fn has_y(&self) -> bool { Self::Y }
pub const fn has_mo(&self) -> bool { Self::MO }
pub const fn has_d(&self) -> bool { Self::D }
pub const fn has_h(&self) -> bool { Self::H }
pub const fn has_s(&self) -> bool { Self::S }
pub const fn has_ms(&self) -> bool { Self::MS }
pub const fn has_us(&self) -> bool { Self::US }
pub const fn has_ns(&self) -> bool { Self::NS }
pub const fn has_y_d(&self) -> bool { Self::Y_D }
pub const fn has_h_s(&self) -> bool { Self::H_S }
pub const fn has_ms_ns(&self) -> bool { Self::MS_NS }
pub const fn has_y_s(&self) -> bool { Self::Y_S }
pub const fn has_h_ns(&self) -> bool { Self::H_NS }
pub const fn has_y_ns(&self) -> bool { Self::Y_NS }
pub const fn is_year_day(&self) -> bool { Self::IS_YEAR_DAY }
pub const fn is_hour_sec(&self) -> bool { Self::IS_HOUR_SEC }
pub const fn is_milli_nano(&self) -> bool { Self::IS_MILLI_NANO }
pub const fn is_year_sec(&self) -> bool { Self::IS_YEAR_SEC }
pub const fn is_hour_nano(&self) -> bool { Self::IS_HOUR_NANO }
pub const fn is_year_nano(&self) -> bool { Self::IS_YEAR_NANO }
}
#[rustfmt::skip]
#[allow(clippy::if_then_some_else_none)]
impl<Y, MO, D, H, M, S, MS, US, NS> TimeSplit<Y, MO, D, H, M, S, MS, US, NS> {
pub fn as_tuple(self) -> (Y, MO, D, H, M, S, MS, US, NS) {
(self.y, self.mo, self.d, self.h, self.m, self.s, self.ms, self.us, self.ns)
}
pub const fn to_tuple(&self) -> (Y, MO, D, H, M, S, MS, US, NS)
where Y: Copy, MO: Copy, D: Copy, H: Copy, M: Copy, S: Copy, MS: Copy, US: Copy, NS: Copy {
(self.y, self.mo, self.d, self.h, self.m, self.s, self.ms, self.us, self.ns)
}
pub fn as_tuple_y_d(self) -> Option<(Y, MO, D)> {
if self.has_y_d() { Some((self.y, self.mo, self.d)) } else { None }
}
pub const fn to_tuple_y_d(&self) -> Option<(Y, MO, D)>
where Y: Copy, MO: Copy, D: Copy {
if self.has_y_d() { Some((self.y, self.mo, self.d)) } else { None }
}
pub fn as_tuple_h_s(self) -> Option<(H, M, S)> {
if self.has_h_s() { Some((self.h, self.m, self.s)) } else { None }
}
pub const fn to_tuple_h_s(&self) -> Option<(H, M, S)>
where H: Copy, M: Copy, S: Copy {
if self.has_h_s() { Some((self.h, self.m, self.s)) } else { None }
}
pub fn as_tuple_ms_ns(self) -> Option<(MS, US, NS)> {
if self.has_ms_ns() { Some((self.ms, self.us, self.ns)) } else { None }
}
pub const fn to_tuple_ms_ns(&self) -> Option<(MS, US, NS)>
where MS: Copy, US: Copy, NS: Copy {
if self.has_ms_ns() { Some((self.ms, self.us, self.ns)) } else { None }
}
pub fn as_tuple_y_s(self) -> Option<(Y, MO, D, H, M, S)> {
if self.has_y_s() { Some((self.y, self.mo, self.d, self.h, self.m, self.s)) } else { None }
}
pub const fn to_tuple_y_s(&self) -> Option<(Y, MO, D, H, M, S)>
where Y: Copy, MO: Copy, D: Copy, H: Copy, M: Copy, S: Copy {
if self.has_y_s() { Some((self.y, self.mo, self.d, self.h, self.m, self.s)) } else { None }
}
pub fn as_tuple_h_ns(self) -> Option<(H, M, S, MS, US, NS)> {
if self.has_h_ns() { Some((self.h, self.m, self.s, self.ms, self.us, self.ns))
} else { None }
}
pub const fn to_tuple_h_ns(&self) -> Option<(H, M, S, MS, US, NS)>
where H: Copy, M: Copy, S: Copy, MS: Copy, US: Copy, NS: Copy {
if self.has_h_ns() { Some((self.h, self.m, self.s, self.ms, self.us, self.ns))
} else { None }
}
#[allow(clippy::type_complexity)]
pub fn as_tuple_y_ns(self) -> Option<(Y, MO, D, H, M, S, MS, US, NS)> {
if self.has_y_ns() {
Some((self.y, self.mo, self.d, self.h, self.m, self.s, self.ms, self.us, self.ns))
} else { None }
}
#[allow(clippy::type_complexity)]
pub const fn to_tuple_y_ns(&self) -> Option<(Y, MO, D, H, M, S, MS, US, NS)>
where Y: Copy, MO: Copy, D: Copy, H: Copy, M: Copy, S: Copy, MS: Copy, US: Copy, NS: Copy {
if self.has_y_ns() {
Some((self.y, self.mo, self.d, self.h, self.m, self.s, self.ms, self.us, self.ns))
} else { None }
}
}
#[rustfmt::skip]
impl<Y, MO, D, H, M, S, MS, US, NS> fmt::Debug for TimeSplit<Y, MO, D, H, M, S, MS, US, NS>
where
Y: 'static + fmt::Debug, MO: 'static + fmt::Debug, D: 'static + fmt::Debug,
H: 'static + fmt::Debug, M: 'static + fmt::Debug, S: 'static + fmt::Debug,
MS: 'static + fmt::Debug, US: 'static + fmt::Debug, NS: 'static + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let notime = ().type_of();
let mut debug_struct = f.debug_struct("TimeSplit");
if Y::type_id() != notime { debug_struct.field("y", &self.mo); }
if MO::type_id() != notime { debug_struct.field("mo", &self.mo); }
if D::type_id() != notime { debug_struct.field("d", &self.d); }
if H::type_id() != notime { debug_struct.field("h", &self.h); }
if M::type_id() != notime { debug_struct.field("m", &self.m); }
if S::type_id() != notime { debug_struct.field("s", &self.s); }
if MS::type_id() != notime { debug_struct.field("ms", &self.ms); }
if US::type_id() != notime { debug_struct.field("us", &self.us); }
if NS::type_id() != notime { debug_struct.field("ns", &self.ns); }
debug_struct.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::format_buf;
#[test]
fn split_debug() {
let mut buf = [0; 32];
let _str = format_buf![&mut buf, "{:?}", TimeSplit::new_hour_sec(1, 2, 3)].unwrap();
assert_eq!["TimeSplit { h: 1, m: 2, s: 3 }", _str];
}
#[test]
fn split_size() {
assert_eq!(0, size_of::<TimeSplit<(), (), (), (), (), (), (), (), ()>>());
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>()); }
}