use core::num::NonZeroU8;
use crate::encoding::EncodingType;
#[non_exhaustive]
#[derive(Default, Debug, PartialEq)]
pub struct IxdtfParseRecord<'a, T: EncodingType> {
pub date: Option<DateRecord>,
pub time: Option<TimeRecord>,
pub offset: Option<UtcOffsetRecordOrZ>,
pub tz: Option<TimeZoneAnnotation<'a, T>>,
pub calendar: Option<&'a [T::CodeUnit]>,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub struct Annotation<'a, T: EncodingType> {
pub critical: bool,
pub key: &'a [T::CodeUnit],
pub value: &'a [T::CodeUnit],
}
#[allow(clippy::exhaustive_structs)] #[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct DateRecord {
pub year: i32,
pub month: u8,
pub day: u8,
}
#[allow(clippy::exhaustive_structs)] #[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct TimeRecord {
pub hour: u8,
pub minute: u8,
pub second: u8,
pub fraction: Option<Fraction>,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub struct TimeZoneAnnotation<'a, T: EncodingType> {
pub critical: bool,
pub tz: TimeZoneRecord<'a, T>,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub enum TimeZoneRecord<'a, T: EncodingType> {
Name(&'a [T::CodeUnit]),
Offset(MinutePrecisionOffset),
}
#[repr(i8)]
#[allow(clippy::exhaustive_enums)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum Sign {
Negative = -1,
Positive = 1,
}
impl From<bool> for Sign {
fn from(value: bool) -> Self {
match value {
true => Self::Positive,
false => Self::Negative,
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum UtcOffsetRecord {
MinutePrecision(MinutePrecisionOffset),
FullPrecisionOffset(FullPrecisionOffset),
}
impl UtcOffsetRecord {
pub fn is_minute_precision(&self) -> bool {
matches!(self, Self::MinutePrecision(_))
}
pub fn zero() -> Self {
Self::MinutePrecision(MinutePrecisionOffset::zero())
}
pub fn sign(&self) -> Sign {
match self {
Self::MinutePrecision(offset) => offset.sign,
Self::FullPrecisionOffset(offset) => offset.minute_precision_offset.sign,
}
}
pub fn hour(&self) -> u8 {
match self {
Self::MinutePrecision(offset) => offset.hour,
Self::FullPrecisionOffset(offset) => offset.minute_precision_offset.hour,
}
}
pub fn minute(&self) -> u8 {
match self {
Self::MinutePrecision(offset) => offset.minute,
Self::FullPrecisionOffset(offset) => offset.minute_precision_offset.minute,
}
}
pub fn second(&self) -> Option<u8> {
match self {
Self::MinutePrecision(_) => None,
Self::FullPrecisionOffset(offset) => Some(offset.second),
}
}
pub fn fraction(&self) -> Option<Fraction> {
match self {
Self::MinutePrecision(_) => None,
Self::FullPrecisionOffset(offset) => offset.fraction,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(clippy::exhaustive_structs)] pub struct MinutePrecisionOffset {
pub sign: Sign,
pub hour: u8,
pub minute: u8,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(clippy::exhaustive_structs)] pub struct FullPrecisionOffset {
pub minute_precision_offset: MinutePrecisionOffset,
pub second: u8,
pub fraction: Option<Fraction>,
}
impl MinutePrecisionOffset {
pub const fn zero() -> Self {
Self {
sign: Sign::Positive,
hour: 0,
minute: 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(clippy::exhaustive_enums)] pub enum UtcOffsetRecordOrZ {
Offset(UtcOffsetRecord),
Z,
}
impl UtcOffsetRecordOrZ {
pub fn resolve_rfc_9557(self) -> UtcOffsetRecord {
match self {
UtcOffsetRecordOrZ::Offset(o) => o,
UtcOffsetRecordOrZ::Z => UtcOffsetRecord::MinutePrecision(MinutePrecisionOffset {
sign: Sign::Negative,
hour: 0,
minute: 0,
}),
}
}
}
#[allow(clippy::exhaustive_structs)]
#[cfg(feature = "duration")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DurationParseRecord {
pub sign: Sign,
pub date: Option<DateDurationRecord>,
pub time: Option<TimeDurationRecord>,
}
#[allow(clippy::exhaustive_structs)]
#[cfg(feature = "duration")]
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct DateDurationRecord {
pub years: u32,
pub months: u32,
pub weeks: u32,
pub days: u64,
}
#[allow(clippy::exhaustive_enums)]
#[cfg(feature = "duration")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TimeDurationRecord {
Hours {
hours: u64,
fraction: Option<Fraction>,
},
Minutes {
hours: u64,
minutes: u64,
fraction: Option<Fraction>,
},
Seconds {
hours: u64,
minutes: u64,
seconds: u64,
fraction: Option<Fraction>,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(clippy::exhaustive_structs)] pub struct Fraction {
pub(crate) digits: NonZeroU8,
pub(crate) value: u64,
}
impl Fraction {
pub fn to_nanoseconds(&self) -> Option<u32> {
if self.digits.get() <= 9 {
Some(10u32.pow(9 - u32::from(self.digits.get())) * (self.value as u32))
} else {
None
}
}
pub fn to_truncated_nanoseconds(&self) -> u32 {
self.to_nanoseconds()
.unwrap_or_else(|| (self.value / 10u64.pow(u32::from(self.digits.get() - 9))) as u32)
}
}