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) -> fmt::Result {
write!(f, "RFC 3339 input too short: {len} bytes")
}
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,
) -> fmt::Result {
write!(f, "{field} {value} out of range {min}..={max}")
}
fn fmt_fraction_width(f: &mut fmt::Formatter<'_>, digits: usize) -> fmt::Result {
write!(f, "fractional seconds width {digits} out of range 1..=9")
}
fn fmt_missing_offset(f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "missing timezone offset ('Z' or '+-HH:MM')")
}
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),
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),
Self::FractionWidth { digits, at: _ } => fmt_fraction_width(f, *digits),
Self::MissingOffset { at: _ } => fmt_missing_offset(f),
}
}
}
impl Error for ParseError {}