1 | use 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)] |
93 | pub 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 | |
103 | impl 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 | |
525 | impl 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 | |
618 | impl core::ops::Add<i8> for Weekday { |
619 | type Output = Weekday; |
620 | |
621 | #[inline ] |
622 | fn add(self, rhs: i8) -> Weekday { |
623 | self.wrapping_add(days:rhs) |
624 | } |
625 | } |
626 | |
627 | impl core::ops::Add<i16> for Weekday { |
628 | type Output = Weekday; |
629 | |
630 | #[inline ] |
631 | fn add(self, rhs: i16) -> Weekday { |
632 | self.wrapping_add(days:rhs) |
633 | } |
634 | } |
635 | |
636 | impl core::ops::Add<i32> for Weekday { |
637 | type Output = Weekday; |
638 | |
639 | #[inline ] |
640 | fn add(self, rhs: i32) -> Weekday { |
641 | self.wrapping_add(days:rhs) |
642 | } |
643 | } |
644 | |
645 | impl core::ops::Add<i64> for Weekday { |
646 | type Output = Weekday; |
647 | |
648 | #[inline ] |
649 | fn add(self, rhs: i64) -> Weekday { |
650 | self.wrapping_add(days:rhs) |
651 | } |
652 | } |
653 | |
654 | // Since addition is commutative, we don't might if users write `n + weekday` |
655 | // or `weekday + n`. |
656 | |
657 | impl 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 | |
666 | impl 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 | |
675 | impl 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 | |
684 | impl 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 | |
693 | impl core::ops::AddAssign<i8> for Weekday { |
694 | #[inline ] |
695 | fn add_assign(&mut self, rhs: i8) { |
696 | *self = *self + rhs; |
697 | } |
698 | } |
699 | |
700 | impl core::ops::AddAssign<i16> for Weekday { |
701 | #[inline ] |
702 | fn add_assign(&mut self, rhs: i16) { |
703 | *self = *self + rhs; |
704 | } |
705 | } |
706 | |
707 | impl core::ops::AddAssign<i32> for Weekday { |
708 | #[inline ] |
709 | fn add_assign(&mut self, rhs: i32) { |
710 | *self = *self + rhs; |
711 | } |
712 | } |
713 | |
714 | impl 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 | |
725 | impl core::ops::Sub<i8> for Weekday { |
726 | type Output = Weekday; |
727 | |
728 | #[inline ] |
729 | fn sub(self, rhs: i8) -> Weekday { |
730 | self.wrapping_sub(days:rhs) |
731 | } |
732 | } |
733 | |
734 | impl core::ops::Sub<i16> for Weekday { |
735 | type Output = Weekday; |
736 | |
737 | #[inline ] |
738 | fn sub(self, rhs: i16) -> Weekday { |
739 | self.wrapping_sub(days:rhs) |
740 | } |
741 | } |
742 | |
743 | impl core::ops::Sub<i32> for Weekday { |
744 | type Output = Weekday; |
745 | |
746 | #[inline ] |
747 | fn sub(self, rhs: i32) -> Weekday { |
748 | self.wrapping_sub(days:rhs) |
749 | } |
750 | } |
751 | |
752 | impl core::ops::Sub<i64> for Weekday { |
753 | type Output = Weekday; |
754 | |
755 | #[inline ] |
756 | fn sub(self, rhs: i64) -> Weekday { |
757 | self.wrapping_sub(days:rhs) |
758 | } |
759 | } |
760 | |
761 | impl core::ops::SubAssign<i8> for Weekday { |
762 | #[inline ] |
763 | fn sub_assign(&mut self, rhs: i8) { |
764 | *self = *self - rhs; |
765 | } |
766 | } |
767 | |
768 | impl core::ops::SubAssign<i16> for Weekday { |
769 | #[inline ] |
770 | fn sub_assign(&mut self, rhs: i16) { |
771 | *self = *self - rhs; |
772 | } |
773 | } |
774 | |
775 | impl core::ops::SubAssign<i32> for Weekday { |
776 | #[inline ] |
777 | fn sub_assign(&mut self, rhs: i32) { |
778 | *self = *self - rhs; |
779 | } |
780 | } |
781 | |
782 | impl 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)] |
790 | impl 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)] |
809 | pub struct WeekdaysForward { |
810 | it: core::iter::Cycle<core::array::IntoIter<Weekday, 7>>, |
811 | } |
812 | |
813 | impl Iterator for WeekdaysForward { |
814 | type Item = Weekday; |
815 | |
816 | #[inline ] |
817 | fn next(&mut self) -> Option<Weekday> { |
818 | self.it.next() |
819 | } |
820 | } |
821 | |
822 | impl 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)] |
828 | pub struct WeekdaysReverse { |
829 | it: core::iter::Cycle<core::array::IntoIter<Weekday, 7>>, |
830 | } |
831 | |
832 | impl Iterator for WeekdaysReverse { |
833 | type Item = Weekday; |
834 | |
835 | #[inline ] |
836 | fn next(&mut self) -> Option<Weekday> { |
837 | self.it.next() |
838 | } |
839 | } |
840 | |
841 | impl core::iter::FusedIterator for WeekdaysReverse {} |
842 | |
843 | #[cfg (test)] |
844 | mod 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 | } |
859 | |