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}