use std::error::Error;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Field {
Year,
Month,
Day,
Hour,
Minute,
Second,
OffsetHour,
OffsetMinute,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum UnixTimeError {
SecondsOverflow {
seconds: i64,
nanoseconds: u32,
},
SystemTimeOutOfRange {
seconds: i64,
nanoseconds: u32,
},
SystemTimeOutsideI64Range {
before_epoch: bool,
},
}
impl fmt::Display for UnixTimeError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::SecondsOverflow {
seconds,
nanoseconds,
} => write!(
formatter,
"Unix seconds overflow while normalizing ({seconds}, {nanoseconds})"
),
Self::SystemTimeOutOfRange {
seconds,
nanoseconds,
} => write!(
formatter,
"platform SystemTime cannot represent ({seconds}, {nanoseconds})"
),
Self::SystemTimeOutsideI64Range { before_epoch } => write!(
formatter,
"SystemTime {} the epoch is outside the i64 Unix-seconds range",
if before_epoch { "before" } else { "after" }
),
}
}
}
impl Error for UnixTimeError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum FormatError {
UnixTime(UnixTimeError),
YearOutsideRfc3339 {
year: i64,
},
}
impl fmt::Display for FormatError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::UnixTime(error) => write!(formatter, "cannot format instant: {error}"),
Self::YearOutsideRfc3339 { year } => write!(
formatter,
"UTC year {year} is outside RFC 3339's four-digit year range 0000..=9999"
),
}
}
}
impl Error for FormatError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
Self::UnixTime(ref error) => Some(error),
Self::YearOutsideRfc3339 { .. } => None,
}
}
}
fn field_name(field: &Field) -> &'static str {
match *field {
Field::Year => "year",
Field::Month => "month",
Field::Day => "day",
Field::Hour => "hour",
Field::Minute => "minute",
Field::Second => "second",
Field::OffsetHour => "offset-hour",
Field::OffsetMinute => "offset-minute",
}
}
impl fmt::Display for Field {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(field_name(self))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ParseError {
TooShort {
len: usize,
at: usize,
},
Malformed {
at: usize,
byte: u8,
},
NonDigit {
field: Field,
at: usize,
byte: u8,
},
OutOfRange {
field: Field,
value: u32,
min: u32,
max: u32,
at: usize,
},
FractionWidth {
digits: usize,
at: usize,
},
UnsupportedLeapSecond {
at: usize,
},
UnrepresentableInstant(UnixTimeError),
MissingOffset {
at: usize,
},
}
fn fmt_too_short(formatter: &mut fmt::Formatter<'_>, len: usize, at: usize) -> fmt::Result {
write!(
formatter,
"RFC 3339 input too short: {len} bytes (ended at offset {at})"
)
}
fn fmt_malformed(formatter: &mut fmt::Formatter<'_>, at: usize, byte: u8) -> fmt::Result {
write!(formatter, "unexpected character {byte:?} at offset {at}")
}
fn fmt_non_digit(
formatter: &mut fmt::Formatter<'_>,
field: Field,
at: usize,
byte: u8,
) -> fmt::Result {
write!(
formatter,
"non-digit character {byte:?} in {field} at offset {at}"
)
}
fn fmt_out_of_range(
formatter: &mut fmt::Formatter<'_>,
field: Field,
value: u32,
min: u32,
max: u32,
at: usize,
) -> fmt::Result {
write!(
formatter,
"{field} {value} out of range {min}..={max} at offset {at}"
)
}
fn fmt_fraction_width(formatter: &mut fmt::Formatter<'_>, digits: usize, at: usize) -> fmt::Result {
write!(
formatter,
"fractional seconds width {digits} out of range 1..=9 at offset {at}"
)
}
fn fmt_missing_offset(formatter: &mut fmt::Formatter<'_>, at: usize) -> fmt::Result {
write!(
formatter,
"missing timezone offset ('Z' or '+-HH:MM') at offset {at}"
)
}
impl fmt::Display for ParseError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::TooShort { len, at } => fmt_too_short(formatter, len, at),
Self::Malformed { at, byte } => fmt_malformed(formatter, at, byte),
Self::NonDigit { field, at, byte } => fmt_non_digit(formatter, field, at, byte),
Self::OutOfRange {
field,
value,
min,
max,
at,
} => fmt_out_of_range(formatter, field, value, min, max, at),
Self::FractionWidth { digits, at } => fmt_fraction_width(formatter, digits, at),
Self::UnsupportedLeapSecond { at } => write!(
formatter,
"leap second is unsupported by the SystemTime profile at offset {at}"
),
Self::UnrepresentableInstant(error) => {
write!(formatter, "parsed instant is not representable: {error}")
}
Self::MissingOffset { at } => fmt_missing_offset(formatter, at),
}
}
}
impl Error for ParseError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
Self::UnrepresentableInstant(ref error) => Some(error),
_ => None,
}
}
}