/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hifitime-4.2.5/src/weekday.rs
Line | Count | Source |
1 | | /* |
2 | | * Hifitime |
3 | | * Copyright (C) 2017-onward Christopher Rabotin <christopher.rabotin@gmail.com> et al. (cf. https://github.com/nyx-space/hifitime/graphs/contributors) |
4 | | * This Source Code Form is subject to the terms of the Mozilla Public |
5 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | * file, You can obtain one at https://mozilla.org/MPL/2.0/. |
7 | | * |
8 | | * Documentation: https://nyxspace.com/ |
9 | | */ |
10 | | |
11 | | use crate::{Duration, ParsingError, Unit}; |
12 | | use core::fmt; |
13 | | use core::ops::{Add, AddAssign, Sub, SubAssign}; |
14 | | use core::str::FromStr; |
15 | | |
16 | | #[cfg(feature = "python")] |
17 | | use pyo3::prelude::*; |
18 | | |
19 | | #[cfg(feature = "serde")] |
20 | | use serde_derive::{Deserialize, Serialize}; |
21 | | |
22 | | #[cfg_attr(kani, derive(kani::Arbitrary))] |
23 | | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] |
24 | | #[repr(u8)] |
25 | | #[cfg_attr(feature = "python", pyclass(eq, eq_int))] |
26 | | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
27 | | #[derive(Default)] |
28 | | pub enum Weekday { |
29 | | #[default] |
30 | | Monday = 0, |
31 | | Tuesday = 1, |
32 | | Wednesday = 2, |
33 | | Thursday = 3, |
34 | | Friday = 4, |
35 | | Saturday = 5, |
36 | | Sunday = 6, |
37 | | } |
38 | | |
39 | | impl Weekday { |
40 | | /// Max: last weekday <=> `Sunday`, used only for conversion to/from u8. |
41 | | const MAX: u8 = 7; |
42 | | /// Trivial, but avoid magic numbers. |
43 | | pub(crate) const DAYS_PER_WEEK: f64 = 7.0; |
44 | | /// Trivial, but avoid magic numbers. |
45 | | pub(crate) const DAYS_PER_WEEK_I128: i128 = 7; |
46 | | |
47 | | // C89 defines Sunday as zero (which is stupid) |
48 | 0 | pub(crate) fn to_c89_weekday(self) -> u8 { |
49 | 0 | let c89_weekday: u8 = (self + 1).into(); |
50 | 0 | c89_weekday |
51 | 0 | } |
52 | | } |
53 | | |
54 | | impl From<u8> for Weekday { |
55 | 0 | fn from(u: u8) -> Self { |
56 | 0 | match u.rem_euclid(Self::MAX) { |
57 | 0 | 0 => Self::Monday, |
58 | 0 | 1 => Self::Tuesday, |
59 | 0 | 2 => Self::Wednesday, |
60 | 0 | 3 => Self::Thursday, |
61 | 0 | 4 => Self::Friday, |
62 | 0 | 5 => Self::Saturday, |
63 | 0 | 6 => Self::Sunday, |
64 | 0 | _ => Self::default(), // Defaults back to default for other values. |
65 | | } |
66 | 0 | } |
67 | | } |
68 | | |
69 | | impl From<i8> for Weekday { |
70 | 0 | fn from(i: i8) -> Self { |
71 | 0 | Self::from((i.rem_euclid(Self::MAX as i8) + Self::MAX as i8) as u8) |
72 | 0 | } |
73 | | } |
74 | | |
75 | | impl From<Weekday> for u8 { |
76 | 0 | fn from(week: Weekday) -> Self { |
77 | 0 | match week { |
78 | 0 | Weekday::Monday => 0, |
79 | 0 | Weekday::Tuesday => 1, |
80 | 0 | Weekday::Wednesday => 2, |
81 | 0 | Weekday::Thursday => 3, |
82 | 0 | Weekday::Friday => 4, |
83 | 0 | Weekday::Saturday => 5, |
84 | 0 | Weekday::Sunday => 6, |
85 | | } |
86 | 0 | } |
87 | | } |
88 | | |
89 | | impl FromStr for Weekday { |
90 | | type Err = ParsingError; |
91 | 0 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
92 | 0 | match s.trim() { |
93 | 0 | "mon" | "Mon" | "MON" | "monday" | "Monday" | "MONDAY" => Ok(Self::Monday), |
94 | 0 | "tue" | "Tue" | "TUE" | "tuesday" | "Tuesday" | "TUESDAY" => Ok(Self::Tuesday), |
95 | 0 | "wed" | "Wed" | "WED" | "wednesday" | "Wednesday" | "WEDNESDAY" => Ok(Self::Wednesday), |
96 | 0 | "thu" | "Thu" | "THU" | "thursday" | "Thursday" | "THURSDAY" => Ok(Self::Thursday), |
97 | 0 | "fri" | "Fri" | "FRI" | "friday" | "Friday" | "FRIDAY" => Ok(Self::Friday), |
98 | 0 | "sat" | "Sat" | "SAT" | "saturday" | "Saturday" | "SATURDAY" => Ok(Self::Saturday), |
99 | 0 | "sun" | "Sun" | "SUN" | "sunday" | "Sunday" | "SUNDAY" => Ok(Self::Sunday), |
100 | 0 | _ => Err(ParsingError::UnknownWeekday), |
101 | | } |
102 | 0 | } |
103 | | } |
104 | | |
105 | | impl Add for Weekday { |
106 | | type Output = Self; |
107 | 0 | fn add(self, rhs: Self) -> Self { |
108 | 0 | Self::from(u8::from(self) + u8::from(rhs)) |
109 | 0 | } |
110 | | } |
111 | | |
112 | | impl Sub for Weekday { |
113 | | type Output = Duration; |
114 | 0 | fn sub(self, rhs: Self) -> Self::Output { |
115 | | // We can safely cast the weekdays as u8 into i8 because the maximum value is 6, and the max value of a i8 is 127. |
116 | 0 | let self_i8 = u8::from(self) as i8; |
117 | 0 | let mut rhs_i8 = u8::from(rhs) as i8; |
118 | 0 | if rhs_i8 - self_i8 < 0 { |
119 | 0 | rhs_i8 += 7; |
120 | 0 | } |
121 | 0 | i64::from(rhs_i8 - self_i8) * Unit::Day |
122 | 0 | } |
123 | | } |
124 | | |
125 | | impl Add<u8> for Weekday { |
126 | | type Output = Self; |
127 | 0 | fn add(self, rhs: u8) -> Self { |
128 | 0 | Self::from(u8::from(self) + rhs) |
129 | 0 | } |
130 | | } |
131 | | |
132 | | impl Sub<u8> for Weekday { |
133 | | type Output = Self; |
134 | 0 | fn sub(self, rhs: u8) -> Self { |
135 | | // We can safely cast the weekdays as u8 into i8 because the maximum value is 6, and the max value of a i8 is 127. |
136 | 0 | Self::from(u8::from(self) as i8 - rhs as i8) |
137 | 0 | } |
138 | | } |
139 | | |
140 | | impl AddAssign<u8> for Weekday { |
141 | 0 | fn add_assign(&mut self, rhs: u8) { |
142 | 0 | *self = *self + rhs; |
143 | 0 | } |
144 | | } |
145 | | |
146 | | impl SubAssign<u8> for Weekday { |
147 | 0 | fn sub_assign(&mut self, rhs: u8) { |
148 | 0 | *self = *self - rhs; |
149 | 0 | } |
150 | | } |
151 | | |
152 | | impl fmt::Display for Weekday { |
153 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
154 | 0 | write!(f, "{self:?}") |
155 | 0 | } |
156 | | } |
157 | | |
158 | | /// LowerHex allows printing the week day in its shortened form in English |
159 | | impl fmt::LowerHex for Weekday { |
160 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
161 | 0 | match self { |
162 | 0 | Self::Monday => write!(f, "Mon"), |
163 | 0 | Self::Tuesday => write!(f, "Tue"), |
164 | 0 | Self::Wednesday => write!(f, "Wed"), |
165 | 0 | Self::Thursday => write!(f, "Thu"), |
166 | 0 | Self::Friday => write!(f, "Fri"), |
167 | 0 | Self::Saturday => write!(f, "Sat"), |
168 | 0 | Self::Sunday => write!(f, "Sun"), |
169 | | } |
170 | 0 | } |
171 | | } |
172 | | |
173 | | #[test] |
174 | | fn test_wrapping() { |
175 | | assert_eq!(Weekday::default(), Weekday::Monday); |
176 | | assert_eq!(Weekday::from(Weekday::MAX), Weekday::Monday); |
177 | | |
178 | | let monday = Weekday::default(); |
179 | | for i in 0..24 { |
180 | | // Test wrapping |
181 | | let add = monday + i; |
182 | | let expected: Weekday = i.rem_euclid(Weekday::MAX).into(); |
183 | | assert_eq!( |
184 | | add, expected, |
185 | | "expecting {expected:?} got {add:?} for {i:02} conversion" |
186 | | ); |
187 | | // Test FromStr |
188 | | } |
189 | | } |
190 | | |
191 | | #[test] |
192 | | fn test_iso_weekday() { |
193 | | assert_eq!(Weekday::Sunday.to_c89_weekday(), 0); |
194 | | assert_eq!(Weekday::Monday.to_c89_weekday(), 1); |
195 | | assert_eq!(Weekday::Tuesday.to_c89_weekday(), 2); |
196 | | assert_eq!(Weekday::Wednesday.to_c89_weekday(), 3); |
197 | | assert_eq!(Weekday::Thursday.to_c89_weekday(), 4); |
198 | | assert_eq!(Weekday::Friday.to_c89_weekday(), 5); |
199 | | assert_eq!(Weekday::Saturday.to_c89_weekday(), 6); |
200 | | } |