chrono/naive/
internals.rs

1// This is a part of Chrono.
2// See README.md and LICENSE.txt for details.
3
4//! The internal implementation of the calendar and ordinal date.
5//!
6//! The current implementation is optimized for determining year, month, day and day of week.
7//! 4-bit `YearFlags` map to one of 14 possible classes of year in the Gregorian calendar,
8//! which are included in every packed `NaiveDate` instance.
9//! The conversion between the packed calendar date (`Mdf`) and the ordinal date (`Of`) is
10//! based on the moderately-sized lookup table (~1.5KB)
11//! and the packed representation is chosen for the efficient lookup.
12//! Every internal data structure does not validate its input,
13//! but the conversion keeps the valid value valid and the invalid value invalid
14//! so that the user-facing `NaiveDate` can validate the input as late as possible.
15
16#![cfg_attr(feature = "__internal_bench", allow(missing_docs))]
17
18use crate::Weekday;
19use core::fmt;
20
21/// The internal date representation: `year << 13 | Of`
22pub(super) type DateImpl = i32;
23
24/// MAX_YEAR is one year less than the type is capable of representing. Internally we may sometimes
25/// use the headroom, notably to handle cases where the offset of a `DateTime` constructed with
26/// `NaiveDate::MAX` pushes it beyond the valid, representable range.
27pub(super) const MAX_YEAR: DateImpl = (i32::MAX >> 13) - 1;
28
29/// MIN_YEAR is one year more than the type is capable of representing. Internally we may sometimes
30/// use the headroom, notably to handle cases where the offset of a `DateTime` constructed with
31/// `NaiveDate::MIN` pushes it beyond the valid, representable range.
32pub(super) const MIN_YEAR: DateImpl = (i32::MIN >> 13) + 1;
33
34/// The year flags (aka the dominical letter).
35///
36/// There are 14 possible classes of year in the Gregorian calendar:
37/// common and leap years starting with Monday through Sunday.
38/// The `YearFlags` stores this information into 4 bits `abbb`,
39/// where `a` is `1` for the common year (simplifies the `Of` validation)
40/// and `bbb` is a non-zero `Weekday` (mapping `Mon` to 7) of the last day in the past year
41/// (simplifies the day of week calculation from the 1-based ordinal).
42#[allow(unreachable_pub)] // public as an alias for benchmarks only
43#[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, // 100
66    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, // 200
70    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, // 300
74    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, // 400
78];
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, // 100
85    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, // 200
90    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, // 300
95    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, // 400+1
100];
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)] // public as an alias for benchmarks only
121    #[doc(hidden)] // for benchmarks only
122    #[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), // non-canonical
173            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
182// OL: (ordinal << 1) | leap year flag
183pub(super) const MIN_OL: u32 = 1 << 1;
184pub(super) const MAX_OL: u32 = 366 << 1; // `(366 << 1) | 1` would be day 366 in a non-leap year
185pub(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, // 0
192    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, // 1
195    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, // 2
198    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, // 3
201    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, // 4
204    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, // 5
207    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, // 6
210    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, // 7
213    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, // 8
216    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, // 9
219    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, // 10
222    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, // 11
225    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, // 12
229];
230
231const OL_TO_MDL: &[u8; MAX_OL as usize + 1] = &[
232    0, 0, // 0
233    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, // 1
236    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, // 2
239    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, // 3
242    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, // 4
245    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, // 5
248    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, // 6
251    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, // 7
254    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, // 8
257    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, // 9
260    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, // 10
263    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, // 11
266    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, // 12
270];
271
272/// Ordinal (day of year) and year flags: `(ordinal << 4) | flags`.
273///
274/// The whole bits except for the least 3 bits are referred as `Ol` (ordinal and leap flag),
275/// which is an index to the `OL_TO_MDL` lookup table.
276///
277/// The methods implemented on `Of` always return a valid value.
278#[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        // We assume the value in the `DateImpl` is valid.
290        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            // Panicking on out-of-bounds indexing would be reasonable, but just return `None`.
298            return None;
299        }
300        // Array is indexed from `[1..=MAX_MDL]`, with a `0` index having a meaningless value.
301        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    /// Returns `(ordinal << 1) | leap-year-flag`.
312    #[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        // week ordinal = ordinal + delta
351        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    /// Returns an `Of` with the next day, or `None` if this is the last day of the year.
363    #[inline]
364    pub(super) const fn succ(&self) -> Option<Of> {
365        let of = Of(self.0 + (1 << 4));
366        of.validate()
367    }
368
369    /// Returns an `Of` with the previous day, or `None` if this is the first day of the year.
370    #[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/// Month, day of month and year flags: `(month << 9) | (day << 4) | flags`
393///
394/// The whole bits except for the least 3 bits are referred as `Mdl`
395/// (month, day of month and leap flag),
396/// which is an index to the `MDL_TO_OL` lookup table.
397///
398/// The methods implemented on `Mdf` do not always return a valid value.
399/// Dates that can't exist, like February 30, can still be represented.
400/// Use `Mdl::valid` to check whether the date is valid.
401#[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            // Array is indexed from `[1..=MAX_OL]`, with a `0` index having a meaningless value.
418            Mdf(of + ((OL_TO_MDL[ol as usize] as u32) << 3))
419        } else {
420            // Panicking here would be reasonable, but we are just going on with a safe value.
421            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            // Array is indexed from `[1..=MAX_MDL]`, with a `0` index having a meaningless value.
431            MDL_TO_OL[mdl as usize] >= 0
432        } else {
433            // Panicking here would be reasonable, but we are just going on with a safe value.
434            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/// Create a `Weekday` from an `u32`, with Monday = 0.
498/// Infallible, takes any `n` and applies `% 7`.
499#[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); // 1 BCE (proleptic Gregorian)
532        assert_eq!(YearFlags::from_year(-1).ndays(), 365); // 2 BCE
533        assert_eq!(YearFlags::from_year(-4).ndays(), 366); // 5 BCE
534        assert_eq!(YearFlags::from_year(-99).ndays(), 365); // 100 BCE
535        assert_eq!(YearFlags::from_year(-100).ndays(), 365); // 101 BCE
536        assert_eq!(YearFlags::from_year(-399).ndays(), 365); // 400 BCE
537        assert_eq!(YearFlags::from_year(-400).ndays(), 366); // 401 BCE
538    }
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            // January 4 should be in the first week
821            let (week, _) = Of::new(4 /* January 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}