use core::fmt;
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
#[repr(u8)]
pub enum Weekday {
Mon = Self::MON_NUM,
Tue = Self::TUE_NUM,
Wed = Self::WED_NUM,
Thu = Self::THU_NUM,
Fri = Self::FRI_NUM,
Sat = Self::SAT_NUM,
Sun = Self::SUN_NUM,
}
impl Weekday {
pub const MON_NUM: u8 = 1;
pub const TUE_NUM: u8 = 2;
pub const WED_NUM: u8 = 3;
pub const THU_NUM: u8 = 4;
pub const FRI_NUM: u8 = 5;
pub const SAT_NUM: u8 = 6;
pub const SUN_NUM: u8 = 7;
pub const MON: &str = "Mon";
pub const TUE: &str = "Tue";
pub const WED: &str = "Wed";
pub const THU: &str = "Thu";
pub const FRI: &str = "Fri";
pub const SAT: &str = "Sat";
pub const SUN: &str = "Sun";
#[must_use]
pub fn num_days_from_monday(self) -> u8 {
self as u8 - 1
}
#[must_use]
pub fn number_from_monday(self) -> u8 {
self as u8
}
#[must_use]
pub fn num_days_from_sunday(self) -> u8 {
if self == Self::Sun { 0 } else { self as u8 }
}
#[must_use]
pub fn number_from_sunday(self) -> u8 {
if self == Self::Sun { 1 } else { self as u8 + 1 }
}
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::Mon => Self::MON,
Self::Tue => Self::TUE,
Self::Wed => Self::WED,
Self::Thu => Self::THU,
Self::Fri => Self::FRI,
Self::Sat => Self::SAT,
Self::Sun => Self::SUN,
}
}
}
impl From<u8> for Weekday {
fn from(value: u8) -> Self {
match value {
Self::MON_NUM => Self::Mon,
Self::TUE_NUM => Self::Tue,
Self::WED_NUM => Self::Wed,
Self::THU_NUM => Self::Thu,
Self::FRI_NUM => Self::Fri,
Self::SAT_NUM => Self::Sat,
_ => Self::Sun,
}
}
}
impl AsRef<str> for Weekday {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl fmt::Debug for Weekday {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self, f)
}
}
impl fmt::Display for Weekday {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for Weekday {
fn format(&self, fmt: defmt::Formatter<'_>) {
defmt::write!(fmt, "{}", self.as_str());
}
}
#[cfg(feature = "ufmt")]
impl ufmt::uDebug for Weekday {
fn fmt<W>(&self, fmt: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error>
where
W: ufmt::uWrite + ?Sized,
{
ufmt::uDisplay::fmt(&self, fmt)
}
}
#[cfg(feature = "ufmt")]
impl ufmt::uDisplay for Weekday {
fn fmt<W>(&self, fmt: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error>
where
W: ufmt::uWrite + ?Sized,
{
fmt.write_str(self.as_str())
}
}
#[cfg(test)]
mod tests {
#![expect(clippy::panic, clippy::unwrap_used, reason = "this is a test")]
use chrono::Datelike as _;
#[test]
fn test_weekday() {
for year in 2000_u16..=2171 {
'next_month: for month in 1_u8..=12 {
for day in 1_u8..=31 {
let Some(embedded_date) = crate::Date::new_checked(year, month, day) else {
continue 'next_month;
};
let chrono_date = chrono::NaiveDate::from_ymd_opt(
i32::from(year),
u32::from(month),
u32::from(day),
)
.unwrap();
let chrono_weekday = chrono_date.weekday();
let embedded_weekday = embedded_date.weekday();
match (chrono_weekday, embedded_weekday) {
(chrono::Weekday::Mon, super::Weekday::Mon)
| (chrono::Weekday::Tue, super::Weekday::Tue)
| (chrono::Weekday::Wed, super::Weekday::Wed)
| (chrono::Weekday::Thu, super::Weekday::Thu)
| (chrono::Weekday::Fri, super::Weekday::Fri)
| (chrono::Weekday::Sat, super::Weekday::Sat)
| (chrono::Weekday::Sun, super::Weekday::Sun) => (),
_ => panic!(
"chrono and embedded weekdays do not match: {chrono_weekday:?} != {embedded_weekday:?} for {chrono_date}"
),
}
assert_eq!(
chrono_weekday.num_days_from_monday(),
u32::from(embedded_weekday.num_days_from_monday()),
"num_days_from_monday: {chrono_date}",
);
assert_eq!(
chrono_weekday.num_days_from_sunday(),
u32::from(embedded_weekday.num_days_from_sunday()),
"num_days_from_sunday: {chrono_date}",
);
assert_eq!(
chrono_weekday.number_from_monday(),
u32::from(embedded_weekday.number_from_monday()),
"number_from_monday: {chrono_date}",
);
assert_eq!(
chrono_weekday.number_from_sunday(),
u32::from(embedded_weekday.number_from_sunday()),
"number_from_sunday: {chrono_date}",
);
}
}
}
}
}