|
1 | 1 | // This is a part of Chrono. |
2 | 2 | // See README.md and LICENSE.txt for details. |
3 | 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. |
| 4 | +//! Helper type for working with year flags. |
15 | 5 |
|
16 | 6 | #![cfg_attr(feature = "__internal_bench", allow(missing_docs))] |
17 | 7 |
|
18 | 8 | use core::fmt; |
19 | 9 |
|
20 | | -/// The year flags (aka the dominical letter). |
| 10 | +/// Year flags (aka the dominical letter). |
| 11 | +/// |
| 12 | +/// `YearFlags` are used as the last four bits of `NaiveDate`, `Mdf` and `IsoWeek`. |
21 | 13 | /// |
22 | 14 | /// There are 14 possible classes of year in the Gregorian calendar: |
23 | 15 | /// common and leap years starting with Monday through Sunday. |
24 | | -/// The `YearFlags` stores this information into 4 bits `abbb`, |
25 | | -/// where `a` is `1` for the common year (simplifies the `Of` validation) |
26 | | -/// and `bbb` is a non-zero `Weekday` (mapping `Mon` to 7) of the last day in the past year |
27 | | -/// (simplifies the day of week calculation from the 1-based ordinal). |
| 16 | +/// |
| 17 | +/// The `YearFlags` stores this information into 4 bits `abbb`. `a` is the leap year flag, with `1` |
| 18 | +/// for the common year (this simplifies validating an ordinal in `NaiveDate`). `bbb` is a non-zero |
| 19 | +/// `Weekday` of the last day in the preceding year. |
28 | 20 | #[allow(unreachable_pub)] // public as an alias for benchmarks only |
29 | 21 | #[derive(PartialEq, Eq, Copy, Clone, Hash)] |
30 | 22 | pub struct YearFlags(pub(super) u8); |
31 | 23 |
|
32 | | -pub(super) const A: YearFlags = YearFlags(0o15); |
33 | | -pub(super) const AG: YearFlags = YearFlags(0o05); |
34 | | -pub(super) const B: YearFlags = YearFlags(0o14); |
35 | | -pub(super) const BA: YearFlags = YearFlags(0o04); |
36 | | -pub(super) const C: YearFlags = YearFlags(0o13); |
37 | | -pub(super) const CB: YearFlags = YearFlags(0o03); |
38 | | -pub(super) const D: YearFlags = YearFlags(0o12); |
39 | | -pub(super) const DC: YearFlags = YearFlags(0o02); |
40 | | -pub(super) const E: YearFlags = YearFlags(0o11); |
41 | | -pub(super) const ED: YearFlags = YearFlags(0o01); |
42 | | -pub(super) const F: YearFlags = YearFlags(0o17); |
43 | | -pub(super) const FE: YearFlags = YearFlags(0o07); |
44 | | -pub(super) const G: YearFlags = YearFlags(0o16); |
45 | | -pub(super) const GF: YearFlags = YearFlags(0o06); |
| 24 | +// Weekday of the last day in the preceding year. |
| 25 | +// Allows for quick day of week calculation from the 1-based ordinal). |
| 26 | +const YEAR_STARTS_AFTER_MONDAY: u8 = 7; // non-zero to allow use with `NonZero*`. |
| 27 | +const YEAR_STARTS_AFTER_THUESDAY: u8 = 1; |
| 28 | +const YEAR_STARTS_AFTER_WEDNESDAY: u8 = 2; |
| 29 | +const YEAR_STARTS_AFTER_THURSDAY: u8 = 3; |
| 30 | +const YEAR_STARTS_AFTER_FRIDAY: u8 = 4; |
| 31 | +const YEAR_STARTS_AFTER_SATURDAY: u8 = 5; |
| 32 | +const YEAR_STARTS_AFTER_SUNDAY: u8 = 6; |
| 33 | + |
| 34 | +const COMMON_YEAR: u8 = 1 << 3; |
| 35 | +const LEAP_YEAR: u8 = 0 << 3; |
| 36 | + |
| 37 | +pub(super) const A: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_SATURDAY); |
| 38 | +pub(super) const AG: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_SATURDAY); |
| 39 | +pub(super) const B: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_FRIDAY); |
| 40 | +pub(super) const BA: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_FRIDAY); |
| 41 | +pub(super) const C: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_THURSDAY); |
| 42 | +pub(super) const CB: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_THURSDAY); |
| 43 | +pub(super) const D: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_WEDNESDAY); |
| 44 | +pub(super) const DC: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_WEDNESDAY); |
| 45 | +pub(super) const E: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_THUESDAY); |
| 46 | +pub(super) const ED: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_THUESDAY); |
| 47 | +pub(super) const F: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_MONDAY); |
| 48 | +pub(super) const FE: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_MONDAY); |
| 49 | +pub(super) const G: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_SUNDAY); |
| 50 | +pub(super) const GF: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_SUNDAY); |
46 | 51 |
|
| 52 | +/// Table to look up year flags for any year in the 400-year cycle of the Gregorian calendar. |
47 | 53 | const YEAR_TO_FLAGS: &[YearFlags; 400] = &[ |
48 | 54 | 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, |
49 | 55 | 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, |
@@ -115,7 +121,7 @@ impl fmt::Debug for YearFlags { |
115 | 121 | 0o02 => "DC".fmt(f), |
116 | 122 | 0o11 => "E".fmt(f), |
117 | 123 | 0o01 => "ED".fmt(f), |
118 | | - 0o10 => "F?".fmt(f), |
| 124 | + 0o10 => "F?".fmt(f), // non-canonical |
119 | 125 | 0o00 => "FE?".fmt(f), // non-canonical |
120 | 126 | 0o17 => "F".fmt(f), |
121 | 127 | 0o07 => "FE".fmt(f), |
|
0 commit comments