1#![cfg_attr(feature = "__internal_bench", allow(missing_docs))]
17
18use crate::Weekday;
19use core::fmt;
20
21pub(super) type DateImpl = i32;
23
24pub(super) const MAX_YEAR: DateImpl = (i32::MAX >> 13) - 1;
28
29pub(super) const MIN_YEAR: DateImpl = (i32::MIN >> 13) + 1;
33
34#[allow(unreachable_pub)] #[derive(PartialEq, Eq, Copy, Clone, Hash)]
44pub struct YearFlags(pub(super) u8);
45
46pub(super) const A: YearFlags = YearFlags(0o15);
47pub(super) const AG: YearFlags = YearFlags(0o05);
48pub(super) const B: YearFlags = YearFlags(0o14);
49pub(super) const BA: YearFlags = YearFlags(0o04);
50pub(super) const C: YearFlags = YearFlags(0o13);
51pub(super) const CB: YearFlags = YearFlags(0o03);
52pub(super) const D: YearFlags = YearFlags(0o12);
53pub(super) const DC: YearFlags = YearFlags(0o02);
54pub(super) const E: YearFlags = YearFlags(0o11);
55pub(super) const ED: YearFlags = YearFlags(0o01);
56pub(super) const F: YearFlags = YearFlags(0o17);
57pub(super) const FE: YearFlags = YearFlags(0o07);
58pub(super) const G: YearFlags = YearFlags(0o16);
59pub(super) const GF: YearFlags = YearFlags(0o06);
60
61const YEAR_TO_FLAGS: &[YearFlags; 400] = &[
62 BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA,
63 G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G,
64 F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F,
65 E, DC, B, A, G, FE, D, C, B, AG, F, E, D, C, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC,
67 B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B,
68 A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A,
69 G, FE, D, C, B, AG, F, E, D, CB, A, G, F, E, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE,
71 D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D,
72 C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C,
73 B, AG, F, E, D, CB, A, G, F, ED, C, B, A, G, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG,
75 F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F,
76 E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E,
77 D, CB, A, G, F, ED, C, B, A, GF, E, D, C, ];
79
80const YEAR_DELTAS: &[u8; 401] = &[
81 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
82 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14,
83 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20,
84 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30,
86 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36,
87 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42,
88 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48,
89 48, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54,
91 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60,
92 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66,
93 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72,
94 72, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78,
96 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84,
97 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90,
98 90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96,
99 96, 97, 97, 97, 97, ];
101
102pub(super) const fn cycle_to_yo(cycle: u32) -> (u32, u32) {
103 let mut year_mod_400 = cycle / 365;
104 let mut ordinal0 = cycle % 365;
105 let delta = YEAR_DELTAS[year_mod_400 as usize] as u32;
106 if ordinal0 < delta {
107 year_mod_400 -= 1;
108 ordinal0 += 365 - YEAR_DELTAS[year_mod_400 as usize] as u32;
109 } else {
110 ordinal0 -= delta;
111 }
112 (year_mod_400, ordinal0 + 1)
113}
114
115pub(super) const fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 {
116 year_mod_400 * 365 + YEAR_DELTAS[year_mod_400 as usize] as u32 + ordinal - 1
117}
118
119impl YearFlags {
120 #[allow(unreachable_pub)] #[doc(hidden)] #[inline]
123 #[must_use]
124 pub const fn from_year(year: i32) -> YearFlags {
125 let year = year.rem_euclid(400);
126 YearFlags::from_year_mod_400(year)
127 }
128
129 #[inline]
130 pub(super) const fn from_year_mod_400(year: i32) -> YearFlags {
131 YEAR_TO_FLAGS[year as usize]
132 }
133
134 #[inline]
135 pub(super) const fn ndays(&self) -> u32 {
136 let YearFlags(flags) = *self;
137 366 - (flags >> 3) as u32
138 }
139
140 #[inline]
141 pub(super) const fn isoweek_delta(&self) -> u32 {
142 let YearFlags(flags) = *self;
143 let mut delta = (flags & 0b0111) as u32;
144 if delta < 3 {
145 delta += 7;
146 }
147 delta
148 }
149
150 #[inline]
151 pub(super) const fn nisoweeks(&self) -> u32 {
152 let YearFlags(flags) = *self;
153 52 + ((0b0000_0100_0000_0110 >> flags as usize) & 1)
154 }
155}
156
157impl fmt::Debug for YearFlags {
158 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159 let YearFlags(flags) = *self;
160 match flags {
161 0o15 => "A".fmt(f),
162 0o05 => "AG".fmt(f),
163 0o14 => "B".fmt(f),
164 0o04 => "BA".fmt(f),
165 0o13 => "C".fmt(f),
166 0o03 => "CB".fmt(f),
167 0o12 => "D".fmt(f),
168 0o02 => "DC".fmt(f),
169 0o11 => "E".fmt(f),
170 0o01 => "ED".fmt(f),
171 0o10 => "F?".fmt(f),
172 0o00 => "FE?".fmt(f), 0o17 => "F".fmt(f),
174 0o07 => "FE".fmt(f),
175 0o16 => "G".fmt(f),
176 0o06 => "GF".fmt(f),
177 _ => write!(f, "YearFlags({})", flags),
178 }
179 }
180}
181
182pub(super) const MIN_OL: u32 = 1 << 1;
184pub(super) const MAX_OL: u32 = 366 << 1; pub(super) const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
186
187const XX: i8 = -128;
188const MDL_TO_OL: &[i8; MAX_MDL as usize + 1] = &[
189 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
190 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
191 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
193 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
194 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, XX, XX, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
196 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
197 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, XX, XX, XX, XX, XX, XX, XX, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
199 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
200 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, XX, XX, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
202 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
203 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, XX, XX, XX, XX, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
205 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
206 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, XX, XX, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
208 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
209 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, XX, XX, XX, XX, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
211 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
212 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, XX, XX, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
214 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
215 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, XX, XX, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
217 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
218 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, XX, XX, XX, XX, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
220 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
221 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, XX, XX, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
223 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
224 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, XX, XX, XX, XX, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
226 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
227 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
228 100, ];
230
231const OL_TO_MDL: &[u8; MAX_OL as usize + 1] = &[
232 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
234 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
235 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
237 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
238 66, 66, 66, 66, 66, 66, 66, 66, 66, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72,
240 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72,
241 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74,
243 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74,
244 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78,
246 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78,
247 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80,
249 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80,
250 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84,
252 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84,
253 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86,
255 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86,
256 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88,
258 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88,
259 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92,
261 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92,
262 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94,
264 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94,
265 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
267 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
268 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
269 98, ];
271
272#[derive(PartialEq, PartialOrd, Copy, Clone)]
279pub(super) struct Of(u32);
280
281impl Of {
282 #[inline]
283 pub(super) const fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Option<Of> {
284 let of = Of((ordinal << 4) | flags as u32);
285 of.validate()
286 }
287
288 pub(super) const fn from_date_impl(date_impl: DateImpl) -> Of {
289 Of((date_impl & 0b1_1111_1111_1111) as u32)
291 }
292
293 #[inline]
294 pub(super) const fn from_mdf(Mdf(mdf): Mdf) -> Option<Of> {
295 let mdl = mdf >> 3;
296 if mdl > MAX_MDL {
297 return None;
299 }
300 let v = MDL_TO_OL[mdl as usize];
302 let of = Of(mdf.wrapping_sub((v as i32 as u32 & 0x3ff) << 3));
303 of.validate()
304 }
305
306 #[inline]
307 pub(super) const fn inner(&self) -> u32 {
308 self.0
309 }
310
311 #[inline]
313 const fn ol(&self) -> u32 {
314 self.0 >> 3
315 }
316
317 #[inline]
318 const fn validate(self) -> Option<Of> {
319 let ol = self.ol();
320 match ol >= MIN_OL && ol <= MAX_OL {
321 true => Some(self),
322 false => None,
323 }
324 }
325
326 #[inline]
327 pub(super) const fn ordinal(&self) -> u32 {
328 self.0 >> 4
329 }
330
331 #[inline]
332 pub(super) const fn with_ordinal(&self, ordinal: u32) -> Option<Of> {
333 let of = Of((ordinal << 4) | (self.0 & 0b1111));
334 of.validate()
335 }
336
337 #[inline]
338 pub(super) const fn flags(&self) -> YearFlags {
339 YearFlags((self.0 & 0b1111) as u8)
340 }
341
342 #[inline]
343 pub(super) const fn weekday(&self) -> Weekday {
344 let Of(of) = *self;
345 weekday_from_u32_mod7((of >> 4) + (of & 0b111))
346 }
347
348 #[inline]
349 pub(super) fn isoweekdate_raw(&self) -> (u32, Weekday) {
350 let Of(of) = *self;
352 let weekord = (of >> 4).wrapping_add(self.flags().isoweek_delta());
353 (weekord / 7, weekday_from_u32_mod7(weekord))
354 }
355
356 #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
357 #[inline]
358 pub(super) const fn to_mdf(&self) -> Mdf {
359 Mdf::from_of(*self)
360 }
361
362 #[inline]
364 pub(super) const fn succ(&self) -> Option<Of> {
365 let of = Of(self.0 + (1 << 4));
366 of.validate()
367 }
368
369 #[inline]
371 pub(super) const fn pred(&self) -> Option<Of> {
372 match self.ordinal() {
373 1 => None,
374 _ => Some(Of(self.0 - (1 << 4))),
375 }
376 }
377}
378
379impl fmt::Debug for Of {
380 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
381 let Of(of) = *self;
382 write!(
383 f,
384 "Of(({} << 4) | {:#04o} /*{:?}*/)",
385 of >> 4,
386 of & 0b1111,
387 YearFlags((of & 0b1111) as u8)
388 )
389 }
390}
391
392#[derive(PartialEq, PartialOrd, Copy, Clone)]
402pub(super) struct Mdf(u32);
403
404impl Mdf {
405 #[inline]
406 pub(super) const fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option<Mdf> {
407 match month >= 1 && month <= 12 && day >= 1 && day <= 31 {
408 true => Some(Mdf((month << 9) | (day << 4) | flags as u32)),
409 false => None,
410 }
411 }
412
413 #[inline]
414 pub(super) const fn from_of(Of(of): Of) -> Mdf {
415 let ol = of >> 3;
416 if ol <= MAX_OL {
417 Mdf(of + ((OL_TO_MDL[ol as usize] as u32) << 3))
419 } else {
420 Mdf(0)
422 }
423 }
424
425 #[cfg(test)]
426 pub(super) const fn valid(&self) -> bool {
427 let Mdf(mdf) = *self;
428 let mdl = mdf >> 3;
429 if mdl <= MAX_MDL {
430 MDL_TO_OL[mdl as usize] >= 0
432 } else {
433 false
435 }
436 }
437
438 #[inline]
439 pub(super) const fn month(&self) -> u32 {
440 let Mdf(mdf) = *self;
441 mdf >> 9
442 }
443
444 #[inline]
445 pub(super) const fn with_month(&self, month: u32) -> Option<Mdf> {
446 if month > 12 {
447 return None;
448 }
449
450 let Mdf(mdf) = *self;
451 Some(Mdf((mdf & 0b1_1111_1111) | (month << 9)))
452 }
453
454 #[inline]
455 pub(super) const fn day(&self) -> u32 {
456 let Mdf(mdf) = *self;
457 (mdf >> 4) & 0b1_1111
458 }
459
460 #[inline]
461 pub(super) const fn with_day(&self, day: u32) -> Option<Mdf> {
462 if day > 31 {
463 return None;
464 }
465
466 let Mdf(mdf) = *self;
467 Some(Mdf((mdf & !0b1_1111_0000) | (day << 4)))
468 }
469
470 #[inline]
471 pub(super) const fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf {
472 let Mdf(mdf) = *self;
473 Mdf((mdf & !0b1111) | flags as u32)
474 }
475
476 #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
477 #[inline]
478 pub(super) const fn to_of(&self) -> Option<Of> {
479 Of::from_mdf(*self)
480 }
481}
482
483impl fmt::Debug for Mdf {
484 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
485 let Mdf(mdf) = *self;
486 write!(
487 f,
488 "Mdf(({} << 9) | ({} << 4) | {:#04o} /*{:?}*/)",
489 mdf >> 9,
490 (mdf >> 4) & 0b1_1111,
491 mdf & 0b1111,
492 YearFlags((mdf & 0b1111) as u8)
493 )
494 }
495}
496
497#[inline]
500const fn weekday_from_u32_mod7(n: u32) -> Weekday {
501 match n % 7 {
502 0 => Weekday::Mon,
503 1 => Weekday::Tue,
504 2 => Weekday::Wed,
505 3 => Weekday::Thu,
506 4 => Weekday::Fri,
507 5 => Weekday::Sat,
508 _ => Weekday::Sun,
509 }
510}
511
512#[cfg(test)]
513mod tests {
514 use super::weekday_from_u32_mod7;
515 use super::{Mdf, Of};
516 use super::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF};
517 use crate::Weekday;
518
519 const NONLEAP_FLAGS: [YearFlags; 7] = [A, B, C, D, E, F, G];
520 const LEAP_FLAGS: [YearFlags; 7] = [AG, BA, CB, DC, ED, FE, GF];
521 const FLAGS: [YearFlags; 14] = [A, B, C, D, E, F, G, AG, BA, CB, DC, ED, FE, GF];
522
523 #[test]
524 fn test_year_flags_ndays_from_year() {
525 assert_eq!(YearFlags::from_year(2014).ndays(), 365);
526 assert_eq!(YearFlags::from_year(2012).ndays(), 366);
527 assert_eq!(YearFlags::from_year(2000).ndays(), 366);
528 assert_eq!(YearFlags::from_year(1900).ndays(), 365);
529 assert_eq!(YearFlags::from_year(1600).ndays(), 366);
530 assert_eq!(YearFlags::from_year(1).ndays(), 365);
531 assert_eq!(YearFlags::from_year(0).ndays(), 366); assert_eq!(YearFlags::from_year(-1).ndays(), 365); assert_eq!(YearFlags::from_year(-4).ndays(), 366); assert_eq!(YearFlags::from_year(-99).ndays(), 365); assert_eq!(YearFlags::from_year(-100).ndays(), 365); assert_eq!(YearFlags::from_year(-399).ndays(), 365); assert_eq!(YearFlags::from_year(-400).ndays(), 366); }
539
540 #[test]
541 fn test_year_flags_nisoweeks() {
542 assert_eq!(A.nisoweeks(), 52);
543 assert_eq!(B.nisoweeks(), 52);
544 assert_eq!(C.nisoweeks(), 52);
545 assert_eq!(D.nisoweeks(), 53);
546 assert_eq!(E.nisoweeks(), 52);
547 assert_eq!(F.nisoweeks(), 52);
548 assert_eq!(G.nisoweeks(), 52);
549 assert_eq!(AG.nisoweeks(), 52);
550 assert_eq!(BA.nisoweeks(), 52);
551 assert_eq!(CB.nisoweeks(), 52);
552 assert_eq!(DC.nisoweeks(), 53);
553 assert_eq!(ED.nisoweeks(), 53);
554 assert_eq!(FE.nisoweeks(), 52);
555 assert_eq!(GF.nisoweeks(), 52);
556 }
557
558 #[test]
559 fn test_of() {
560 fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) {
561 for ordinal in ordinal1..=ordinal2 {
562 let of = match Of::new(ordinal, flags) {
563 Some(of) => of,
564 None if !expected => continue,
565 None => panic!("Of::new({}, {:?}) returned None", ordinal, flags),
566 };
567
568 assert!(
569 of.validate().is_some() == expected,
570 "ordinal {} = {:?} should be {} for dominical year {:?}",
571 ordinal,
572 of,
573 if expected { "valid" } else { "invalid" },
574 flags
575 );
576 }
577 }
578
579 for &flags in NONLEAP_FLAGS.iter() {
580 check(false, flags, 0, 0);
581 check(true, flags, 1, 365);
582 check(false, flags, 366, 1024);
583 check(false, flags, u32::MAX, u32::MAX);
584 }
585
586 for &flags in LEAP_FLAGS.iter() {
587 check(false, flags, 0, 0);
588 check(true, flags, 1, 366);
589 check(false, flags, 367, 1024);
590 check(false, flags, u32::MAX, u32::MAX);
591 }
592 }
593
594 #[test]
595 fn test_mdf_valid() {
596 fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, month2: u32, day2: u32) {
597 for month in month1..=month2 {
598 for day in day1..=day2 {
599 let mdf = match Mdf::new(month, day, flags) {
600 Some(mdf) => mdf,
601 None if !expected => continue,
602 None => panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags),
603 };
604
605 assert!(
606 mdf.valid() == expected,
607 "month {} day {} = {:?} should be {} for dominical year {:?}",
608 month,
609 day,
610 mdf,
611 if expected { "valid" } else { "invalid" },
612 flags
613 );
614 }
615 }
616 }
617
618 for &flags in NONLEAP_FLAGS.iter() {
619 check(false, flags, 0, 0, 0, 1024);
620 check(false, flags, 0, 0, 16, 0);
621 check(true, flags, 1, 1, 1, 31);
622 check(false, flags, 1, 32, 1, 1024);
623 check(true, flags, 2, 1, 2, 28);
624 check(false, flags, 2, 29, 2, 1024);
625 check(true, flags, 3, 1, 3, 31);
626 check(false, flags, 3, 32, 3, 1024);
627 check(true, flags, 4, 1, 4, 30);
628 check(false, flags, 4, 31, 4, 1024);
629 check(true, flags, 5, 1, 5, 31);
630 check(false, flags, 5, 32, 5, 1024);
631 check(true, flags, 6, 1, 6, 30);
632 check(false, flags, 6, 31, 6, 1024);
633 check(true, flags, 7, 1, 7, 31);
634 check(false, flags, 7, 32, 7, 1024);
635 check(true, flags, 8, 1, 8, 31);
636 check(false, flags, 8, 32, 8, 1024);
637 check(true, flags, 9, 1, 9, 30);
638 check(false, flags, 9, 31, 9, 1024);
639 check(true, flags, 10, 1, 10, 31);
640 check(false, flags, 10, 32, 10, 1024);
641 check(true, flags, 11, 1, 11, 30);
642 check(false, flags, 11, 31, 11, 1024);
643 check(true, flags, 12, 1, 12, 31);
644 check(false, flags, 12, 32, 12, 1024);
645 check(false, flags, 13, 0, 16, 1024);
646 check(false, flags, u32::MAX, 0, u32::MAX, 1024);
647 check(false, flags, 0, u32::MAX, 16, u32::MAX);
648 check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
649 }
650
651 for &flags in LEAP_FLAGS.iter() {
652 check(false, flags, 0, 0, 0, 1024);
653 check(false, flags, 0, 0, 16, 0);
654 check(true, flags, 1, 1, 1, 31);
655 check(false, flags, 1, 32, 1, 1024);
656 check(true, flags, 2, 1, 2, 29);
657 check(false, flags, 2, 30, 2, 1024);
658 check(true, flags, 3, 1, 3, 31);
659 check(false, flags, 3, 32, 3, 1024);
660 check(true, flags, 4, 1, 4, 30);
661 check(false, flags, 4, 31, 4, 1024);
662 check(true, flags, 5, 1, 5, 31);
663 check(false, flags, 5, 32, 5, 1024);
664 check(true, flags, 6, 1, 6, 30);
665 check(false, flags, 6, 31, 6, 1024);
666 check(true, flags, 7, 1, 7, 31);
667 check(false, flags, 7, 32, 7, 1024);
668 check(true, flags, 8, 1, 8, 31);
669 check(false, flags, 8, 32, 8, 1024);
670 check(true, flags, 9, 1, 9, 30);
671 check(false, flags, 9, 31, 9, 1024);
672 check(true, flags, 10, 1, 10, 31);
673 check(false, flags, 10, 32, 10, 1024);
674 check(true, flags, 11, 1, 11, 30);
675 check(false, flags, 11, 31, 11, 1024);
676 check(true, flags, 12, 1, 12, 31);
677 check(false, flags, 12, 32, 12, 1024);
678 check(false, flags, 13, 0, 16, 1024);
679 check(false, flags, u32::MAX, 0, u32::MAX, 1024);
680 check(false, flags, 0, u32::MAX, 16, u32::MAX);
681 check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
682 }
683 }
684
685 #[test]
686 fn test_of_fields() {
687 for &flags in FLAGS.iter() {
688 for ordinal in 1u32..=366 {
689 if let Some(of) = Of::new(ordinal, flags) {
690 assert_eq!(of.ordinal(), ordinal);
691 }
692 }
693 }
694 }
695
696 #[test]
697 fn test_of_with_fields() {
698 fn check(flags: YearFlags, ordinal: u32) {
699 let of = Of::new(ordinal, flags).unwrap();
700
701 for ordinal in 0u32..=1024 {
702 let of = of.with_ordinal(ordinal);
703 assert_eq!(of, Of::new(ordinal, flags));
704 if let Some(of) = of {
705 assert_eq!(of.ordinal(), ordinal);
706 }
707 }
708 }
709
710 for &flags in NONLEAP_FLAGS.iter() {
711 check(flags, 1);
712 check(flags, 365);
713 }
714 for &flags in LEAP_FLAGS.iter() {
715 check(flags, 1);
716 check(flags, 366);
717 }
718 }
719
720 #[test]
721 fn test_of_weekday() {
722 assert_eq!(Of::new(1, A).unwrap().weekday(), Weekday::Sun);
723 assert_eq!(Of::new(1, B).unwrap().weekday(), Weekday::Sat);
724 assert_eq!(Of::new(1, C).unwrap().weekday(), Weekday::Fri);
725 assert_eq!(Of::new(1, D).unwrap().weekday(), Weekday::Thu);
726 assert_eq!(Of::new(1, E).unwrap().weekday(), Weekday::Wed);
727 assert_eq!(Of::new(1, F).unwrap().weekday(), Weekday::Tue);
728 assert_eq!(Of::new(1, G).unwrap().weekday(), Weekday::Mon);
729 assert_eq!(Of::new(1, AG).unwrap().weekday(), Weekday::Sun);
730 assert_eq!(Of::new(1, BA).unwrap().weekday(), Weekday::Sat);
731 assert_eq!(Of::new(1, CB).unwrap().weekday(), Weekday::Fri);
732 assert_eq!(Of::new(1, DC).unwrap().weekday(), Weekday::Thu);
733 assert_eq!(Of::new(1, ED).unwrap().weekday(), Weekday::Wed);
734 assert_eq!(Of::new(1, FE).unwrap().weekday(), Weekday::Tue);
735 assert_eq!(Of::new(1, GF).unwrap().weekday(), Weekday::Mon);
736
737 for &flags in FLAGS.iter() {
738 let mut prev = Of::new(1, flags).unwrap().weekday();
739 for ordinal in 2u32..=flags.ndays() {
740 let of = Of::new(ordinal, flags).unwrap();
741 let expected = prev.succ();
742 assert_eq!(of.weekday(), expected);
743 prev = expected;
744 }
745 }
746 }
747
748 #[test]
749 fn test_mdf_fields() {
750 for &flags in FLAGS.iter() {
751 for month in 1u32..=12 {
752 for day in 1u32..31 {
753 let mdf = match Mdf::new(month, day, flags) {
754 Some(mdf) => mdf,
755 None => continue,
756 };
757
758 if mdf.valid() {
759 assert_eq!(mdf.month(), month);
760 assert_eq!(mdf.day(), day);
761 }
762 }
763 }
764 }
765 }
766
767 #[test]
768 fn test_mdf_with_fields() {
769 fn check(flags: YearFlags, month: u32, day: u32) {
770 let mdf = Mdf::new(month, day, flags).unwrap();
771
772 for month in 0u32..=16 {
773 let mdf = match mdf.with_month(month) {
774 Some(mdf) => mdf,
775 None if month > 12 => continue,
776 None => panic!("failed to create Mdf with month {}", month),
777 };
778
779 if mdf.valid() {
780 assert_eq!(mdf.month(), month);
781 assert_eq!(mdf.day(), day);
782 }
783 }
784
785 for day in 0u32..=1024 {
786 let mdf = match mdf.with_day(day) {
787 Some(mdf) => mdf,
788 None if day > 31 => continue,
789 None => panic!("failed to create Mdf with month {}", month),
790 };
791
792 if mdf.valid() {
793 assert_eq!(mdf.month(), month);
794 assert_eq!(mdf.day(), day);
795 }
796 }
797 }
798
799 for &flags in NONLEAP_FLAGS.iter() {
800 check(flags, 1, 1);
801 check(flags, 1, 31);
802 check(flags, 2, 1);
803 check(flags, 2, 28);
804 check(flags, 2, 29);
805 check(flags, 12, 31);
806 }
807 for &flags in LEAP_FLAGS.iter() {
808 check(flags, 1, 1);
809 check(flags, 1, 31);
810 check(flags, 2, 1);
811 check(flags, 2, 29);
812 check(flags, 2, 30);
813 check(flags, 12, 31);
814 }
815 }
816
817 #[test]
818 fn test_of_isoweekdate_raw() {
819 for &flags in FLAGS.iter() {
820 let (week, _) = Of::new(4 , flags).unwrap().isoweekdate_raw();
822 assert_eq!(week, 1);
823 }
824 }
825
826 #[test]
827 fn test_of_to_mdf() {
828 for i in 0u32..=8192 {
829 if let Some(of) = Of(i).validate() {
830 assert!(of.to_mdf().valid());
831 }
832 }
833 }
834
835 #[test]
836 fn test_mdf_to_of() {
837 for i in 0u32..=8192 {
838 let mdf = Mdf(i);
839 assert_eq!(mdf.valid(), mdf.to_of().is_some());
840 }
841 }
842
843 #[test]
844 fn test_of_to_mdf_to_of() {
845 for i in 0u32..=8192 {
846 if let Some(of) = Of(i).validate() {
847 assert_eq!(of, of.to_mdf().to_of().unwrap());
848 }
849 }
850 }
851
852 #[test]
853 fn test_mdf_to_of_to_mdf() {
854 for i in 0u32..=8192 {
855 let mdf = Mdf(i);
856 if mdf.valid() {
857 assert_eq!(mdf, mdf.to_of().unwrap().to_mdf());
858 }
859 }
860 }
861
862 #[test]
863 fn test_invalid_returns_none() {
864 let regular_year = YearFlags::from_year(2023);
865 let leap_year = YearFlags::from_year(2024);
866 assert!(Of::new(0, regular_year).is_none());
867 assert!(Of::new(366, regular_year).is_none());
868 assert!(Of::new(366, leap_year).is_some());
869 assert!(Of::new(367, regular_year).is_none());
870
871 assert!(Mdf::new(0, 1, regular_year).is_none());
872 assert!(Mdf::new(13, 1, regular_year).is_none());
873 assert!(Mdf::new(1, 0, regular_year).is_none());
874 assert!(Mdf::new(1, 32, regular_year).is_none());
875 assert!(Mdf::new(2, 31, regular_year).is_some());
876
877 assert!(Of::from_mdf(Mdf::new(2, 30, regular_year).unwrap()).is_none());
878 assert!(Of::from_mdf(Mdf::new(2, 30, leap_year).unwrap()).is_none());
879 assert!(Of::from_mdf(Mdf::new(2, 29, regular_year).unwrap()).is_none());
880 assert!(Of::from_mdf(Mdf::new(2, 29, leap_year).unwrap()).is_some());
881 assert!(Of::from_mdf(Mdf::new(2, 28, regular_year).unwrap()).is_some());
882
883 assert!(Of::new(365, regular_year).unwrap().succ().is_none());
884 assert!(Of::new(365, leap_year).unwrap().succ().is_some());
885 assert!(Of::new(366, leap_year).unwrap().succ().is_none());
886
887 assert!(Of::new(1, regular_year).unwrap().pred().is_none());
888 assert!(Of::new(1, leap_year).unwrap().pred().is_none());
889 }
890
891 #[test]
892 fn test_weekday_from_u32_mod7() {
893 for i in 0..=1000 {
894 assert_eq!(weekday_from_u32_mod7(i), Weekday::try_from((i % 7) as u8).unwrap());
895 }
896 assert_eq!(weekday_from_u32_mod7(u32::MAX), Weekday::Thu);
897 }
898}