use time::Time; use crate::error::{PartialVariant, TryFromPartial}; use crate::partial::Partial; /// An [`PartTime`] struct represents a partial [`Time`] struct. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct PartTime { hour: Option, minute: Option, second: Option, nanosecond: Option, } impl PartTime { /// Attempts to create a [`PartTime`] from the hour, minute, and second. pub fn from_hms( hour: Option, minute: Option, second: Option, ) -> Result { Self::from_hms_nano(hour, minute, second, Some(0)) } /// Attempts to create a [`PartTime`] from the hour, minute, second, and millisecond. pub fn from_hms_milli( hour: Option, minute: Option, second: Option, millisecond: Option, ) -> Result { let nanosecond = millisecond.map(|ms| ms as u32 * 1_000_000); Self::from_hms_nano(hour, minute, second, nanosecond) } /// Attempt to create a [`PartTime`] from the hour, minute, second, and microsecond. pub fn from_hms_micro( hour: Option, minute: Option, second: Option, microsecond: Option, ) -> Result { let nanosecond = microsecond.map(|ms| ms * 1_000); Self::from_hms_nano(hour, minute, second, nanosecond) } /// Attempt to create a [`PartTime`] from the hour, minute, second, and nanosecond. pub fn from_hms_nano( hour: Option, minute: Option, second: Option, nanosecond: Option, ) -> Result { // TODO: Soundness. Ok(Self::from_hms_nano_unchecked( hour, minute, second, nanosecond, )) } /// Creates a [`PartTime`] from its components. fn from_hms_nano_unchecked( hour: Option, minute: Option, second: Option, nanosecond: Option, ) -> Self { Self { hour, minute, second, nanosecond, } } /// Returns the clock hour. pub fn hour(self) -> Option { self.hour } /// Returns the minute within the hour. pub fn minute(self) -> Option { self.minute } /// Returns the second within the minute. pub fn second(self) -> Option { self.second } /// Returns the milliseconds within the second. pub fn millisecond(self) -> Option { self.nanosecond.map(|ns| (ns / 1_000_000) as _) } /// Returns the microseconds within the second. pub fn microsecond(self) -> Option { self.nanosecond.map(|ns| (ns / 1_000) as _) } /// Returns the nanoseconds within the second. pub fn nanosecond(self) -> Option { self.nanosecond } /// Replaces the clock hour. pub fn replace_hour(self, hour: Option) -> Result { Self::from_hms_nano(hour, self.minute, self.minute, self.nanosecond) } /// Replaces the minutes within the hour. pub fn replace_minute(self, minute: Option) -> Result { Self::from_hms_nano(self.hour, minute, self.minute, self.nanosecond) } /// Replaces the seconds within the minute. pub fn replace_second(self, second: Option) -> Result { Self::from_hms_nano(self.hour, self.minute, second, self.nanosecond) } /// Replaces the milliseconds within the second. pub fn replace_millisecond(self, millisecond: Option) -> Result { Self::from_hms_milli(self.hour, self.minute, self.minute, millisecond) } /// Replaces the microseconds within the second. pub fn replace_microsecond(self, microsecond: Option) -> Result { Self::from_hms_micro(self.hour, self.minute, self.minute, microsecond) } /// Replaces the nanoseconds within the second. pub fn replace_nanosecond(self, nanosecond: Option) -> Result { Self::from_hms_nano(self.hour, self.minute, self.minute, nanosecond) } } impl Partial for PartTime { type Complete = Time; fn from_complete(complete: Self::Complete) -> Self { let h = Some(complete.hour()); let m = Some(complete.minute()); let s = Some(complete.second()); let n = Some(complete.nanosecond()); Self::from_hms_nano_unchecked(h, m, s, n) } fn into_complete(self) -> Result { let f = |name: &'static str| -> TryFromPartial { PartialVariant::new(name).into() }; let h = self.hour().ok_or_else(|| f("hour"))?; let m = self.minute().ok_or_else(|| f("minute"))?; let s = self.second().ok_or_else(|| f("second"))?; let n = self.nanosecond().ok_or_else(|| f("nanosecond"))?; let time = Self::Complete::from_hms_nano(h, m, s, n); time.map_err(|e| e.into()) } fn with_fallback(self, fallback: Self::Complete) -> Result { let h = Some(self.hour.unwrap_or(fallback.hour())); let m = Some(self.minute.unwrap_or(fallback.minute())); let s = Some(self.second.unwrap_or(fallback.second())); let n = Some(self.nanosecond.unwrap_or(fallback.nanosecond())); Self::from_hms_nano(h, m, s, n) } } impl From