/rust/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.41/src/naive/internals.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Internal helper types for working with dates. |
2 | | |
3 | | #![cfg_attr(feature = "__internal_bench", allow(missing_docs))] |
4 | | |
5 | | use core::fmt; |
6 | | |
7 | | /// Year flags (aka the dominical letter). |
8 | | /// |
9 | | /// `YearFlags` are used as the last four bits of `NaiveDate`, `Mdf` and `IsoWeek`. |
10 | | /// |
11 | | /// There are 14 possible classes of year in the Gregorian calendar: |
12 | | /// common and leap years starting with Monday through Sunday. |
13 | | /// |
14 | | /// The `YearFlags` stores this information into 4 bits `LWWW`. `L` is the leap year flag, with `1` |
15 | | /// for the common year (this simplifies validating an ordinal in `NaiveDate`). `WWW` is a non-zero |
16 | | /// `Weekday` of the last day in the preceding year. |
17 | | #[allow(unreachable_pub)] // public as an alias for benchmarks only |
18 | | #[derive(PartialEq, Eq, Copy, Clone, Hash)] |
19 | | pub struct YearFlags(pub(super) u8); |
20 | | |
21 | | // Weekday of the last day in the preceding year. |
22 | | // Allows for quick day of week calculation from the 1-based ordinal. |
23 | | const YEAR_STARTS_AFTER_MONDAY: u8 = 7; // non-zero to allow use with `NonZero*`. |
24 | | const YEAR_STARTS_AFTER_THUESDAY: u8 = 1; |
25 | | const YEAR_STARTS_AFTER_WEDNESDAY: u8 = 2; |
26 | | const YEAR_STARTS_AFTER_THURSDAY: u8 = 3; |
27 | | const YEAR_STARTS_AFTER_FRIDAY: u8 = 4; |
28 | | const YEAR_STARTS_AFTER_SATURDAY: u8 = 5; |
29 | | const YEAR_STARTS_AFTER_SUNDAY: u8 = 6; |
30 | | |
31 | | const COMMON_YEAR: u8 = 1 << 3; |
32 | | const LEAP_YEAR: u8 = 0 << 3; |
33 | | |
34 | | pub(super) const A: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_SATURDAY); |
35 | | pub(super) const AG: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_SATURDAY); |
36 | | pub(super) const B: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_FRIDAY); |
37 | | pub(super) const BA: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_FRIDAY); |
38 | | pub(super) const C: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_THURSDAY); |
39 | | pub(super) const CB: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_THURSDAY); |
40 | | pub(super) const D: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_WEDNESDAY); |
41 | | pub(super) const DC: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_WEDNESDAY); |
42 | | pub(super) const E: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_THUESDAY); |
43 | | pub(super) const ED: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_THUESDAY); |
44 | | pub(super) const F: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_MONDAY); |
45 | | pub(super) const FE: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_MONDAY); |
46 | | pub(super) const G: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_SUNDAY); |
47 | | pub(super) const GF: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_SUNDAY); |
48 | | |
49 | | const 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, // 100 |
54 | | 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, // 200 |
58 | | 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, // 300 |
62 | | 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, // 400 |
66 | | ]; |
67 | | |
68 | | impl YearFlags { |
69 | | #[allow(unreachable_pub)] // public as an alias for benchmarks only |
70 | | #[doc(hidden)] // for benchmarks only |
71 | | #[inline] |
72 | | #[must_use] |
73 | 0 | pub const fn from_year(year: i32) -> YearFlags { |
74 | 0 | let year = year.rem_euclid(400); |
75 | 0 | YearFlags::from_year_mod_400(year) |
76 | 0 | } |
77 | | |
78 | | #[inline] |
79 | 0 | pub(super) const fn from_year_mod_400(year: i32) -> YearFlags { |
80 | 0 | YEAR_TO_FLAGS[year as usize] |
81 | 0 | } |
82 | | |
83 | | #[inline] |
84 | 0 | pub(super) const fn ndays(&self) -> u32 { |
85 | 0 | let YearFlags(flags) = *self; |
86 | 0 | 366 - (flags >> 3) as u32 |
87 | 0 | } |
88 | | |
89 | | #[inline] |
90 | 0 | pub(super) const fn isoweek_delta(&self) -> u32 { |
91 | 0 | let YearFlags(flags) = *self; |
92 | 0 | let mut delta = (flags & 0b0111) as u32; |
93 | 0 | if delta < 3 { |
94 | 0 | delta += 7; |
95 | 0 | } |
96 | 0 | delta |
97 | 0 | } |
98 | | |
99 | | #[inline] |
100 | 0 | pub(super) const fn nisoweeks(&self) -> u32 { |
101 | 0 | let YearFlags(flags) = *self; |
102 | 0 | 52 + ((0b0000_0100_0000_0110 >> flags as usize) & 1) |
103 | 0 | } |
104 | | } |
105 | | |
106 | | impl fmt::Debug for YearFlags { |
107 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
108 | 0 | let YearFlags(flags) = *self; |
109 | 0 | match flags { |
110 | 0 | 0o15 => "A".fmt(f), |
111 | 0 | 0o05 => "AG".fmt(f), |
112 | 0 | 0o14 => "B".fmt(f), |
113 | 0 | 0o04 => "BA".fmt(f), |
114 | 0 | 0o13 => "C".fmt(f), |
115 | 0 | 0o03 => "CB".fmt(f), |
116 | 0 | 0o12 => "D".fmt(f), |
117 | 0 | 0o02 => "DC".fmt(f), |
118 | 0 | 0o11 => "E".fmt(f), |
119 | 0 | 0o01 => "ED".fmt(f), |
120 | 0 | 0o10 => "F?".fmt(f), |
121 | 0 | 0o00 => "FE?".fmt(f), // non-canonical |
122 | 0 | 0o17 => "F".fmt(f), |
123 | 0 | 0o07 => "FE".fmt(f), |
124 | 0 | 0o16 => "G".fmt(f), |
125 | 0 | 0o06 => "GF".fmt(f), |
126 | 0 | _ => write!(f, "YearFlags({})", flags), |
127 | | } |
128 | 0 | } |
129 | | } |
130 | | |
131 | | // OL: (ordinal << 1) | leap year flag |
132 | | const MAX_OL: u32 = 366 << 1; // `(366 << 1) | 1` would be day 366 in a non-leap year |
133 | | const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1; |
134 | | |
135 | | // The next table are adjustment values to convert a date encoded as month-day-leapyear to |
136 | | // ordinal-leapyear. OL = MDL - adjustment. |
137 | | // Dates that do not exist are encoded as `XX`. |
138 | | const XX: i8 = 0; |
139 | | const 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, // 0 |
143 | | 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, // 1 |
146 | | 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, // 2 |
149 | | 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, // 3 |
152 | | 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, // 4 |
155 | | 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, // 5 |
158 | | 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, // 6 |
161 | | 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, // 7 |
164 | | 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, // 8 |
167 | | 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, // 9 |
170 | | 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, // 10 |
173 | | 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, // 11 |
176 | | 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, // 12 |
180 | | ]; |
181 | | |
182 | | const OL_TO_MDL: &[u8; MAX_OL as usize + 1] = &[ |
183 | | 0, 0, // 0 |
184 | | 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, // 1 |
187 | | 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, // 2 |
190 | | 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, // 3 |
193 | | 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, // 4 |
196 | | 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, // 5 |
199 | | 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, // 6 |
202 | | 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, // 7 |
205 | | 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, // 8 |
208 | | 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, // 9 |
211 | | 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, // 10 |
214 | | 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, // 11 |
217 | | 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, // 12 |
221 | | ]; |
222 | | |
223 | | /// Month, day of month and year flags: `(month << 9) | (day << 4) | flags` |
224 | | /// `M_MMMD_DDDD_LFFF` |
225 | | /// |
226 | | /// The whole bits except for the least 3 bits are referred as `Mdl` (month, day of month, and leap |
227 | | /// year flag), which is an index to the `MDL_TO_OL` lookup table. |
228 | | /// |
229 | | /// The conversion between the packed calendar date (`Mdf`) and the ordinal date (`NaiveDate`) is |
230 | | /// based on the moderately-sized lookup table (~1.5KB) and the packed representation is chosen for |
231 | | /// efficient lookup. |
232 | | /// |
233 | | /// The methods of `Mdf` validate their inputs as late as possible. Dates that can't exist, like |
234 | | /// February 30, can still be represented. This allows the validation to be combined with the final |
235 | | /// table lookup, which is good for performance. |
236 | | #[derive(PartialEq, PartialOrd, Copy, Clone)] |
237 | | pub(super) struct Mdf(u32); |
238 | | |
239 | | impl Mdf { |
240 | | /// Makes a new `Mdf` value from month, day and `YearFlags`. |
241 | | /// |
242 | | /// This method doesn't fully validate the range of the `month` and `day` parameters, only as |
243 | | /// much as what can't be deferred until later. The year `flags` are trusted to be correct. |
244 | | /// |
245 | | /// # Errors |
246 | | /// |
247 | | /// Returns `None` if `month > 12` or `day > 31`. |
248 | | #[inline] |
249 | 0 | pub(super) const fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option<Mdf> { |
250 | 0 | match month <= 12 && day <= 31 { |
251 | 0 | true => Some(Mdf((month << 9) | (day << 4) | flags as u32)), |
252 | 0 | false => None, |
253 | | } |
254 | 0 | } |
255 | | |
256 | | /// Makes a new `Mdf` value from an `i32` with an ordinal and a leap year flag, and year |
257 | | /// `flags`. |
258 | | /// |
259 | | /// The `ol` is trusted to be valid, and the `flags` are trusted to match it. |
260 | | #[inline] |
261 | 0 | pub(super) const fn from_ol(ol: i32, YearFlags(flags): YearFlags) -> Mdf { |
262 | 0 | debug_assert!(ol > 1 && ol <= MAX_OL as i32); |
263 | | // Array is indexed from `[2..=MAX_OL]`, with a `0` index having a meaningless value. |
264 | 0 | Mdf(((ol as u32 + OL_TO_MDL[ol as usize] as u32) << 3) | flags as u32) |
265 | 0 | } Unexecuted instantiation: <chrono::naive::internals::Mdf>::from_ol Unexecuted instantiation: <chrono::naive::internals::Mdf>::from_ol |
266 | | |
267 | | /// Returns the month of this `Mdf`. |
268 | | #[inline] |
269 | 0 | pub(super) const fn month(&self) -> u32 { |
270 | 0 | let Mdf(mdf) = *self; |
271 | 0 | mdf >> 9 |
272 | 0 | } Unexecuted instantiation: <chrono::naive::internals::Mdf>::month Unexecuted instantiation: <chrono::naive::internals::Mdf>::month |
273 | | |
274 | | /// Replaces the month of this `Mdf`, keeping the day and flags. |
275 | | /// |
276 | | /// # Errors |
277 | | /// |
278 | | /// Returns `None` if `month > 12`. |
279 | | #[inline] |
280 | 0 | pub(super) const fn with_month(&self, month: u32) -> Option<Mdf> { |
281 | 0 | if month > 12 { |
282 | 0 | return None; |
283 | 0 | } |
284 | 0 |
|
285 | 0 | let Mdf(mdf) = *self; |
286 | 0 | Some(Mdf((mdf & 0b1_1111_1111) | (month << 9))) |
287 | 0 | } |
288 | | |
289 | | /// Returns the day of this `Mdf`. |
290 | | #[inline] |
291 | 0 | pub(super) const fn day(&self) -> u32 { |
292 | 0 | let Mdf(mdf) = *self; |
293 | 0 | (mdf >> 4) & 0b1_1111 |
294 | 0 | } Unexecuted instantiation: <chrono::naive::internals::Mdf>::day Unexecuted instantiation: <chrono::naive::internals::Mdf>::day |
295 | | |
296 | | /// Replaces the day of this `Mdf`, keeping the month and flags. |
297 | | /// |
298 | | /// # Errors |
299 | | /// |
300 | | /// Returns `None` if `day > 31`. |
301 | | #[inline] |
302 | 0 | pub(super) const fn with_day(&self, day: u32) -> Option<Mdf> { |
303 | 0 | if day > 31 { |
304 | 0 | return None; |
305 | 0 | } |
306 | 0 |
|
307 | 0 | let Mdf(mdf) = *self; |
308 | 0 | Some(Mdf((mdf & !0b1_1111_0000) | (day << 4))) |
309 | 0 | } |
310 | | |
311 | | /// Replaces the flags of this `Mdf`, keeping the month and day. |
312 | | #[inline] |
313 | 0 | pub(super) const fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf { |
314 | 0 | let Mdf(mdf) = *self; |
315 | 0 | Mdf((mdf & !0b1111) | flags as u32) |
316 | 0 | } |
317 | | |
318 | | /// Returns the ordinal that corresponds to this `Mdf`. |
319 | | /// |
320 | | /// This does a table lookup to calculate the corresponding ordinal. It will return an error if |
321 | | /// the `Mdl` turns out not to be a valid date. |
322 | | /// |
323 | | /// # Errors |
324 | | /// |
325 | | /// Returns `None` if `month == 0` or `day == 0`, or if a the given day does not exist in the |
326 | | /// given month. |
327 | | #[inline] |
328 | 0 | pub(super) const fn ordinal(&self) -> Option<u32> { |
329 | 0 | let mdl = self.0 >> 3; |
330 | 0 | match MDL_TO_OL[mdl as usize] { |
331 | 0 | XX => None, |
332 | 0 | v => Some((mdl - v as u8 as u32) >> 1), |
333 | | } |
334 | 0 | } |
335 | | |
336 | | /// Returns the year flags of this `Mdf`. |
337 | | #[inline] |
338 | 0 | pub(super) const fn year_flags(&self) -> YearFlags { |
339 | 0 | YearFlags((self.0 & 0b1111) as u8) |
340 | 0 | } |
341 | | |
342 | | /// Returns the ordinal that corresponds to this `Mdf`, encoded as a value including year flags. |
343 | | /// |
344 | | /// This does a table lookup to calculate the corresponding ordinal. It will return an error if |
345 | | /// the `Mdl` turns out not to be a valid date. |
346 | | /// |
347 | | /// # Errors |
348 | | /// |
349 | | /// Returns `None` if `month == 0` or `day == 0`, or if a the given day does not exist in the |
350 | | /// given month. |
351 | | #[inline] |
352 | 0 | pub(super) const fn ordinal_and_flags(&self) -> Option<i32> { |
353 | 0 | let mdl = self.0 >> 3; |
354 | 0 | match MDL_TO_OL[mdl as usize] { |
355 | 0 | XX => None, |
356 | 0 | v => Some(self.0 as i32 - ((v as i32) << 3)), |
357 | | } |
358 | 0 | } |
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 | | |
367 | | impl fmt::Debug for Mdf { |
368 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
369 | 0 | let Mdf(mdf) = *self; |
370 | 0 | write!( |
371 | 0 | f, |
372 | 0 | "Mdf(({} << 9) | ({} << 4) | {:#04o} /*{:?}*/)", |
373 | 0 | mdf >> 9, |
374 | 0 | (mdf >> 4) & 0b1_1111, |
375 | 0 | mdf & 0b1111, |
376 | 0 | YearFlags((mdf & 0b1111) as u8) |
377 | 0 | ) |
378 | 0 | } |
379 | | } |
380 | | |
381 | | #[cfg(test)] |
382 | | mod tests { |
383 | | use super::Mdf; |
384 | | use super::{A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF, YearFlags}; |
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); // 1 BCE (proleptic Gregorian) |
399 | | assert_eq!(YearFlags::from_year(-1).ndays(), 365); // 2 BCE |
400 | | assert_eq!(YearFlags::from_year(-4).ndays(), 366); // 5 BCE |
401 | | assert_eq!(YearFlags::from_year(-99).ndays(), 365); // 100 BCE |
402 | | assert_eq!(YearFlags::from_year(-100).ndays(), 365); // 101 BCE |
403 | | assert_eq!(YearFlags::from_year(-399).ndays(), 365); // 400 BCE |
404 | | assert_eq!(YearFlags::from_year(-400).ndays(), 366); // 401 BCE |
405 | | } |
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 | | } |