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