fdate 0.2.2

Natural date input parsing
Documentation
use chrono::Weekday;
use nom::{IResult, Parser, character::complete::multispace1, combinator::opt};

use super::common::{self, RelativeDirection};

pub(super) fn parse_relative_weekday(input: &str) -> IResult<&str, RelativeWeekday> {
    opt(common::parse_relative_direction
        .and(multispace1)
        .map(|(direction, _)| direction))
    .and(common::parse_weekday)
    .map(|(direction, weekday)| RelativeWeekday { direction, weekday })
    .parse(input)
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) struct RelativeWeekday {
    pub direction: Option<RelativeDirection>,
    pub weekday: Weekday,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_bare_relative_weekdays() {
        assert_eq!(
            parse_relative_weekday("monday"),
            Ok((
                "",
                RelativeWeekday {
                    direction: None,
                    weekday: Weekday::Mon,
                },
            ))
        );
        assert_eq!(
            parse_relative_weekday("thu"),
            Ok((
                "",
                RelativeWeekday {
                    direction: None,
                    weekday: Weekday::Thu,
                },
            ))
        );
    }

    #[test]
    fn parses_relative_weekdays_with_direction() {
        assert_eq!(
            parse_relative_weekday("next monday"),
            Ok((
                "",
                RelativeWeekday {
                    direction: Some(RelativeDirection::Future),
                    weekday: Weekday::Mon,
                },
            ))
        );
        assert_eq!(
            parse_relative_weekday("last fri"),
            Ok((
                "",
                RelativeWeekday {
                    direction: Some(RelativeDirection::Past),
                    weekday: Weekday::Fri,
                },
            ))
        );
    }

    #[test]
    fn parses_relative_weekdays_case_insensitively() {
        assert_eq!(
            parse_relative_weekday("Next Tuesday"),
            Ok((
                "",
                RelativeWeekday {
                    direction: Some(RelativeDirection::Future),
                    weekday: Weekday::Tue,
                },
            ))
        );
        assert_eq!(
            parse_relative_weekday("LAST sunday"),
            Ok((
                "",
                RelativeWeekday {
                    direction: Some(RelativeDirection::Past),
                    weekday: Weekday::Sun,
                },
            ))
        );
    }

    #[test]
    fn leaves_remaining_input_for_larger_parsers() {
        assert_eq!(
            parse_relative_weekday("next monday morning"),
            Ok((
                " morning",
                RelativeWeekday {
                    direction: Some(RelativeDirection::Future),
                    weekday: Weekday::Mon,
                },
            ))
        );
    }

    #[test]
    fn rejects_invalid_relative_weekdays() {
        assert!(parse_relative_weekday("next").is_err());
        assert!(parse_relative_weekday("hello").is_err());
        assert!(parse_relative_weekday("nextmonday").is_err());
    }
}