use std::error::Error;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Field {
Year,
Month,
Day,
Hour,
Minute,
Second,
OffsetHour,
OffsetMinute,
}
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)]
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,
},
MissingOffset {
at: usize,
},
}
fn fmt_too_short(f: &mut fmt::Formatter<'_>, len: usize, at: usize) -> fmt::Result {
write!(
f,
"RFC 3339 input too short: {len} bytes (ended at offset {at})"
)
}
fn fmt_malformed(f: &mut fmt::Formatter<'_>, at: usize, byte: u8) -> fmt::Result {
write!(f, "unexpected character {byte:?} at offset {at}")
}
fn fmt_non_digit(f: &mut fmt::Formatter<'_>, field: Field, at: usize, byte: u8) -> fmt::Result {
write!(f, "non-digit character {byte:?} in {field} at offset {at}")
}
fn fmt_out_of_range(
f: &mut fmt::Formatter<'_>,
field: Field,
value: u32,
min: u32,
max: u32,
at: usize,
) -> fmt::Result {
write!(
f,
"{field} {value} out of range {min}..={max} at offset {at}"
)
}
fn fmt_fraction_width(f: &mut fmt::Formatter<'_>, digits: usize, at: usize) -> fmt::Result {
write!(
f,
"fractional seconds width {digits} out of range 1..=9 at offset {at}"
)
}
fn fmt_missing_offset(f: &mut fmt::Formatter<'_>, at: usize) -> fmt::Result {
write!(
f,
"missing timezone offset ('Z' or '+-HH:MM') at offset {at}"
)
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TooShort { len, at } => fmt_too_short(f, *len, *at),
Self::Malformed { at, byte } => fmt_malformed(f, *at, *byte),
Self::NonDigit { field, at, byte } => fmt_non_digit(f, *field, *at, *byte),
Self::OutOfRange {
field,
value,
min,
max,
at,
} => fmt_out_of_range(f, *field, *value, *min, *max, *at),
Self::FractionWidth { digits, at } => fmt_fraction_width(f, *digits, *at),
Self::MissingOffset { at } => fmt_missing_offset(f, *at),
}
}
}
impl Error for ParseError {}