jiff/civil/
weekday.rs

1use crate::{
2    error::Error,
3    util::{
4        rangeint::{RFrom, RInto},
5        t::{self, C},
6    },
7};
8
9/// A representation for the day of the week.
10///
11/// The default representation follows ISO 8601. That is, the week starts with
12/// Monday and numbering starts at `1`. However, the various constructors and
13/// accessors support using other schemes in wide use:
14///
15/// * [`Weekday::from_monday_zero_offset`] builds a weekday from
16/// a scheme that starts the week on Monday at offset `0`, while
17/// [`Weekday::to_monday_zero_offset`] converts to it.
18/// * [`Weekday::from_monday_one_offset`] builds a weekday from a scheme
19/// that starts the week on Monday at offset `1` (the default representation),
20/// while [`Weekday::to_monday_one_offset`] converts to it.
21/// * [`Weekday::from_sunday_zero_offset`] builds a weekday from
22/// a scheme that starts the week on Sunday at offset `0`, while
23/// [`Weekday::to_sunday_zero_offset`] converts to it.
24/// * [`Weekday::from_sunday_one_offset`] builds a weekday from
25/// a scheme that starts the week on Sunday at offset `1`, while
26/// [`Weekday::to_sunday_one_offset`] converts to it.
27///
28/// # Arithmetic
29///
30/// This type provides [`Weekday::wrapping_add`] and [`Weekday::wrapping_sub`]
31/// for performing wrapping arithmetic on weekdays. These are also available
32/// via operator overloading:
33///
34/// ```
35/// use jiff::civil::Weekday;
36///
37/// assert_eq!(Weekday::Monday + 1, Weekday::Tuesday);
38/// assert_eq!(Weekday::Sunday - 1, Weekday::Saturday);
39/// ```
40///
41/// # Comparisons
42///
43/// This type provides `Eq` and `PartialEq` trait implementations for easy
44/// comparison:
45///
46/// ```
47/// use jiff::civil::Weekday;
48///
49/// assert_eq!(Weekday::Wednesday, Weekday::Wednesday + 7);
50/// assert_ne!(Weekday::Thursday, Weekday::Friday);
51/// ```
52///
53/// But this type specifically does not provide `Ord` or `PartialOrd` trait
54/// implementations. Such an implementation would require deciding whether
55/// Sunday is less than Monday or greater than Monday. The former case
56/// corresponds to a week scheme where Sunday is the first day in the week,
57/// where as the latter corresponds to a scheme where Monday is the first day.
58/// Since both schemes are in widespread use, it would be inappropriate to bake
59/// in an assumption of one or the other. Instead, one can convert a weekday
60/// into the desired offset scheme, and then compare the offsets:
61///
62/// ```
63/// use jiff::civil::Weekday;
64///
65/// let (sun, mon) = (Weekday::Sunday, Weekday::Monday);
66/// assert!(sun.to_sunday_zero_offset() < mon.to_sunday_zero_offset());
67/// assert!(sun.to_monday_zero_offset() > mon.to_monday_zero_offset());
68/// ```
69///
70/// # Example
71///
72/// This example shows the result of converting to and from different schemes:
73///
74/// ```
75/// use jiff::civil::Weekday;
76///
77/// // The different representations of Monday.
78/// assert_eq!(Weekday::Monday.to_monday_zero_offset(), 0);
79/// assert_eq!(Weekday::Monday.to_monday_one_offset(), 1);
80/// assert_eq!(Weekday::Monday.to_sunday_zero_offset(), 1);
81/// assert_eq!(Weekday::Monday.to_sunday_one_offset(), 2);
82///
83/// // The different representations of Sunday.
84/// assert_eq!(Weekday::Sunday.to_monday_zero_offset(), 6);
85/// assert_eq!(Weekday::Sunday.to_monday_one_offset(), 7);
86/// assert_eq!(Weekday::Sunday.to_sunday_zero_offset(), 0);
87/// assert_eq!(Weekday::Sunday.to_sunday_one_offset(), 1);
88/// ```
89#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
90#[repr(u8)]
91#[allow(missing_docs)]
92pub enum Weekday {
93    Monday = 1,
94    Tuesday = 2,
95    Wednesday = 3,
96    Thursday = 4,
97    Friday = 5,
98    Saturday = 6,
99    Sunday = 7,
100}
101
102impl Weekday {
103    /// Convert an offset to a structured `Weekday`.
104    ///
105    /// The offset should be from a scheme where the first day of the week
106    /// is Monday and starts numbering at `0`.
107    ///
108    /// # Errors
109    ///
110    /// This returns an error when the given offset is not in the range
111    /// `0..=6`.
112    ///
113    /// # Example
114    ///
115    /// ```
116    /// use jiff::civil::Weekday;
117    ///
118    /// let weekday = Weekday::from_monday_zero_offset(3)?;
119    /// assert_eq!(weekday, Weekday::Thursday);
120    ///
121    /// assert!(Weekday::from_monday_zero_offset(7).is_err());
122    /// assert!(Weekday::from_monday_zero_offset(-1).is_err());
123    ///
124    /// # Ok::<(), Box<dyn std::error::Error>>(())
125    /// ```
126    #[inline]
127    pub fn from_monday_zero_offset(offset: i8) -> Result<Weekday, Error> {
128        let offset = t::WeekdayZero::try_new("weekday", offset)?;
129        Ok(Weekday::from_monday_zero_offset_ranged(offset))
130    }
131
132    /// Convert an offset to a structured `Weekday`.
133    ///
134    /// The offset should be from a scheme where the first day of the week
135    /// is Monday and starts numbering at `1`.
136    ///
137    /// # Errors
138    ///
139    /// This returns an error when the given offset is not in the range
140    /// `1..=7`.
141    ///
142    /// # Example
143    ///
144    /// ```
145    /// use jiff::civil::Weekday;
146    ///
147    /// let weekday = Weekday::from_monday_one_offset(4)?;
148    /// assert_eq!(weekday, Weekday::Thursday);
149    ///
150    /// assert!(Weekday::from_monday_one_offset(8).is_err());
151    /// assert!(Weekday::from_monday_one_offset(0).is_err());
152    ///
153    /// # Ok::<(), Box<dyn std::error::Error>>(())
154    /// ```
155    #[inline]
156    pub fn from_monday_one_offset(offset: i8) -> Result<Weekday, Error> {
157        let offset = t::WeekdayOne::try_new("weekday", offset)?;
158        Ok(Weekday::from_monday_one_offset_ranged(offset))
159    }
160
161    /// Convert an offset to a structured `Weekday`.
162    ///
163    /// The offset should be from a scheme where the first day of the week
164    /// is Sunday and starts numbering at `0`.
165    ///
166    /// # Errors
167    ///
168    /// This returns an error when the given offset is not in the range
169    /// `0..=6`.
170    ///
171    /// # Example
172    ///
173    /// ```
174    /// use jiff::civil::Weekday;
175    ///
176    /// let weekday = Weekday::from_sunday_zero_offset(4)?;
177    /// assert_eq!(weekday, Weekday::Thursday);
178    ///
179    /// assert!(Weekday::from_sunday_zero_offset(7).is_err());
180    /// assert!(Weekday::from_sunday_zero_offset(-1).is_err());
181    ///
182    /// # Ok::<(), Box<dyn std::error::Error>>(())
183    /// ```
184    #[inline]
185    pub fn from_sunday_zero_offset(offset: i8) -> Result<Weekday, Error> {
186        let offset = t::WeekdayZero::try_new("weekday", offset)?;
187        Ok(Weekday::from_sunday_zero_offset_ranged(offset))
188    }
189
190    /// Convert an offset to a structured `Weekday`.
191    ///
192    /// The offset should be from a scheme where the first day of the week
193    /// is Sunday and starts numbering at `1`.
194    ///
195    /// # Errors
196    ///
197    /// This returns an error when the given offset is not in the range
198    /// `1..=7`.
199    ///
200    /// # Example
201    ///
202    /// ```
203    /// use jiff::civil::Weekday;
204    ///
205    /// let weekday = Weekday::from_sunday_one_offset(5)?;
206    /// assert_eq!(weekday, Weekday::Thursday);
207    ///
208    /// assert!(Weekday::from_sunday_one_offset(8).is_err());
209    /// assert!(Weekday::from_sunday_one_offset(0).is_err());
210    ///
211    /// # Ok::<(), Box<dyn std::error::Error>>(())
212    /// ```
213    #[inline]
214    pub fn from_sunday_one_offset(offset: i8) -> Result<Weekday, Error> {
215        let offset = t::WeekdayOne::try_new("weekday", offset)?;
216        Ok(Weekday::from_sunday_one_offset_ranged(offset))
217    }
218
219    /// Returns this weekday as an offset.
220    ///
221    /// The offset returned is computed based on a week that starts with Monday
222    /// and begins numbering at `0`.
223    ///
224    /// # Example
225    ///
226    /// ```
227    /// use jiff::civil::Weekday;
228    ///
229    /// assert_eq!(Weekday::Thursday.to_monday_zero_offset(), 3);
230    ///
231    /// # Ok::<(), Box<dyn std::error::Error>>(())
232    /// ```
233    #[inline]
234    pub fn to_monday_zero_offset(self) -> i8 {
235        self.to_monday_zero_offset_ranged().get()
236    }
237
238    /// Returns this weekday as an offset.
239    ///
240    /// The offset returned is computed based on a week that starts with Monday
241    /// and begins numbering at `1`.
242    ///
243    /// # Example
244    ///
245    /// ```
246    /// use jiff::civil::Weekday;
247    ///
248    /// assert_eq!(Weekday::Thursday.to_monday_one_offset(), 4);
249    ///
250    /// # Ok::<(), Box<dyn std::error::Error>>(())
251    /// ```
252    #[inline]
253    pub fn to_monday_one_offset(self) -> i8 {
254        self.to_monday_one_offset_ranged().get()
255    }
256
257    /// Returns this weekday as an offset.
258    ///
259    /// The offset returned is computed based on a week that starts with Sunday
260    /// and begins numbering at `0`.
261    ///
262    /// # Example
263    ///
264    /// ```
265    /// use jiff::civil::Weekday;
266    ///
267    /// assert_eq!(Weekday::Thursday.to_sunday_zero_offset(), 4);
268    ///
269    /// # Ok::<(), Box<dyn std::error::Error>>(())
270    /// ```
271    #[inline]
272    pub fn to_sunday_zero_offset(self) -> i8 {
273        self.to_sunday_zero_offset_ranged().get()
274    }
275
276    /// Returns this weekday as an offset.
277    ///
278    /// The offset returned is computed based on a week that starts with Sunday
279    /// and begins numbering at `1`.
280    ///
281    /// # Example
282    ///
283    /// ```
284    /// use jiff::civil::Weekday;
285    ///
286    /// assert_eq!(Weekday::Thursday.to_sunday_one_offset(), 5);
287    ///
288    /// # Ok::<(), Box<dyn std::error::Error>>(())
289    /// ```
290    #[inline]
291    pub fn to_sunday_one_offset(self) -> i8 {
292        self.to_sunday_one_offset_ranged().get()
293    }
294
295    /// Returns the next weekday, wrapping around at the end of week to the
296    /// beginning of the week.
297    ///
298    /// This is a convenience routing for calling [`Weekday::wrapping_add`]
299    /// with a value of `1`.
300    ///
301    /// # Example
302    ///
303    /// ```
304    /// use jiff::civil::Weekday;
305    ///
306    /// assert_eq!(Weekday::Wednesday.next(), Weekday::Thursday);
307    /// assert_eq!(Weekday::Sunday.next(), Weekday::Monday);
308    /// assert_eq!(Weekday::Saturday.next(), Weekday::Sunday);
309    /// ```
310    #[inline]
311    pub fn next(self) -> Weekday {
312        self.wrapping_add(1)
313    }
314
315    /// Returns the previous weekday, wrapping around at the beginning of week
316    /// to the end of the week.
317    ///
318    /// This is a convenience routing for calling [`Weekday::wrapping_sub`]
319    /// with a value of `1`.
320    ///
321    /// # Example
322    ///
323    /// ```
324    /// use jiff::civil::Weekday;
325    ///
326    /// assert_eq!(Weekday::Wednesday.previous(), Weekday::Tuesday);
327    /// assert_eq!(Weekday::Sunday.previous(), Weekday::Saturday);
328    /// assert_eq!(Weekday::Saturday.previous(), Weekday::Friday);
329    /// ```
330    #[inline]
331    pub fn previous(self) -> Weekday {
332        self.wrapping_sub(1)
333    }
334
335    /// Returns the number of days from `other` to this weekday.
336    ///
337    /// Adding the returned number of days to `other` is guaranteed to sum to
338    /// this weekday. The number of days returned is guaranteed to be in the
339    /// range `0..=6`.
340    ///
341    /// # Example
342    ///
343    /// ```
344    /// use jiff::civil::Weekday;
345    ///
346    /// assert_eq!(Weekday::Friday.since(Weekday::Tuesday), 3);
347    /// assert_eq!(Weekday::Tuesday.since(Weekday::Tuesday), 0);
348    /// assert_eq!(Weekday::Monday.since(Weekday::Sunday), 1);
349    /// assert_eq!(Weekday::Sunday.since(Weekday::Monday), 6);
350    /// ```
351    #[inline]
352    pub fn since(self, other: Weekday) -> i8 {
353        self.since_ranged(other).get()
354    }
355
356    /// Returns the number of days until `other` from this weekday.
357    ///
358    /// Adding the returned number of days to this weekday is guaranteed to sum
359    /// to `other` weekday. The number of days returned is guaranteed to be in
360    /// the range `0..=6`.
361    ///
362    /// # Example
363    ///
364    /// ```
365    /// use jiff::civil::Weekday;
366    ///
367    /// assert_eq!(Weekday::Friday.until(Weekday::Tuesday), 4);
368    /// assert_eq!(Weekday::Tuesday.until(Weekday::Tuesday), 0);
369    /// assert_eq!(Weekday::Monday.until(Weekday::Sunday), 6);
370    /// assert_eq!(Weekday::Sunday.until(Weekday::Monday), 1);
371    /// ```
372    #[inline]
373    pub fn until(self, other: Weekday) -> i8 {
374        self.until_ranged(other).get()
375    }
376
377    /// Add the given number of days to this weekday, using wrapping arithmetic,
378    /// and return the resulting weekday.
379    ///
380    /// Adding a multiple of `7` (including `0`) is guaranteed to produce the
381    /// same weekday as this one.
382    ///
383    /// Note that this routine is also available via the `+` operator.
384    ///
385    /// # Example
386    ///
387    /// ```
388    /// use jiff::civil::Weekday;
389    ///
390    /// assert_eq!(Weekday::Sunday.wrapping_add(1), Weekday::Monday);
391    /// assert_eq!(Weekday::Sunday.wrapping_add(2), Weekday::Tuesday);
392    /// assert_eq!(Weekday::Saturday.wrapping_add(1), Weekday::Sunday);
393    /// assert_eq!(Weekday::Saturday.wrapping_add(7), Weekday::Saturday);
394    /// assert_eq!(Weekday::Sunday.wrapping_add(-1), Weekday::Saturday);
395    /// ```
396    ///
397    /// Wrapping arithmetic is also performed by the `+` operator:
398    ///
399    /// ```
400    /// use jiff::civil::Weekday;
401    ///
402    /// assert_eq!(Weekday::Sunday + 1, Weekday::Monday);
403    /// assert_eq!(Weekday::Sunday + 2, Weekday::Tuesday);
404    /// assert_eq!(Weekday::Saturday + 1, Weekday::Sunday);
405    /// assert_eq!(Weekday::Saturday + 7, Weekday::Saturday);
406    /// assert_eq!(Weekday::Sunday + -1, Weekday::Saturday);
407    /// // The weekday can also be on the right hand side of addition:
408    /// assert_eq!(1 + Weekday::Sunday, Weekday::Monday);
409    /// ```
410    #[inline]
411    pub fn wrapping_add<D: Into<i64>>(self, days: D) -> Weekday {
412        let start = t::NoUnits::rfrom(self.to_monday_zero_offset_ranged());
413        // OK because all i64 values fit in a NoUnits.
414        let rhs = t::NoUnits::new(days.into()).unwrap();
415        let end = start.wrapping_add(rhs) % C(7);
416        Weekday::from_monday_zero_offset_ranged(end)
417    }
418
419    /// Subtract the given number of days from this weekday, using wrapping
420    /// arithmetic, and return the resulting weekday.
421    ///
422    /// Subtracting a multiple of `7` (including `0`) is guaranteed to produce
423    /// the same weekday as this one.
424    ///
425    /// Note that this routine is also available via the `-` operator.
426    ///
427    /// # Example
428    ///
429    /// ```
430    /// use jiff::civil::Weekday;
431    ///
432    /// assert_eq!(Weekday::Sunday.wrapping_sub(1), Weekday::Saturday);
433    /// assert_eq!(Weekday::Sunday.wrapping_sub(2), Weekday::Friday);
434    /// assert_eq!(Weekday::Saturday.wrapping_sub(1), Weekday::Friday);
435    /// assert_eq!(Weekday::Saturday.wrapping_sub(7), Weekday::Saturday);
436    /// assert_eq!(Weekday::Sunday.wrapping_sub(-1), Weekday::Monday);
437    /// ```
438    ///
439    /// Wrapping arithmetic is also performed by the `-` operator:
440    ///
441    /// ```
442    /// use jiff::civil::Weekday;
443    ///
444    /// assert_eq!(Weekday::Sunday - 1, Weekday::Saturday);
445    /// assert_eq!(Weekday::Sunday - 2, Weekday::Friday);
446    /// assert_eq!(Weekday::Saturday - 1, Weekday::Friday);
447    /// assert_eq!(Weekday::Saturday - 7, Weekday::Saturday);
448    /// assert_eq!(Weekday::Sunday - -1, Weekday::Monday);
449    /// ```
450    ///
451    /// Unlike addition, since subtraction is not commutative and negating a
452    /// weekday has no semantic meaning, the weekday cannot be on the right
453    /// hand side of the `-` operator.
454    #[inline]
455    pub fn wrapping_sub<D: Into<i64>>(self, days: D) -> Weekday {
456        self.wrapping_add(-days.into())
457    }
458
459    /// Starting with this weekday, this returns an unending iterator that
460    /// cycles forward through the days of the week.
461    ///
462    /// # Example
463    ///
464    /// ```
465    /// use jiff::civil::Weekday;
466    ///
467    /// let mut it = Weekday::Tuesday.cycle_forward();
468    /// assert_eq!(it.next(), Some(Weekday::Tuesday));
469    /// assert_eq!(it.next(), Some(Weekday::Wednesday));
470    /// assert_eq!(it.next(), Some(Weekday::Thursday));
471    /// assert_eq!(it.next(), Some(Weekday::Friday));
472    /// assert_eq!(it.next(), Some(Weekday::Saturday));
473    /// assert_eq!(it.next(), Some(Weekday::Sunday));
474    /// assert_eq!(it.next(), Some(Weekday::Monday));
475    /// assert_eq!(it.next(), Some(Weekday::Tuesday));
476    /// ```
477    #[inline]
478    pub fn cycle_forward(self) -> WeekdaysForward {
479        let nexts = [
480            self,
481            self.wrapping_add(1),
482            self.wrapping_add(2),
483            self.wrapping_add(3),
484            self.wrapping_add(4),
485            self.wrapping_add(5),
486            self.wrapping_add(6),
487        ];
488        WeekdaysForward { it: nexts.into_iter().cycle() }
489    }
490
491    /// Starting with this weekday, this returns an unending iterator that
492    /// cycles backward through the days of the week.
493    ///
494    /// # Example
495    ///
496    /// ```
497    /// use jiff::civil::Weekday;
498    ///
499    /// let mut it = Weekday::Tuesday.cycle_reverse();
500    /// assert_eq!(it.next(), Some(Weekday::Tuesday));
501    /// assert_eq!(it.next(), Some(Weekday::Monday));
502    /// assert_eq!(it.next(), Some(Weekday::Sunday));
503    /// assert_eq!(it.next(), Some(Weekday::Saturday));
504    /// assert_eq!(it.next(), Some(Weekday::Friday));
505    /// assert_eq!(it.next(), Some(Weekday::Thursday));
506    /// assert_eq!(it.next(), Some(Weekday::Wednesday));
507    /// assert_eq!(it.next(), Some(Weekday::Tuesday));
508    /// ```
509    #[inline]
510    pub fn cycle_reverse(self) -> WeekdaysReverse {
511        let nexts = [
512            self,
513            self.wrapping_sub(1),
514            self.wrapping_sub(2),
515            self.wrapping_sub(3),
516            self.wrapping_sub(4),
517            self.wrapping_sub(5),
518            self.wrapping_sub(6),
519        ];
520        WeekdaysReverse { it: nexts.into_iter().cycle() }
521    }
522}
523
524impl Weekday {
525    #[inline]
526    pub(crate) fn from_monday_zero_offset_ranged(
527        offset: impl RInto<t::WeekdayZero>,
528    ) -> Weekday {
529        match offset.rinto().get() {
530            0 => Weekday::Monday,
531            1 => Weekday::Tuesday,
532            2 => Weekday::Wednesday,
533            3 => Weekday::Thursday,
534            4 => Weekday::Friday,
535            5 => Weekday::Saturday,
536            6 => Weekday::Sunday,
537            _ => unreachable!(),
538        }
539    }
540
541    #[inline]
542    pub(crate) fn from_monday_one_offset_ranged(
543        offset: impl RInto<t::WeekdayOne>,
544    ) -> Weekday {
545        let offset_zero = offset.rinto() - C(1);
546        Weekday::from_monday_zero_offset_ranged(offset_zero)
547    }
548
549    #[inline]
550    pub(crate) fn from_sunday_zero_offset_ranged(
551        offset: impl RInto<t::WeekdayZero>,
552    ) -> Weekday {
553        let offset_sunday = (offset.rinto() - C(1)) % C(7);
554        Weekday::from_monday_zero_offset_ranged(offset_sunday)
555    }
556
557    #[inline]
558    pub(crate) fn from_sunday_one_offset_ranged(
559        offset: impl RInto<t::WeekdayOne>,
560    ) -> Weekday {
561        let offset_zero = offset.rinto() - C(1);
562        Weekday::from_sunday_zero_offset_ranged(offset_zero)
563    }
564
565    #[inline]
566    pub(crate) fn to_monday_zero_offset_ranged(self) -> t::WeekdayZero {
567        (self.to_monday_one_offset_ranged() - C(1)).rinto()
568    }
569
570    #[inline]
571    pub(crate) fn to_monday_one_offset_ranged(self) -> t::WeekdayOne {
572        t::WeekdayOne::new_unchecked(self as i8)
573    }
574
575    #[inline]
576    pub(crate) fn to_sunday_zero_offset_ranged(self) -> t::WeekdayZero {
577        (self.to_monday_zero_offset_ranged() + C(1)) % C(7)
578    }
579
580    #[inline]
581    pub(crate) fn to_sunday_one_offset_ranged(self) -> t::WeekdayOne {
582        (self.to_sunday_zero_offset_ranged() + C(1)).rinto()
583    }
584
585    #[inline]
586    pub(crate) fn since_ranged(self, other: Weekday) -> t::WeekdayZero {
587        (self.to_monday_zero_offset_ranged()
588            - other.to_monday_zero_offset_ranged())
589            % C(7)
590    }
591
592    #[inline]
593    pub(crate) fn until_ranged(self, other: Weekday) -> t::WeekdayZero {
594        other.since_ranged(self)
595    }
596}
597
598impl core::ops::Add<i8> for Weekday {
599    type Output = Weekday;
600
601    #[inline]
602    fn add(self, rhs: i8) -> Weekday {
603        self.wrapping_add(rhs)
604    }
605}
606
607impl core::ops::Add<i16> for Weekday {
608    type Output = Weekday;
609
610    #[inline]
611    fn add(self, rhs: i16) -> Weekday {
612        self.wrapping_add(rhs)
613    }
614}
615
616impl core::ops::Add<i32> for Weekday {
617    type Output = Weekday;
618
619    #[inline]
620    fn add(self, rhs: i32) -> Weekday {
621        self.wrapping_add(rhs)
622    }
623}
624
625impl core::ops::Add<i64> for Weekday {
626    type Output = Weekday;
627
628    #[inline]
629    fn add(self, rhs: i64) -> Weekday {
630        self.wrapping_add(rhs)
631    }
632}
633
634// Since addition is commutative, we don't might if users write `n + weekday`
635// or `weekday + n`.
636
637impl core::ops::Add<Weekday> for i8 {
638    type Output = Weekday;
639
640    #[inline]
641    fn add(self, rhs: Weekday) -> Weekday {
642        rhs.wrapping_add(self)
643    }
644}
645
646impl core::ops::Add<Weekday> for i16 {
647    type Output = Weekday;
648
649    #[inline]
650    fn add(self, rhs: Weekday) -> Weekday {
651        rhs.wrapping_add(self)
652    }
653}
654
655impl core::ops::Add<Weekday> for i32 {
656    type Output = Weekday;
657
658    #[inline]
659    fn add(self, rhs: Weekday) -> Weekday {
660        rhs.wrapping_add(self)
661    }
662}
663
664impl core::ops::Add<Weekday> for i64 {
665    type Output = Weekday;
666
667    #[inline]
668    fn add(self, rhs: Weekday) -> Weekday {
669        rhs.wrapping_add(self)
670    }
671}
672
673impl core::ops::AddAssign<i8> for Weekday {
674    #[inline]
675    fn add_assign(&mut self, rhs: i8) {
676        *self = *self + rhs;
677    }
678}
679
680impl core::ops::AddAssign<i16> for Weekday {
681    #[inline]
682    fn add_assign(&mut self, rhs: i16) {
683        *self = *self + rhs;
684    }
685}
686
687impl core::ops::AddAssign<i32> for Weekday {
688    #[inline]
689    fn add_assign(&mut self, rhs: i32) {
690        *self = *self + rhs;
691    }
692}
693
694impl core::ops::AddAssign<i64> for Weekday {
695    #[inline]
696    fn add_assign(&mut self, rhs: i64) {
697        *self = *self + rhs;
698    }
699}
700
701// Subtraction isn't commutative, so we only define it when the right hand
702// side is an integer. Otherwise we'd need a concept of what it means to
703// "negate" a weekday, which doesn't really make sense?
704
705impl core::ops::Sub<i8> for Weekday {
706    type Output = Weekday;
707
708    #[inline]
709    fn sub(self, rhs: i8) -> Weekday {
710        self.wrapping_sub(rhs)
711    }
712}
713
714impl core::ops::Sub<i16> for Weekday {
715    type Output = Weekday;
716
717    #[inline]
718    fn sub(self, rhs: i16) -> Weekday {
719        self.wrapping_sub(rhs)
720    }
721}
722
723impl core::ops::Sub<i32> for Weekday {
724    type Output = Weekday;
725
726    #[inline]
727    fn sub(self, rhs: i32) -> Weekday {
728        self.wrapping_sub(rhs)
729    }
730}
731
732impl core::ops::Sub<i64> for Weekday {
733    type Output = Weekday;
734
735    #[inline]
736    fn sub(self, rhs: i64) -> Weekday {
737        self.wrapping_sub(rhs)
738    }
739}
740
741impl core::ops::SubAssign<i8> for Weekday {
742    #[inline]
743    fn sub_assign(&mut self, rhs: i8) {
744        *self = *self - rhs;
745    }
746}
747
748impl core::ops::SubAssign<i16> for Weekday {
749    #[inline]
750    fn sub_assign(&mut self, rhs: i16) {
751        *self = *self - rhs;
752    }
753}
754
755impl core::ops::SubAssign<i32> for Weekday {
756    #[inline]
757    fn sub_assign(&mut self, rhs: i32) {
758        *self = *self - rhs;
759    }
760}
761
762impl core::ops::SubAssign<i64> for Weekday {
763    #[inline]
764    fn sub_assign(&mut self, rhs: i64) {
765        *self = *self - rhs;
766    }
767}
768
769#[cfg(test)]
770impl quickcheck::Arbitrary for Weekday {
771    fn arbitrary(g: &mut quickcheck::Gen) -> Weekday {
772        let offset = t::WeekdayZero::arbitrary(g);
773        Weekday::from_monday_zero_offset_ranged(offset)
774    }
775
776    fn shrink(&self) -> alloc::boxed::Box<dyn Iterator<Item = Weekday>> {
777        alloc::boxed::Box::new(
778            self.to_monday_zero_offset_ranged()
779                .shrink()
780                .map(Weekday::from_monday_zero_offset_ranged),
781        )
782    }
783}
784
785/// An unending iterator of the days of the week.
786///
787/// This iterator is created by calling [`Weekday::cycle_forward`].
788#[derive(Clone, Debug)]
789pub struct WeekdaysForward {
790    it: core::iter::Cycle<core::array::IntoIter<Weekday, 7>>,
791}
792
793impl Iterator for WeekdaysForward {
794    type Item = Weekday;
795
796    #[inline]
797    fn next(&mut self) -> Option<Weekday> {
798        self.it.next()
799    }
800}
801
802impl core::iter::FusedIterator for WeekdaysForward {}
803
804/// An unending iterator of the days of the week in reverse.
805///
806/// This iterator is created by calling [`Weekday::cycle_reverse`].
807#[derive(Clone, Debug)]
808pub struct WeekdaysReverse {
809    it: core::iter::Cycle<core::array::IntoIter<Weekday, 7>>,
810}
811
812impl Iterator for WeekdaysReverse {
813    type Item = Weekday;
814
815    #[inline]
816    fn next(&mut self) -> Option<Weekday> {
817        self.it.next()
818    }
819}
820
821impl core::iter::FusedIterator for WeekdaysReverse {}
822
823#[cfg(test)]
824mod tests {
825    use super::*;
826
827    quickcheck::quickcheck! {
828        fn prop_since_add_equals_self(wd1: Weekday, wd2: Weekday) -> bool {
829            let days = wd1.since(wd2);
830            wd2.wrapping_add(days) == wd1
831        }
832
833        fn prop_until_add_equals_other(wd1: Weekday, wd2: Weekday) -> bool {
834            let days = wd1.until(wd2);
835            wd1.wrapping_add(days) == wd2
836        }
837    }
838}