Skip to main content

jiff/civil/
weekday.rs

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