From 9bb6f9a5b3b96f5797d870e01a799ae0553058af Mon Sep 17 00:00:00 2001 From: Botahamec Date: Mon, 27 Dec 2021 16:50:28 -0500 Subject: Add weekdays --- src/lib.rs | 2 + src/weekday.rs | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/weekday.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index c1bd251..fdfeb5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ #![doc = include_str!("../README.md")] mod month; +mod weekday; mod year; pub use month::Month; +pub use weekday::Weekday; pub use year::Year; diff --git a/src/weekday.rs b/src/weekday.rs new file mode 100644 index 0000000..5679bc7 --- /dev/null +++ b/src/weekday.rs @@ -0,0 +1,176 @@ +use std::str::FromStr; + +use derive_more::Display; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use self::Weekday::*; + +/// Day of the week +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[repr(u8)] +pub enum Weekday { + Monday = 0, + Tuesday = 1, + Wednesday = 2, + Thursday = 3, + Friday = 4, + Saturday = 5, + Sunday = 6, +} + +impl Weekday { + /// Get the weekday from its name. Returns `None` if an invalid name was given. + /// + /// # Example + /// + /// ``` + /// use botic::Weekday; + /// + /// assert_eq!(Weekday::Monday, Weekday::from_name("Monday").unwrap()); + /// assert_eq!(None, Weekday::from_name("monday")); + /// ``` + pub fn from_name(name: &str) -> Option { + match name { + "Monday" => Some(Monday), + "Tuesday" => Some(Tuesday), + "Wednesday" => Some(Wednesday), + "Thursday" => Some(Thursday), + "Friday" => Some(Friday), + "Saturday" => Some(Saturday), + "Sunday" => Some(Sunday), + _ => None, + } + } + + /// Get the next weekday + /// + /// # Example + /// + /// ``` + /// use botic::Weekday; + /// + /// assert_eq!(Weekday::Tuesday, Weekday::Monday.next()); + /// ``` + pub const fn next(self) -> Self { + match self { + Monday => Tuesday, + Tuesday => Wednesday, + Wednesday => Thursday, + Thursday => Friday, + Friday => Saturday, + Saturday => Sunday, + Sunday => Monday, + } + } + + /// Get the previous weekday + /// + /// # Example + /// + /// ``` + /// use botic::Weekday; + /// + /// assert_eq!(Weekday::Sunday, Weekday::Monday.previous()); + /// ``` + pub const fn previous(self) -> Self { + match self { + Monday => Sunday, + Tuesday => Monday, + Wednesday => Tuesday, + Thursday => Wednesday, + Friday => Thursday, + Saturday => Friday, + Sunday => Saturday, + } + } + + /// Get the zero-indexed number of days from Monday. + /// In other words, the number representing the day of the week, + /// starting with Monday = 0 + /// + /// # Example + /// + /// ``` + /// use botic::Weekday; + /// + /// assert_eq!(0, Weekday::Monday.number_days_from_monday()); + /// assert_eq!(6, Weekday::Sunday.number_days_from_monday()); + /// ``` + pub const fn number_days_from_monday(self) -> u8 { + self as u8 + } + + /// Get the one-indexed number of days from Monday. + /// In other words, the number representing the day of the week, + /// starting with Monday = 1 + /// + /// # Example + /// + /// ``` + /// use botic::Weekday; + /// + /// assert_eq!(1, Weekday::Monday.number_from_monday()); + /// assert_eq!(7, Weekday::Sunday.number_from_monday()); + /// ``` + pub const fn number_from_monday(self) -> u8 { + self.number_days_from_monday() + 1 + } + + /// Get the zero-indexed number of days from Sunday. + /// In other words, the number representing the day of the week, + /// starting with Sunday = 0 + /// + /// # Example + /// + /// ``` + /// use botic::Weekday; + /// + /// assert_eq!(0, Weekday::Sunday.number_days_from_sunday()); + /// assert_eq!(1, Weekday::Monday.number_days_from_sunday()); + /// ``` + // TODO benchmark this + pub const fn number_days_from_sunday(self) -> u8 { + match self { + Sunday => 0, + _ => (self as u8) + 1, + } + } + + /// Get the one-indexed number of days from Sunday. + /// In other words, the number representing the day of the week, + /// starting with Sunday = 1 + /// + /// # Example + /// + /// ``` + /// use botic::Weekday; + /// + /// assert_eq!(1, Weekday::Sunday.number_from_sunday()); + /// assert_eq!(2, Weekday::Monday.number_from_sunday()); + /// ``` + pub const fn number_from_sunday(self) -> u8 { + self.number_days_from_sunday() + 1 + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Error)] +#[error("Failed to parse the month")] +// TODO Consider trying to figure out what month the user meant to use +pub struct ParseWeekdayError; + +// TODO make case-insensitive +// TODO support short names +impl FromStr for Weekday { + type Err = ParseWeekdayError; + + fn from_str(s: &str) -> Result { + match Self::from_name(s) { + Some(weekday) => Ok(weekday), + None => Err(ParseWeekdayError), + } + } +} -- cgit v1.2.3