use crate::{error::Error, shared::util::itime::IWeekday, util::b};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
#[allow(missing_docs)]
pub enum Weekday {
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
Sunday = 7,
}
impl Weekday {
#[inline]
pub fn from_monday_zero_offset(offset: i8) -> Result<Weekday, Error> {
Ok(Weekday::from_monday_zero_offset_unchecked(
b::WeekdayMondayZero::check(offset)?,
))
}
#[inline]
fn from_monday_zero_offset_unchecked(offset: impl Into<i64>) -> Weekday {
match offset.into() {
0 => Weekday::Monday,
1 => Weekday::Tuesday,
2 => Weekday::Wednesday,
3 => Weekday::Thursday,
4 => Weekday::Friday,
5 => Weekday::Saturday,
6 => Weekday::Sunday,
_ => unreachable!(),
}
}
#[inline]
pub fn from_monday_one_offset(offset: i8) -> Result<Weekday, Error> {
let offset = b::WeekdayMondayOne::check(offset)?;
Weekday::from_monday_zero_offset(offset - 1)
}
#[inline]
pub fn from_sunday_zero_offset(offset: i8) -> Result<Weekday, Error> {
let offset = b::WeekdaySundayZero::check(offset)?;
Weekday::from_monday_zero_offset((offset - 1).rem_euclid(7))
}
#[inline]
pub fn from_sunday_one_offset(offset: i8) -> Result<Weekday, Error> {
let offset = b::WeekdaySundayOne::check(offset)?;
Weekday::from_monday_zero_offset((offset - 2).rem_euclid(7))
}
#[inline]
pub fn to_monday_zero_offset(self) -> i8 {
self.to_monday_one_offset() - 1
}
#[inline]
pub fn to_monday_one_offset(self) -> i8 {
self as i8
}
#[inline]
pub fn to_sunday_zero_offset(self) -> i8 {
let offset = self.to_monday_one_offset();
if offset == 7 {
0
} else {
offset
}
}
#[inline]
pub fn to_sunday_one_offset(self) -> i8 {
self.to_sunday_zero_offset() + 1
}
#[inline]
pub fn next(self) -> Weekday {
self.wrapping_add(1)
}
#[inline]
pub fn previous(self) -> Weekday {
self.wrapping_sub(1)
}
#[inline]
pub fn since(self, other: Weekday) -> i8 {
(self.to_monday_zero_offset() - other.to_monday_zero_offset())
.rem_euclid(7)
}
#[inline]
pub fn until(self, other: Weekday) -> i8 {
other.since(self)
}
#[inline]
pub fn wrapping_add<D: Into<i64>>(self, days: D) -> Weekday {
let start = i64::from(self.to_monday_zero_offset());
let rhs = days.into();
let end = start.wrapping_add(rhs).rem_euclid(7);
Weekday::from_monday_zero_offset_unchecked(end)
}
#[inline]
pub fn wrapping_sub<D: Into<i64>>(self, days: D) -> Weekday {
self.wrapping_add(-days.into())
}
#[inline]
pub fn cycle_forward(self) -> WeekdaysForward {
let nexts = [
self,
self.wrapping_add(1),
self.wrapping_add(2),
self.wrapping_add(3),
self.wrapping_add(4),
self.wrapping_add(5),
self.wrapping_add(6),
];
WeekdaysForward { it: nexts.into_iter().cycle() }
}
#[inline]
pub fn cycle_reverse(self) -> WeekdaysReverse {
let nexts = [
self,
self.wrapping_sub(1),
self.wrapping_sub(2),
self.wrapping_sub(3),
self.wrapping_sub(4),
self.wrapping_sub(5),
self.wrapping_sub(6),
];
WeekdaysReverse { it: nexts.into_iter().cycle() }
}
}
impl Weekday {
#[inline]
pub(crate) fn from_iweekday(iweekday: IWeekday) -> Weekday {
match iweekday.to_monday_one_offset() {
1 => Weekday::Monday,
2 => Weekday::Tuesday,
3 => Weekday::Wednesday,
4 => Weekday::Thursday,
5 => Weekday::Friday,
6 => Weekday::Saturday,
7 => Weekday::Sunday,
_ => unreachable!(),
}
}
#[inline]
pub(crate) fn to_iweekday(self) -> IWeekday {
IWeekday::from_monday_one_offset(self.to_monday_one_offset())
}
}
impl core::ops::Add<i8> for Weekday {
type Output = Weekday;
#[inline]
fn add(self, rhs: i8) -> Weekday {
self.wrapping_add(rhs)
}
}
impl core::ops::Add<i16> for Weekday {
type Output = Weekday;
#[inline]
fn add(self, rhs: i16) -> Weekday {
self.wrapping_add(rhs)
}
}
impl core::ops::Add<i32> for Weekday {
type Output = Weekday;
#[inline]
fn add(self, rhs: i32) -> Weekday {
self.wrapping_add(rhs)
}
}
impl core::ops::Add<i64> for Weekday {
type Output = Weekday;
#[inline]
fn add(self, rhs: i64) -> Weekday {
self.wrapping_add(rhs)
}
}
impl core::ops::Add<Weekday> for i8 {
type Output = Weekday;
#[inline]
fn add(self, rhs: Weekday) -> Weekday {
rhs.wrapping_add(self)
}
}
impl core::ops::Add<Weekday> for i16 {
type Output = Weekday;
#[inline]
fn add(self, rhs: Weekday) -> Weekday {
rhs.wrapping_add(self)
}
}
impl core::ops::Add<Weekday> for i32 {
type Output = Weekday;
#[inline]
fn add(self, rhs: Weekday) -> Weekday {
rhs.wrapping_add(self)
}
}
impl core::ops::Add<Weekday> for i64 {
type Output = Weekday;
#[inline]
fn add(self, rhs: Weekday) -> Weekday {
rhs.wrapping_add(self)
}
}
impl core::ops::AddAssign<i8> for Weekday {
#[inline]
fn add_assign(&mut self, rhs: i8) {
*self = *self + rhs;
}
}
impl core::ops::AddAssign<i16> for Weekday {
#[inline]
fn add_assign(&mut self, rhs: i16) {
*self = *self + rhs;
}
}
impl core::ops::AddAssign<i32> for Weekday {
#[inline]
fn add_assign(&mut self, rhs: i32) {
*self = *self + rhs;
}
}
impl core::ops::AddAssign<i64> for Weekday {
#[inline]
fn add_assign(&mut self, rhs: i64) {
*self = *self + rhs;
}
}
impl core::ops::Sub<i8> for Weekday {
type Output = Weekday;
#[inline]
fn sub(self, rhs: i8) -> Weekday {
self.wrapping_sub(rhs)
}
}
impl core::ops::Sub<i16> for Weekday {
type Output = Weekday;
#[inline]
fn sub(self, rhs: i16) -> Weekday {
self.wrapping_sub(rhs)
}
}
impl core::ops::Sub<i32> for Weekday {
type Output = Weekday;
#[inline]
fn sub(self, rhs: i32) -> Weekday {
self.wrapping_sub(rhs)
}
}
impl core::ops::Sub<i64> for Weekday {
type Output = Weekday;
#[inline]
fn sub(self, rhs: i64) -> Weekday {
self.wrapping_sub(rhs)
}
}
impl core::ops::SubAssign<i8> for Weekday {
#[inline]
fn sub_assign(&mut self, rhs: i8) {
*self = *self - rhs;
}
}
impl core::ops::SubAssign<i16> for Weekday {
#[inline]
fn sub_assign(&mut self, rhs: i16) {
*self = *self - rhs;
}
}
impl core::ops::SubAssign<i32> for Weekday {
#[inline]
fn sub_assign(&mut self, rhs: i32) {
*self = *self - rhs;
}
}
impl core::ops::SubAssign<i64> for Weekday {
#[inline]
fn sub_assign(&mut self, rhs: i64) {
*self = *self - rhs;
}
}
#[cfg(test)]
impl quickcheck::Arbitrary for Weekday {
fn arbitrary(g: &mut quickcheck::Gen) -> Weekday {
let offset = b::WeekdayMondayZero::arbitrary(g);
Weekday::from_monday_zero_offset(offset).unwrap()
}
fn shrink(&self) -> alloc::boxed::Box<dyn Iterator<Item = Weekday>> {
alloc::boxed::Box::new(
self.to_monday_zero_offset()
.shrink()
.filter_map(|n| Weekday::from_monday_zero_offset(n).ok()),
)
}
}
#[derive(Clone, Debug)]
pub struct WeekdaysForward {
it: core::iter::Cycle<core::array::IntoIter<Weekday, 7>>,
}
impl Iterator for WeekdaysForward {
type Item = Weekday;
#[inline]
fn next(&mut self) -> Option<Weekday> {
self.it.next()
}
}
impl core::iter::FusedIterator for WeekdaysForward {}
#[derive(Clone, Debug)]
pub struct WeekdaysReverse {
it: core::iter::Cycle<core::array::IntoIter<Weekday, 7>>,
}
impl Iterator for WeekdaysReverse {
type Item = Weekday;
#[inline]
fn next(&mut self) -> Option<Weekday> {
self.it.next()
}
}
impl core::iter::FusedIterator for WeekdaysReverse {}
#[cfg(test)]
mod tests {
use super::*;
quickcheck::quickcheck! {
fn prop_since_add_equals_self(wd1: Weekday, wd2: Weekday) -> bool {
let days = wd1.since(wd2);
wd2.wrapping_add(days) == wd1
}
fn prop_until_add_equals_other(wd1: Weekday, wd2: Weekday) -> bool {
let days = wd1.until(wd2);
wd1.wrapping_add(days) == wd2
}
}
}