Skip to content

Commit

Permalink
Make weekday optional in RFC2822
Browse files Browse the repository at this point in the history
  • Loading branch information
jhpratt committed Feb 23, 2024
1 parent 4991a89 commit 7a6a800
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 31 deletions.
35 changes: 17 additions & 18 deletions tests/parsing.rs
Expand Up @@ -114,32 +114,31 @@ fn rfc_2822() -> time::Result<()> {
Ok(())
}

#[test]
fn issue_661() -> time::Result<()> {
assert_eq!(
OffsetDateTime::parse("02 Jan 2021 03:04:05 +0607", &Rfc2822)?,
datetime!(2021-01-02 03:04:05 +06:07),
);
assert_eq!(
Date::parse("02 Jan 2021 03:04:05 +0607", &Rfc2822)?,
date!(2021 - 01 - 02)
);

Ok(())
}

#[allow(clippy::cognitive_complexity)] // all test the same thing
#[test]
fn rfc_2822_err() {
// In the first test, the "weekday" component is invalid, we're actually testing the whitespace
// parser. The error is because the parser attempts and fails to parse the whitespace, but it's
// optional so it backtracks and attempts to parse the weekday (while still having leading
// whitespace), thus failing.
// whitespace). The weekday is also optional, so it backtracks and attempts to parse the day.
// This component is required, so it fails at this point.
assert!(matches!(
OffsetDateTime::parse(" \r\nM", &Rfc2822),
invalid_component!("weekday")
));
assert!(matches!(
OffsetDateTime::parse("Mon,(\u{0}", &Rfc2822),
invalid_literal!()
));
assert!(matches!(
OffsetDateTime::parse("Mon,(", &Rfc2822),
invalid_literal!()
));
assert!(matches!(
OffsetDateTime::parse("Mon,(\\\u{ff}", &Rfc2822),
invalid_literal!()
));
assert!(matches!(
OffsetDateTime::parse("Mon,((\\\u{0})(\\\u{b} )(\\\u{d})", &Rfc2822),
invalid_literal!()
invalid_component!("day")
));

assert!(matches!(
Expand Down
39 changes: 26 additions & 13 deletions time/src/parsing/parsable.rs
Expand Up @@ -165,8 +165,8 @@ impl sealed::Sealed for Rfc2822 {
let colon = ascii_char::<b':'>;
let comma = ascii_char::<b','>;

let input = opt(fws)(input).into_inner();
let input = first_match(
let input = opt(cfws)(input).into_inner();
let weekday = first_match(
[
(b"Mon".as_slice(), Weekday::Monday),
(b"Tue".as_slice(), Weekday::Tuesday),
Expand All @@ -177,11 +177,16 @@ impl sealed::Sealed for Rfc2822 {
(b"Sun".as_slice(), Weekday::Sunday),
],
false,
)(input)
.and_then(|item| item.consume_value(|value| parsed.set_weekday(value)))
.ok_or(InvalidComponent("weekday"))?;
let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
)(input);
let input = if let Some(item) = weekday {
let input = item
.consume_value(|value| parsed.set_weekday(value))
.ok_or(InvalidComponent("weekday"))?;
let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
opt(cfws)(input).into_inner()
} else {
input
};
let input = n_to_m_digits::<1, 2, _>(input)
.and_then(|item| item.consume_value(|value| parsed.set_day(value)))
.ok_or(InvalidComponent("day"))?;
Expand Down Expand Up @@ -307,6 +312,8 @@ impl sealed::Sealed for Rfc2822 {
})
.ok_or(InvalidComponent("offset minute"))?;

let input = opt(cfws)(input).into_inner();

Ok(input)
}

Expand All @@ -320,10 +327,10 @@ impl sealed::Sealed for Rfc2822 {
let colon = ascii_char::<b':'>;
let comma = ascii_char::<b','>;

let input = opt(fws)(input).into_inner();
let input = opt(cfws)(input).into_inner();
// This parses the weekday, but we don't actually use the value anywhere. Because of this,
// just return `()` to avoid unnecessary generated code.
let ParsedItem(input, ()) = first_match(
let weekday = first_match(
[
(b"Mon".as_slice(), ()),
(b"Tue".as_slice(), ()),
Expand All @@ -334,10 +341,14 @@ impl sealed::Sealed for Rfc2822 {
(b"Sun".as_slice(), ()),
],
false,
)(input)
.ok_or(InvalidComponent("weekday"))?;
let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
)(input);
let input = if let Some(item) = weekday {
let input = item.into_inner();
let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
opt(cfws)(input).into_inner()
} else {
input
};
let ParsedItem(input, day) =
n_to_m_digits::<1, 2, _>(input).ok_or(InvalidComponent("day"))?;
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
Expand Down Expand Up @@ -442,6 +453,8 @@ impl sealed::Sealed for Rfc2822 {
(input, offset_hour, offset_minute.cast_signed())
};

let input = opt(cfws)(input).into_inner();

if !input.is_empty() {
return Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::UnexpectedTrailingCharacters,
Expand Down

0 comments on commit 7a6a800

Please sign in to comment.