• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #![allow(dead_code)] // some internal methods have been left for consistency
17 #![cfg_attr(feature = "__internal_bench", allow(missing_docs))]
18 
19 use core::{fmt, i32};
20 use div::{div_rem, mod_floor};
21 use num_traits::FromPrimitive;
22 use Weekday;
23 
24 /// The internal date representation. This also includes the packed `Mdf` value.
25 pub type DateImpl = i32;
26 
27 pub const MAX_YEAR: DateImpl = i32::MAX >> 13;
28 pub const MIN_YEAR: DateImpl = i32::MIN >> 13;
29 
30 /// The year flags (aka the dominical letter).
31 ///
32 /// There are 14 possible classes of year in the Gregorian calendar:
33 /// common and leap years starting with Monday through Sunday.
34 /// The `YearFlags` stores this information into 4 bits `abbb`,
35 /// where `a` is `1` for the common year (simplifies the `Of` validation)
36 /// and `bbb` is a non-zero `Weekday` (mapping `Mon` to 7) of the last day in the past year
37 /// (simplifies the day of week calculation from the 1-based ordinal).
38 #[derive(PartialEq, Eq, Copy, Clone)]
39 pub struct YearFlags(pub u8);
40 
41 pub const A: YearFlags = YearFlags(0o15);
42 pub const AG: YearFlags = YearFlags(0o05);
43 pub const B: YearFlags = YearFlags(0o14);
44 pub const BA: YearFlags = YearFlags(0o04);
45 pub const C: YearFlags = YearFlags(0o13);
46 pub const CB: YearFlags = YearFlags(0o03);
47 pub const D: YearFlags = YearFlags(0o12);
48 pub const DC: YearFlags = YearFlags(0o02);
49 pub const E: YearFlags = YearFlags(0o11);
50 pub const ED: YearFlags = YearFlags(0o01);
51 pub const F: YearFlags = YearFlags(0o17);
52 pub const FE: YearFlags = YearFlags(0o07);
53 pub const G: YearFlags = YearFlags(0o16);
54 pub const GF: YearFlags = YearFlags(0o06);
55 
56 static YEAR_TO_FLAGS: [YearFlags; 400] = [
57     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,
58     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,
59     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,
60     E, DC, B, A, G, FE, D, C, B, AG, F, E, D, // 100
61     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,
62     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,
63     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,
64     G, FE, D, C, B, AG, F, E, D, CB, A, G, F, // 200
65     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,
66     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,
67     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,
68     B, AG, F, E, D, CB, A, G, F, ED, C, B, A, // 300
69     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,
70     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,
71     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,
72     D, CB, A, G, F, ED, C, B, A, GF, E, D, C, // 400
73 ];
74 
75 static YEAR_DELTAS: [u8; 401] = [
76     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,
77     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,
78     15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20,
79     21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, // 100
80     25, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30,
81     30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36,
82     36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42,
83     42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48,
84     48, 49, 49, 49, // 200
85     49, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54,
86     54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60,
87     60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66,
88     66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72,
89     72, 73, 73, 73, // 300
90     73, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78,
91     78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84,
92     84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90,
93     90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96,
94     96, 97, 97, 97, 97, // 400+1
95 ];
96 
cycle_to_yo(cycle: u32) -> (u32, u32)97 pub fn cycle_to_yo(cycle: u32) -> (u32, u32) {
98     let (mut year_mod_400, mut ordinal0) = div_rem(cycle, 365);
99     let delta = u32::from(YEAR_DELTAS[year_mod_400 as usize]);
100     if ordinal0 < delta {
101         year_mod_400 -= 1;
102         ordinal0 += 365 - u32::from(YEAR_DELTAS[year_mod_400 as usize]);
103     } else {
104         ordinal0 -= delta;
105     }
106     (year_mod_400, ordinal0 + 1)
107 }
108 
yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32109 pub fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 {
110     year_mod_400 * 365 + u32::from(YEAR_DELTAS[year_mod_400 as usize]) + ordinal - 1
111 }
112 
113 impl YearFlags {
114     #[inline]
from_year(year: i32) -> YearFlags115     pub fn from_year(year: i32) -> YearFlags {
116         let year = mod_floor(year, 400);
117         YearFlags::from_year_mod_400(year)
118     }
119 
120     #[inline]
from_year_mod_400(year: i32) -> YearFlags121     pub fn from_year_mod_400(year: i32) -> YearFlags {
122         YEAR_TO_FLAGS[year as usize]
123     }
124 
125     #[inline]
ndays(&self) -> u32126     pub fn ndays(&self) -> u32 {
127         let YearFlags(flags) = *self;
128         366 - u32::from(flags >> 3)
129     }
130 
131     #[inline]
isoweek_delta(&self) -> u32132     pub fn isoweek_delta(&self) -> u32 {
133         let YearFlags(flags) = *self;
134         let mut delta = u32::from(flags) & 0b0111;
135         if delta < 3 {
136             delta += 7;
137         }
138         delta
139     }
140 
141     #[inline]
nisoweeks(&self) -> u32142     pub fn nisoweeks(&self) -> u32 {
143         let YearFlags(flags) = *self;
144         52 + ((0b0000_0100_0000_0110 >> flags as usize) & 1)
145     }
146 }
147 
148 impl fmt::Debug for YearFlags {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result149     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150         let YearFlags(flags) = *self;
151         match flags {
152             0o15 => "A".fmt(f),
153             0o05 => "AG".fmt(f),
154             0o14 => "B".fmt(f),
155             0o04 => "BA".fmt(f),
156             0o13 => "C".fmt(f),
157             0o03 => "CB".fmt(f),
158             0o12 => "D".fmt(f),
159             0o02 => "DC".fmt(f),
160             0o11 => "E".fmt(f),
161             0o01 => "ED".fmt(f),
162             0o10 => "F?".fmt(f),
163             0o00 => "FE?".fmt(f), // non-canonical
164             0o17 => "F".fmt(f),
165             0o07 => "FE".fmt(f),
166             0o16 => "G".fmt(f),
167             0o06 => "GF".fmt(f),
168             _ => write!(f, "YearFlags({})", flags),
169         }
170     }
171 }
172 
173 pub const MIN_OL: u32 = 1 << 1;
174 pub const MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1`
175 pub const MIN_MDL: u32 = (1 << 6) | (1 << 1);
176 pub const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
177 
178 const XX: i8 = -128;
179 static MDL_TO_OL: [i8; MAX_MDL as usize + 1] = [
180     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
181     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
182     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, // 0
183     XX, XX, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
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, // 1
186     XX, XX, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
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, XX, XX, XX, XX, XX, // 2
189     XX, XX, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
190     72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
191     72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, // 3
192     XX, XX, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
193     74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
194     74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, XX, XX, // 4
195     XX, XX, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
196     78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
197     78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, // 5
198     XX, XX, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
199     80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
200     80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, XX, XX, // 6
201     XX, XX, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
202     84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
203     84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, // 7
204     XX, XX, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
205     86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
206     86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, // 8
207     XX, XX, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
208     88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
209     88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, XX, XX, // 9
210     XX, XX, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
211     92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
212     92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, // 10
213     XX, XX, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
214     94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
215     94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, XX, XX, // 11
216     XX, XX, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
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, // 12
220 ];
221 
222 static OL_TO_MDL: [u8; MAX_OL as usize + 1] = [
223     0, 0, // 0
224     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
225     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
226     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 1
227     66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
228     66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
229     66, 66, 66, 66, 66, 66, 66, 66, 66, // 2
230     74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72,
231     74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72,
232     74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, // 3
233     76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74,
234     76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74,
235     76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, // 4
236     80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78,
237     80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78,
238     80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, // 5
239     82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80,
240     82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80,
241     82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, // 6
242     86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84,
243     86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84,
244     86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, // 7
245     88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86,
246     88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86,
247     88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, // 8
248     90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88,
249     90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88,
250     90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, // 9
251     94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92,
252     94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92,
253     94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, // 10
254     96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94,
255     96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94,
256     96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, // 11
257     100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
258     98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
259     100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
260     98, // 12
261 ];
262 
263 /// Ordinal (day of year) and year flags: `(ordinal << 4) | flags`.
264 ///
265 /// The whole bits except for the least 3 bits are referred as `Ol` (ordinal and leap flag),
266 /// which is an index to the `OL_TO_MDL` lookup table.
267 #[derive(PartialEq, PartialOrd, Copy, Clone)]
268 pub struct Of(pub u32);
269 
270 impl Of {
271     #[inline]
clamp_ordinal(ordinal: u32) -> u32272     fn clamp_ordinal(ordinal: u32) -> u32 {
273         if ordinal > 366 {
274             0
275         } else {
276             ordinal
277         }
278     }
279 
280     #[inline]
new(ordinal: u32, YearFlags(flags): YearFlags) -> Of281     pub fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Of {
282         let ordinal = Of::clamp_ordinal(ordinal);
283         Of((ordinal << 4) | u32::from(flags))
284     }
285 
286     #[inline]
from_mdf(Mdf(mdf): Mdf) -> Of287     pub fn from_mdf(Mdf(mdf): Mdf) -> Of {
288         let mdl = mdf >> 3;
289         match MDL_TO_OL.get(mdl as usize) {
290             Some(&v) => Of(mdf.wrapping_sub((i32::from(v) as u32 & 0x3ff) << 3)),
291             None => Of(0),
292         }
293     }
294 
295     #[inline]
valid(&self) -> bool296     pub fn valid(&self) -> bool {
297         let Of(of) = *self;
298         let ol = of >> 3;
299         MIN_OL <= ol && ol <= MAX_OL
300     }
301 
302     #[inline]
ordinal(&self) -> u32303     pub fn ordinal(&self) -> u32 {
304         let Of(of) = *self;
305         of >> 4
306     }
307 
308     #[inline]
with_ordinal(&self, ordinal: u32) -> Of309     pub fn with_ordinal(&self, ordinal: u32) -> Of {
310         let ordinal = Of::clamp_ordinal(ordinal);
311         let Of(of) = *self;
312         Of((of & 0b1111) | (ordinal << 4))
313     }
314 
315     #[inline]
flags(&self) -> YearFlags316     pub fn flags(&self) -> YearFlags {
317         let Of(of) = *self;
318         YearFlags((of & 0b1111) as u8)
319     }
320 
321     #[inline]
with_flags(&self, YearFlags(flags): YearFlags) -> Of322     pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Of {
323         let Of(of) = *self;
324         Of((of & !0b1111) | u32::from(flags))
325     }
326 
327     #[inline]
weekday(&self) -> Weekday328     pub fn weekday(&self) -> Weekday {
329         let Of(of) = *self;
330         Weekday::from_u32(((of >> 4) + (of & 0b111)) % 7).unwrap()
331     }
332 
333     #[inline]
isoweekdate_raw(&self) -> (u32, Weekday)334     pub fn isoweekdate_raw(&self) -> (u32, Weekday) {
335         // week ordinal = ordinal + delta
336         let Of(of) = *self;
337         let weekord = (of >> 4).wrapping_add(self.flags().isoweek_delta());
338         (weekord / 7, Weekday::from_u32(weekord % 7).unwrap())
339     }
340 
341     #[inline]
to_mdf(&self) -> Mdf342     pub fn to_mdf(&self) -> Mdf {
343         Mdf::from_of(*self)
344     }
345 
346     #[inline]
succ(&self) -> Of347     pub fn succ(&self) -> Of {
348         let Of(of) = *self;
349         Of(of + (1 << 4))
350     }
351 
352     #[inline]
pred(&self) -> Of353     pub fn pred(&self) -> Of {
354         let Of(of) = *self;
355         Of(of - (1 << 4))
356     }
357 }
358 
359 impl fmt::Debug for Of {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result360     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
361         let Of(of) = *self;
362         write!(
363             f,
364             "Of(({} << 4) | {:#04o} /*{:?}*/)",
365             of >> 4,
366             of & 0b1111,
367             YearFlags((of & 0b1111) as u8)
368         )
369     }
370 }
371 
372 /// Month, day of month and year flags: `(month << 9) | (day << 4) | flags`
373 ///
374 /// The whole bits except for the least 3 bits are referred as `Mdl`
375 /// (month, day of month and leap flag),
376 /// which is an index to the `MDL_TO_OL` lookup table.
377 #[derive(PartialEq, PartialOrd, Copy, Clone)]
378 pub struct Mdf(pub u32);
379 
380 impl Mdf {
381     #[inline]
clamp_month(month: u32) -> u32382     fn clamp_month(month: u32) -> u32 {
383         if month > 12 {
384             0
385         } else {
386             month
387         }
388     }
389 
390     #[inline]
clamp_day(day: u32) -> u32391     fn clamp_day(day: u32) -> u32 {
392         if day > 31 {
393             0
394         } else {
395             day
396         }
397     }
398 
399     #[inline]
new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Mdf400     pub fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Mdf {
401         let month = Mdf::clamp_month(month);
402         let day = Mdf::clamp_day(day);
403         Mdf((month << 9) | (day << 4) | u32::from(flags))
404     }
405 
406     #[inline]
from_of(Of(of): Of) -> Mdf407     pub fn from_of(Of(of): Of) -> Mdf {
408         let ol = of >> 3;
409         match OL_TO_MDL.get(ol as usize) {
410             Some(&v) => Mdf(of + (u32::from(v) << 3)),
411             None => Mdf(0),
412         }
413     }
414 
415     #[inline]
valid(&self) -> bool416     pub fn valid(&self) -> bool {
417         let Mdf(mdf) = *self;
418         let mdl = mdf >> 3;
419         match MDL_TO_OL.get(mdl as usize) {
420             Some(&v) => v >= 0,
421             None => false,
422         }
423     }
424 
425     #[inline]
month(&self) -> u32426     pub fn month(&self) -> u32 {
427         let Mdf(mdf) = *self;
428         mdf >> 9
429     }
430 
431     #[inline]
with_month(&self, month: u32) -> Mdf432     pub fn with_month(&self, month: u32) -> Mdf {
433         let month = Mdf::clamp_month(month);
434         let Mdf(mdf) = *self;
435         Mdf((mdf & 0b1_1111_1111) | (month << 9))
436     }
437 
438     #[inline]
day(&self) -> u32439     pub fn day(&self) -> u32 {
440         let Mdf(mdf) = *self;
441         (mdf >> 4) & 0b1_1111
442     }
443 
444     #[inline]
with_day(&self, day: u32) -> Mdf445     pub fn with_day(&self, day: u32) -> Mdf {
446         let day = Mdf::clamp_day(day);
447         let Mdf(mdf) = *self;
448         Mdf((mdf & !0b1_1111_0000) | (day << 4))
449     }
450 
451     #[inline]
flags(&self) -> YearFlags452     pub fn flags(&self) -> YearFlags {
453         let Mdf(mdf) = *self;
454         YearFlags((mdf & 0b1111) as u8)
455     }
456 
457     #[inline]
with_flags(&self, YearFlags(flags): YearFlags) -> Mdf458     pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf {
459         let Mdf(mdf) = *self;
460         Mdf((mdf & !0b1111) | u32::from(flags))
461     }
462 
463     #[inline]
to_of(&self) -> Of464     pub fn to_of(&self) -> Of {
465         Of::from_mdf(*self)
466     }
467 }
468 
469 impl fmt::Debug for Mdf {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result470     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
471         let Mdf(mdf) = *self;
472         write!(
473             f,
474             "Mdf(({} << 9) | ({} << 4) | {:#04o} /*{:?}*/)",
475             mdf >> 9,
476             (mdf >> 4) & 0b1_1111,
477             mdf & 0b1111,
478             YearFlags((mdf & 0b1111) as u8)
479         )
480     }
481 }
482 
483 #[cfg(test)]
484 mod tests {
485     #[cfg(test)]
486     extern crate num_iter;
487 
488     use self::num_iter::range_inclusive;
489     use super::{Mdf, Of};
490     use super::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF};
491     use std::u32;
492     use Weekday;
493 
494     const NONLEAP_FLAGS: [YearFlags; 7] = [A, B, C, D, E, F, G];
495     const LEAP_FLAGS: [YearFlags; 7] = [AG, BA, CB, DC, ED, FE, GF];
496     const FLAGS: [YearFlags; 14] = [A, B, C, D, E, F, G, AG, BA, CB, DC, ED, FE, GF];
497 
498     #[test]
test_year_flags_ndays_from_year()499     fn test_year_flags_ndays_from_year() {
500         assert_eq!(YearFlags::from_year(2014).ndays(), 365);
501         assert_eq!(YearFlags::from_year(2012).ndays(), 366);
502         assert_eq!(YearFlags::from_year(2000).ndays(), 366);
503         assert_eq!(YearFlags::from_year(1900).ndays(), 365);
504         assert_eq!(YearFlags::from_year(1600).ndays(), 366);
505         assert_eq!(YearFlags::from_year(1).ndays(), 365);
506         assert_eq!(YearFlags::from_year(0).ndays(), 366); // 1 BCE (proleptic Gregorian)
507         assert_eq!(YearFlags::from_year(-1).ndays(), 365); // 2 BCE
508         assert_eq!(YearFlags::from_year(-4).ndays(), 366); // 5 BCE
509         assert_eq!(YearFlags::from_year(-99).ndays(), 365); // 100 BCE
510         assert_eq!(YearFlags::from_year(-100).ndays(), 365); // 101 BCE
511         assert_eq!(YearFlags::from_year(-399).ndays(), 365); // 400 BCE
512         assert_eq!(YearFlags::from_year(-400).ndays(), 366); // 401 BCE
513     }
514 
515     #[test]
test_year_flags_nisoweeks()516     fn test_year_flags_nisoweeks() {
517         assert_eq!(A.nisoweeks(), 52);
518         assert_eq!(B.nisoweeks(), 52);
519         assert_eq!(C.nisoweeks(), 52);
520         assert_eq!(D.nisoweeks(), 53);
521         assert_eq!(E.nisoweeks(), 52);
522         assert_eq!(F.nisoweeks(), 52);
523         assert_eq!(G.nisoweeks(), 52);
524         assert_eq!(AG.nisoweeks(), 52);
525         assert_eq!(BA.nisoweeks(), 52);
526         assert_eq!(CB.nisoweeks(), 52);
527         assert_eq!(DC.nisoweeks(), 53);
528         assert_eq!(ED.nisoweeks(), 53);
529         assert_eq!(FE.nisoweeks(), 52);
530         assert_eq!(GF.nisoweeks(), 52);
531     }
532 
533     #[test]
test_of()534     fn test_of() {
535         fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) {
536             for ordinal in range_inclusive(ordinal1, ordinal2) {
537                 let of = Of::new(ordinal, flags);
538                 assert!(
539                     of.valid() == expected,
540                     "ordinal {} = {:?} should be {} for dominical year {:?}",
541                     ordinal,
542                     of,
543                     if expected { "valid" } else { "invalid" },
544                     flags
545                 );
546             }
547         }
548 
549         for &flags in NONLEAP_FLAGS.iter() {
550             check(false, flags, 0, 0);
551             check(true, flags, 1, 365);
552             check(false, flags, 366, 1024);
553             check(false, flags, u32::MAX, u32::MAX);
554         }
555 
556         for &flags in LEAP_FLAGS.iter() {
557             check(false, flags, 0, 0);
558             check(true, flags, 1, 366);
559             check(false, flags, 367, 1024);
560             check(false, flags, u32::MAX, u32::MAX);
561         }
562     }
563 
564     #[test]
test_mdf_valid()565     fn test_mdf_valid() {
566         fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, month2: u32, day2: u32) {
567             for month in range_inclusive(month1, month2) {
568                 for day in range_inclusive(day1, day2) {
569                     let mdf = Mdf::new(month, day, flags);
570                     assert!(
571                         mdf.valid() == expected,
572                         "month {} day {} = {:?} should be {} for dominical year {:?}",
573                         month,
574                         day,
575                         mdf,
576                         if expected { "valid" } else { "invalid" },
577                         flags
578                     );
579                 }
580             }
581         }
582 
583         for &flags in NONLEAP_FLAGS.iter() {
584             check(false, flags, 0, 0, 0, 1024);
585             check(false, flags, 0, 0, 16, 0);
586             check(true, flags, 1, 1, 1, 31);
587             check(false, flags, 1, 32, 1, 1024);
588             check(true, flags, 2, 1, 2, 28);
589             check(false, flags, 2, 29, 2, 1024);
590             check(true, flags, 3, 1, 3, 31);
591             check(false, flags, 3, 32, 3, 1024);
592             check(true, flags, 4, 1, 4, 30);
593             check(false, flags, 4, 31, 4, 1024);
594             check(true, flags, 5, 1, 5, 31);
595             check(false, flags, 5, 32, 5, 1024);
596             check(true, flags, 6, 1, 6, 30);
597             check(false, flags, 6, 31, 6, 1024);
598             check(true, flags, 7, 1, 7, 31);
599             check(false, flags, 7, 32, 7, 1024);
600             check(true, flags, 8, 1, 8, 31);
601             check(false, flags, 8, 32, 8, 1024);
602             check(true, flags, 9, 1, 9, 30);
603             check(false, flags, 9, 31, 9, 1024);
604             check(true, flags, 10, 1, 10, 31);
605             check(false, flags, 10, 32, 10, 1024);
606             check(true, flags, 11, 1, 11, 30);
607             check(false, flags, 11, 31, 11, 1024);
608             check(true, flags, 12, 1, 12, 31);
609             check(false, flags, 12, 32, 12, 1024);
610             check(false, flags, 13, 0, 16, 1024);
611             check(false, flags, u32::MAX, 0, u32::MAX, 1024);
612             check(false, flags, 0, u32::MAX, 16, u32::MAX);
613             check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
614         }
615 
616         for &flags in LEAP_FLAGS.iter() {
617             check(false, flags, 0, 0, 0, 1024);
618             check(false, flags, 0, 0, 16, 0);
619             check(true, flags, 1, 1, 1, 31);
620             check(false, flags, 1, 32, 1, 1024);
621             check(true, flags, 2, 1, 2, 29);
622             check(false, flags, 2, 30, 2, 1024);
623             check(true, flags, 3, 1, 3, 31);
624             check(false, flags, 3, 32, 3, 1024);
625             check(true, flags, 4, 1, 4, 30);
626             check(false, flags, 4, 31, 4, 1024);
627             check(true, flags, 5, 1, 5, 31);
628             check(false, flags, 5, 32, 5, 1024);
629             check(true, flags, 6, 1, 6, 30);
630             check(false, flags, 6, 31, 6, 1024);
631             check(true, flags, 7, 1, 7, 31);
632             check(false, flags, 7, 32, 7, 1024);
633             check(true, flags, 8, 1, 8, 31);
634             check(false, flags, 8, 32, 8, 1024);
635             check(true, flags, 9, 1, 9, 30);
636             check(false, flags, 9, 31, 9, 1024);
637             check(true, flags, 10, 1, 10, 31);
638             check(false, flags, 10, 32, 10, 1024);
639             check(true, flags, 11, 1, 11, 30);
640             check(false, flags, 11, 31, 11, 1024);
641             check(true, flags, 12, 1, 12, 31);
642             check(false, flags, 12, 32, 12, 1024);
643             check(false, flags, 13, 0, 16, 1024);
644             check(false, flags, u32::MAX, 0, u32::MAX, 1024);
645             check(false, flags, 0, u32::MAX, 16, u32::MAX);
646             check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
647         }
648     }
649 
650     #[test]
test_of_fields()651     fn test_of_fields() {
652         for &flags in FLAGS.iter() {
653             for ordinal in range_inclusive(1u32, 366) {
654                 let of = Of::new(ordinal, flags);
655                 if of.valid() {
656                     assert_eq!(of.ordinal(), ordinal);
657                 }
658             }
659         }
660     }
661 
662     #[test]
test_of_with_fields()663     fn test_of_with_fields() {
664         fn check(flags: YearFlags, ordinal: u32) {
665             let of = Of::new(ordinal, flags);
666 
667             for ordinal in range_inclusive(0u32, 1024) {
668                 let of = of.with_ordinal(ordinal);
669                 assert_eq!(of.valid(), Of::new(ordinal, flags).valid());
670                 if of.valid() {
671                     assert_eq!(of.ordinal(), ordinal);
672                 }
673             }
674         }
675 
676         for &flags in NONLEAP_FLAGS.iter() {
677             check(flags, 1);
678             check(flags, 365);
679         }
680         for &flags in LEAP_FLAGS.iter() {
681             check(flags, 1);
682             check(flags, 366);
683         }
684     }
685 
686     #[test]
test_of_weekday()687     fn test_of_weekday() {
688         assert_eq!(Of::new(1, A).weekday(), Weekday::Sun);
689         assert_eq!(Of::new(1, B).weekday(), Weekday::Sat);
690         assert_eq!(Of::new(1, C).weekday(), Weekday::Fri);
691         assert_eq!(Of::new(1, D).weekday(), Weekday::Thu);
692         assert_eq!(Of::new(1, E).weekday(), Weekday::Wed);
693         assert_eq!(Of::new(1, F).weekday(), Weekday::Tue);
694         assert_eq!(Of::new(1, G).weekday(), Weekday::Mon);
695         assert_eq!(Of::new(1, AG).weekday(), Weekday::Sun);
696         assert_eq!(Of::new(1, BA).weekday(), Weekday::Sat);
697         assert_eq!(Of::new(1, CB).weekday(), Weekday::Fri);
698         assert_eq!(Of::new(1, DC).weekday(), Weekday::Thu);
699         assert_eq!(Of::new(1, ED).weekday(), Weekday::Wed);
700         assert_eq!(Of::new(1, FE).weekday(), Weekday::Tue);
701         assert_eq!(Of::new(1, GF).weekday(), Weekday::Mon);
702 
703         for &flags in FLAGS.iter() {
704             let mut prev = Of::new(1, flags).weekday();
705             for ordinal in range_inclusive(2u32, flags.ndays()) {
706                 let of = Of::new(ordinal, flags);
707                 let expected = prev.succ();
708                 assert_eq!(of.weekday(), expected);
709                 prev = expected;
710             }
711         }
712     }
713 
714     #[test]
test_mdf_fields()715     fn test_mdf_fields() {
716         for &flags in FLAGS.iter() {
717             for month in range_inclusive(1u32, 12) {
718                 for day in range_inclusive(1u32, 31) {
719                     let mdf = Mdf::new(month, day, flags);
720                     if mdf.valid() {
721                         assert_eq!(mdf.month(), month);
722                         assert_eq!(mdf.day(), day);
723                     }
724                 }
725             }
726         }
727     }
728 
729     #[test]
test_mdf_with_fields()730     fn test_mdf_with_fields() {
731         fn check(flags: YearFlags, month: u32, day: u32) {
732             let mdf = Mdf::new(month, day, flags);
733 
734             for month in range_inclusive(0u32, 16) {
735                 let mdf = mdf.with_month(month);
736                 assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
737                 if mdf.valid() {
738                     assert_eq!(mdf.month(), month);
739                     assert_eq!(mdf.day(), day);
740                 }
741             }
742 
743             for day in range_inclusive(0u32, 1024) {
744                 let mdf = mdf.with_day(day);
745                 assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
746                 if mdf.valid() {
747                     assert_eq!(mdf.month(), month);
748                     assert_eq!(mdf.day(), day);
749                 }
750             }
751         }
752 
753         for &flags in NONLEAP_FLAGS.iter() {
754             check(flags, 1, 1);
755             check(flags, 1, 31);
756             check(flags, 2, 1);
757             check(flags, 2, 28);
758             check(flags, 2, 29);
759             check(flags, 12, 31);
760         }
761         for &flags in LEAP_FLAGS.iter() {
762             check(flags, 1, 1);
763             check(flags, 1, 31);
764             check(flags, 2, 1);
765             check(flags, 2, 29);
766             check(flags, 2, 30);
767             check(flags, 12, 31);
768         }
769     }
770 
771     #[test]
test_of_isoweekdate_raw()772     fn test_of_isoweekdate_raw() {
773         for &flags in FLAGS.iter() {
774             // January 4 should be in the first week
775             let (week, _) = Of::new(4 /* January 4 */, flags).isoweekdate_raw();
776             assert_eq!(week, 1);
777         }
778     }
779 
780     #[test]
test_of_to_mdf()781     fn test_of_to_mdf() {
782         for i in range_inclusive(0u32, 8192) {
783             let of = Of(i);
784             assert_eq!(of.valid(), of.to_mdf().valid());
785         }
786     }
787 
788     #[test]
test_mdf_to_of()789     fn test_mdf_to_of() {
790         for i in range_inclusive(0u32, 8192) {
791             let mdf = Mdf(i);
792             assert_eq!(mdf.valid(), mdf.to_of().valid());
793         }
794     }
795 
796     #[test]
test_of_to_mdf_to_of()797     fn test_of_to_mdf_to_of() {
798         for i in range_inclusive(0u32, 8192) {
799             let of = Of(i);
800             if of.valid() {
801                 assert_eq!(of, of.to_mdf().to_of());
802             }
803         }
804     }
805 
806     #[test]
test_mdf_to_of_to_mdf()807     fn test_mdf_to_of_to_mdf() {
808         for i in range_inclusive(0u32, 8192) {
809             let mdf = Mdf(i);
810             if mdf.valid() {
811                 assert_eq!(mdf, mdf.to_of().to_mdf());
812             }
813         }
814     }
815 }
816