1#![cfg_attr(feature = "__internal_bench", allow(missing_docs))]
4
5use core::fmt;
6
7#[allow(unreachable_pub)] #[derive(PartialEq, Eq, Copy, Clone, Hash)]
19pub struct YearFlags(pub(super) u8);
20
21const YEAR_STARTS_AFTER_MONDAY: u8 = 7; const YEAR_STARTS_AFTER_THUESDAY: u8 = 1;
25const YEAR_STARTS_AFTER_WEDNESDAY: u8 = 2;
26const YEAR_STARTS_AFTER_THURSDAY: u8 = 3;
27const YEAR_STARTS_AFTER_FRIDAY: u8 = 4;
28const YEAR_STARTS_AFTER_SATURDAY: u8 = 5;
29const YEAR_STARTS_AFTER_SUNDAY: u8 = 6;
30
31const COMMON_YEAR: u8 = 1 << 3;
32const LEAP_YEAR: u8 = 0 << 3;
33
34pub(super) const A: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_SATURDAY);
35pub(super) const AG: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_SATURDAY);
36pub(super) const B: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_FRIDAY);
37pub(super) const BA: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_FRIDAY);
38pub(super) const C: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_THURSDAY);
39pub(super) const CB: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_THURSDAY);
40pub(super) const D: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_WEDNESDAY);
41pub(super) const DC: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_WEDNESDAY);
42pub(super) const E: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_THUESDAY);
43pub(super) const ED: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_THUESDAY);
44pub(super) const F: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_MONDAY);
45pub(super) const FE: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_MONDAY);
46pub(super) const G: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_SUNDAY);
47pub(super) const GF: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_SUNDAY);
48
49const YEAR_TO_FLAGS: &[YearFlags; 400] = &[
50 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,
51 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,
52 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,
53 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,
55 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,
56 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,
57 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,
59 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,
60 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,
61 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,
63 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,
64 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,
65 D, CB, A, G, F, ED, C, B, A, GF, E, D, C, ];
67
68impl YearFlags {
69 #[allow(unreachable_pub)] #[doc(hidden)] #[inline]
72 #[must_use]
73 pub const fn from_year(year: i32) -> YearFlags {
74 let year = year.rem_euclid(400);
75 YearFlags::from_year_mod_400(year)
76 }
77
78 #[inline]
79 pub(super) const fn from_year_mod_400(year: i32) -> YearFlags {
80 YEAR_TO_FLAGS[year as usize]
81 }
82
83 #[inline]
84 pub(super) const fn ndays(&self) -> u32 {
85 let YearFlags(flags) = *self;
86 366 - (flags >> 3) as u32
87 }
88
89 #[inline]
90 pub(super) const fn isoweek_delta(&self) -> u32 {
91 let YearFlags(flags) = *self;
92 let mut delta = (flags & 0b0111) as u32;
93 if delta < 3 {
94 delta += 7;
95 }
96 delta
97 }
98
99 #[inline]
100 pub(super) const fn nisoweeks(&self) -> u32 {
101 let YearFlags(flags) = *self;
102 52 + ((0b0000_0100_0000_0110 >> flags as usize) & 1)
103 }
104}
105
106impl fmt::Debug for YearFlags {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 let YearFlags(flags) = *self;
109 match flags {
110 0o15 => "A".fmt(f),
111 0o05 => "AG".fmt(f),
112 0o14 => "B".fmt(f),
113 0o04 => "BA".fmt(f),
114 0o13 => "C".fmt(f),
115 0o03 => "CB".fmt(f),
116 0o12 => "D".fmt(f),
117 0o02 => "DC".fmt(f),
118 0o11 => "E".fmt(f),
119 0o01 => "ED".fmt(f),
120 0o10 => "F?".fmt(f),
121 0o00 => "FE?".fmt(f), 0o17 => "F".fmt(f),
123 0o07 => "FE".fmt(f),
124 0o16 => "G".fmt(f),
125 0o06 => "GF".fmt(f),
126 _ => write!(f, "YearFlags({})", flags),
127 }
128 }
129}
130
131const MAX_OL: u32 = 366 << 1; const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
134
135const XX: i8 = 0;
139const MDL_TO_OL: &[i8; MAX_MDL as usize + 1] = &[
140 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
141 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
142 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,
144 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
145 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,
147 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
148 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,
150 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
151 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,
153 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
154 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,
156 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
157 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,
159 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
160 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,
162 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
163 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,
165 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
166 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,
168 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
169 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,
171 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
172 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,
174 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
175 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,
177 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
178 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
179 100, ];
181
182const OL_TO_MDL: &[u8; MAX_OL as usize + 1] = &[
183 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,
185 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
186 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,
188 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
189 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,
191 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72,
192 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,
194 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74,
195 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,
197 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78,
198 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,
200 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80,
201 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,
203 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84,
204 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,
206 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86,
207 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,
209 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88,
210 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,
212 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92,
213 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,
215 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94,
216 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,
218 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
219 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
220 98, ];
222
223#[derive(PartialEq, PartialOrd, Copy, Clone)]
237pub(super) struct Mdf(u32);
238
239impl Mdf {
240 #[inline]
249 pub(super) const fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option<Mdf> {
250 match month <= 12 && day <= 31 {
251 true => Some(Mdf((month << 9) | (day << 4) | flags as u32)),
252 false => None,
253 }
254 }
255
256 #[inline]
261 pub(super) const fn from_ol(ol: i32, YearFlags(flags): YearFlags) -> Mdf {
262 debug_assert!(ol > 1 && ol <= MAX_OL as i32);
263 Mdf(((ol as u32 + OL_TO_MDL[ol as usize] as u32) << 3) | flags as u32)
265 }
266
267 #[inline]
269 pub(super) const fn month(&self) -> u32 {
270 let Mdf(mdf) = *self;
271 mdf >> 9
272 }
273
274 #[inline]
280 pub(super) const fn with_month(&self, month: u32) -> Option<Mdf> {
281 if month > 12 {
282 return None;
283 }
284
285 let Mdf(mdf) = *self;
286 Some(Mdf((mdf & 0b1_1111_1111) | (month << 9)))
287 }
288
289 #[inline]
291 pub(super) const fn day(&self) -> u32 {
292 let Mdf(mdf) = *self;
293 (mdf >> 4) & 0b1_1111
294 }
295
296 #[inline]
302 pub(super) const fn with_day(&self, day: u32) -> Option<Mdf> {
303 if day > 31 {
304 return None;
305 }
306
307 let Mdf(mdf) = *self;
308 Some(Mdf((mdf & !0b1_1111_0000) | (day << 4)))
309 }
310
311 #[inline]
313 pub(super) const fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf {
314 let Mdf(mdf) = *self;
315 Mdf((mdf & !0b1111) | flags as u32)
316 }
317
318 #[inline]
328 pub(super) const fn ordinal(&self) -> Option<u32> {
329 let mdl = self.0 >> 3;
330 match MDL_TO_OL[mdl as usize] {
331 XX => None,
332 v => Some((mdl - v as u8 as u32) >> 1),
333 }
334 }
335
336 #[inline]
338 pub(super) const fn year_flags(&self) -> YearFlags {
339 YearFlags((self.0 & 0b1111) as u8)
340 }
341
342 #[inline]
352 pub(super) const fn ordinal_and_flags(&self) -> Option<i32> {
353 let mdl = self.0 >> 3;
354 match MDL_TO_OL[mdl as usize] {
355 XX => None,
356 v => Some(self.0 as i32 - ((v as i32) << 3)),
357 }
358 }
359
360 #[cfg(test)]
361 fn valid(&self) -> bool {
362 let mdl = self.0 >> 3;
363 MDL_TO_OL[mdl as usize] > 0
364 }
365}
366
367impl fmt::Debug for Mdf {
368 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
369 let Mdf(mdf) = *self;
370 write!(
371 f,
372 "Mdf(({} << 9) | ({} << 4) | {:#04o} /*{:?}*/)",
373 mdf >> 9,
374 (mdf >> 4) & 0b1_1111,
375 mdf & 0b1111,
376 YearFlags((mdf & 0b1111) as u8)
377 )
378 }
379}
380
381#[cfg(test)]
382mod tests {
383 use super::Mdf;
384 use super::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF};
385
386 const NONLEAP_FLAGS: [YearFlags; 7] = [A, B, C, D, E, F, G];
387 const LEAP_FLAGS: [YearFlags; 7] = [AG, BA, CB, DC, ED, FE, GF];
388 const FLAGS: [YearFlags; 14] = [A, B, C, D, E, F, G, AG, BA, CB, DC, ED, FE, GF];
389
390 #[test]
391 fn test_year_flags_ndays_from_year() {
392 assert_eq!(YearFlags::from_year(2014).ndays(), 365);
393 assert_eq!(YearFlags::from_year(2012).ndays(), 366);
394 assert_eq!(YearFlags::from_year(2000).ndays(), 366);
395 assert_eq!(YearFlags::from_year(1900).ndays(), 365);
396 assert_eq!(YearFlags::from_year(1600).ndays(), 366);
397 assert_eq!(YearFlags::from_year(1).ndays(), 365);
398 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); }
406
407 #[test]
408 fn test_year_flags_nisoweeks() {
409 assert_eq!(A.nisoweeks(), 52);
410 assert_eq!(B.nisoweeks(), 52);
411 assert_eq!(C.nisoweeks(), 52);
412 assert_eq!(D.nisoweeks(), 53);
413 assert_eq!(E.nisoweeks(), 52);
414 assert_eq!(F.nisoweeks(), 52);
415 assert_eq!(G.nisoweeks(), 52);
416 assert_eq!(AG.nisoweeks(), 52);
417 assert_eq!(BA.nisoweeks(), 52);
418 assert_eq!(CB.nisoweeks(), 52);
419 assert_eq!(DC.nisoweeks(), 53);
420 assert_eq!(ED.nisoweeks(), 53);
421 assert_eq!(FE.nisoweeks(), 52);
422 assert_eq!(GF.nisoweeks(), 52);
423 }
424
425 #[test]
426 fn test_mdf_valid() {
427 fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, month2: u32, day2: u32) {
428 for month in month1..=month2 {
429 for day in day1..=day2 {
430 let mdf = match Mdf::new(month, day, flags) {
431 Some(mdf) => mdf,
432 None if !expected => continue,
433 None => panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags),
434 };
435
436 assert!(
437 mdf.valid() == expected,
438 "month {} day {} = {:?} should be {} for dominical year {:?}",
439 month,
440 day,
441 mdf,
442 if expected { "valid" } else { "invalid" },
443 flags
444 );
445 }
446 }
447 }
448
449 for &flags in NONLEAP_FLAGS.iter() {
450 check(false, flags, 0, 0, 0, 1024);
451 check(false, flags, 0, 0, 16, 0);
452 check(true, flags, 1, 1, 1, 31);
453 check(false, flags, 1, 32, 1, 1024);
454 check(true, flags, 2, 1, 2, 28);
455 check(false, flags, 2, 29, 2, 1024);
456 check(true, flags, 3, 1, 3, 31);
457 check(false, flags, 3, 32, 3, 1024);
458 check(true, flags, 4, 1, 4, 30);
459 check(false, flags, 4, 31, 4, 1024);
460 check(true, flags, 5, 1, 5, 31);
461 check(false, flags, 5, 32, 5, 1024);
462 check(true, flags, 6, 1, 6, 30);
463 check(false, flags, 6, 31, 6, 1024);
464 check(true, flags, 7, 1, 7, 31);
465 check(false, flags, 7, 32, 7, 1024);
466 check(true, flags, 8, 1, 8, 31);
467 check(false, flags, 8, 32, 8, 1024);
468 check(true, flags, 9, 1, 9, 30);
469 check(false, flags, 9, 31, 9, 1024);
470 check(true, flags, 10, 1, 10, 31);
471 check(false, flags, 10, 32, 10, 1024);
472 check(true, flags, 11, 1, 11, 30);
473 check(false, flags, 11, 31, 11, 1024);
474 check(true, flags, 12, 1, 12, 31);
475 check(false, flags, 12, 32, 12, 1024);
476 check(false, flags, 13, 0, 16, 1024);
477 check(false, flags, u32::MAX, 0, u32::MAX, 1024);
478 check(false, flags, 0, u32::MAX, 16, u32::MAX);
479 check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
480 }
481
482 for &flags in LEAP_FLAGS.iter() {
483 check(false, flags, 0, 0, 0, 1024);
484 check(false, flags, 0, 0, 16, 0);
485 check(true, flags, 1, 1, 1, 31);
486 check(false, flags, 1, 32, 1, 1024);
487 check(true, flags, 2, 1, 2, 29);
488 check(false, flags, 2, 30, 2, 1024);
489 check(true, flags, 3, 1, 3, 31);
490 check(false, flags, 3, 32, 3, 1024);
491 check(true, flags, 4, 1, 4, 30);
492 check(false, flags, 4, 31, 4, 1024);
493 check(true, flags, 5, 1, 5, 31);
494 check(false, flags, 5, 32, 5, 1024);
495 check(true, flags, 6, 1, 6, 30);
496 check(false, flags, 6, 31, 6, 1024);
497 check(true, flags, 7, 1, 7, 31);
498 check(false, flags, 7, 32, 7, 1024);
499 check(true, flags, 8, 1, 8, 31);
500 check(false, flags, 8, 32, 8, 1024);
501 check(true, flags, 9, 1, 9, 30);
502 check(false, flags, 9, 31, 9, 1024);
503 check(true, flags, 10, 1, 10, 31);
504 check(false, flags, 10, 32, 10, 1024);
505 check(true, flags, 11, 1, 11, 30);
506 check(false, flags, 11, 31, 11, 1024);
507 check(true, flags, 12, 1, 12, 31);
508 check(false, flags, 12, 32, 12, 1024);
509 check(false, flags, 13, 0, 16, 1024);
510 check(false, flags, u32::MAX, 0, u32::MAX, 1024);
511 check(false, flags, 0, u32::MAX, 16, u32::MAX);
512 check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
513 }
514 }
515
516 #[test]
517 fn test_mdf_fields() {
518 for &flags in FLAGS.iter() {
519 for month in 1u32..=12 {
520 for day in 1u32..31 {
521 let mdf = match Mdf::new(month, day, flags) {
522 Some(mdf) => mdf,
523 None => continue,
524 };
525
526 if mdf.valid() {
527 assert_eq!(mdf.month(), month);
528 assert_eq!(mdf.day(), day);
529 }
530 }
531 }
532 }
533 }
534
535 #[test]
536 fn test_mdf_with_fields() {
537 fn check(flags: YearFlags, month: u32, day: u32) {
538 let mdf = Mdf::new(month, day, flags).unwrap();
539
540 for month in 0u32..=16 {
541 let mdf = match mdf.with_month(month) {
542 Some(mdf) => mdf,
543 None if month > 12 => continue,
544 None => panic!("failed to create Mdf with month {}", month),
545 };
546
547 if mdf.valid() {
548 assert_eq!(mdf.month(), month);
549 assert_eq!(mdf.day(), day);
550 }
551 }
552
553 for day in 0u32..=1024 {
554 let mdf = match mdf.with_day(day) {
555 Some(mdf) => mdf,
556 None if day > 31 => continue,
557 None => panic!("failed to create Mdf with month {}", month),
558 };
559
560 if mdf.valid() {
561 assert_eq!(mdf.month(), month);
562 assert_eq!(mdf.day(), day);
563 }
564 }
565 }
566
567 for &flags in NONLEAP_FLAGS.iter() {
568 check(flags, 1, 1);
569 check(flags, 1, 31);
570 check(flags, 2, 1);
571 check(flags, 2, 28);
572 check(flags, 2, 29);
573 check(flags, 12, 31);
574 }
575 for &flags in LEAP_FLAGS.iter() {
576 check(flags, 1, 1);
577 check(flags, 1, 31);
578 check(flags, 2, 1);
579 check(flags, 2, 29);
580 check(flags, 2, 30);
581 check(flags, 12, 31);
582 }
583 }
584
585 #[test]
586 fn test_mdf_new_range() {
587 let flags = YearFlags::from_year(2023);
588 assert!(Mdf::new(13, 1, flags).is_none());
589 assert!(Mdf::new(1, 32, flags).is_none());
590 }
591}