icu_calendar/
provider.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5//! 🚧 \[Unstable\] Data provider struct definitions for this ICU4X component.
6//!
7//! <div class="stab unstable">
8//! 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
9//! including in SemVer minor releases. While the serde representation of data structs is guaranteed
10//! to be stable, their Rust representation might not be. Use with caution.
11//! </div>
12//!
13//! Read more about data providers: [`icu_provider`]
14
15// Provider structs must be stable
16#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)]
17
18pub mod chinese_based;
19pub mod hijri;
20pub use chinese_based::{CalendarChineseV1, CalendarDangiV1};
21pub use hijri::CalendarHijriSimulatedMeccaV1;
22
23use crate::types::Weekday;
24use icu_provider::fallback::{LocaleFallbackConfig, LocaleFallbackPriority};
25use icu_provider::prelude::*;
26use tinystr::TinyStr16;
27use zerovec::ZeroVec;
28
29#[cfg(feature = "compiled_data")]
30#[derive(Debug)]
31/// Baked data
32///
33/// <div class="stab unstable">
34/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
35/// including in SemVer minor releases. In particular, the `DataProvider` implementations are only
36/// guaranteed to match with this version's `*_unstable` providers. Use with caution.
37/// </div>
38pub struct Baked;
39
40#[cfg(feature = "compiled_data")]
41#[allow(unused_imports)]
42const _: () = {
43    use icu_calendar_data::*;
44    pub mod icu {
45        pub use crate as calendar;
46        pub use icu_locale as locale;
47    }
48    make_provider!(Baked);
49    impl_calendar_chinese_v1!(Baked);
50    impl_calendar_dangi_v1!(Baked);
51    impl_calendar_hijri_simulated_mecca_v1!(Baked);
52    impl_calendar_japanese_modern_v1!(Baked);
53    impl_calendar_japanese_extended_v1!(Baked);
54    impl_calendar_week_v1!(Baked);
55};
56
57icu_provider::data_marker!(
58    /// Modern Japanese era names
59    CalendarJapaneseModernV1,
60    "calendar/japanese/modern/v1",
61    JapaneseEras<'static>,
62    is_singleton = true
63);
64icu_provider::data_marker!(
65    /// Full Japanese era names
66    CalendarJapaneseExtendedV1,
67    "calendar/japanese/extended/v1",
68    JapaneseEras<'static>,
69    is_singleton = true
70);
71icu_provider::data_marker!(
72    /// Week information
73    CalendarWeekV1,
74    "calendar/week/v1",
75    WeekData,
76    fallback_config = {
77        let mut config = LocaleFallbackConfig::default();
78        config.priority = LocaleFallbackPriority::Region;
79        config
80    },
81);
82
83#[cfg(feature = "datagen")]
84/// The latest minimum set of markers required by this component.
85pub const MARKERS: &[DataMarkerInfo] = &[
86    CalendarChineseV1::INFO,
87    CalendarDangiV1::INFO,
88    CalendarHijriSimulatedMeccaV1::INFO,
89    CalendarJapaneseModernV1::INFO,
90    CalendarJapaneseExtendedV1::INFO,
91    CalendarWeekV1::INFO,
92];
93
94/// The date at which an era started
95///
96/// The order of fields in this struct is important!
97///
98/// <div class="stab unstable">
99/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
100/// including in SemVer minor releases. While the serde representation of data structs is guaranteed
101/// to be stable, their Rust representation might not be. Use with caution.
102/// </div>
103#[zerovec::make_ule(EraStartDateULE)]
104#[derive(
105    Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, yoke::Yokeable, zerofrom::ZeroFrom,
106)]
107#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
108#[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider))]
109#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
110pub struct EraStartDate {
111    /// The year the era started in
112    pub year: i32,
113    /// The month the era started in
114    pub month: u8,
115    /// The day the era started in
116    pub day: u8,
117}
118
119/// A data structure containing the necessary era data for constructing a
120/// [`Japanese`](crate::cal::Japanese) calendar object
121///
122/// <div class="stab unstable">
123/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
124/// including in SemVer minor releases. While the serde representation of data structs is guaranteed
125/// to be stable, their Rust representation might not be. Use with caution.
126/// </div>
127#[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
128#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
129#[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider))]
130#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
131pub struct JapaneseEras<'data> {
132    /// A map from era start dates to their era codes
133    #[cfg_attr(feature = "serde", serde(borrow))]
134    pub dates_to_eras: ZeroVec<'data, (EraStartDate, TinyStr16)>,
135}
136
137icu_provider::data_struct!(
138    JapaneseEras<'_>,
139    #[cfg(feature = "datagen")]
140);
141
142/// An ICU4X mapping to a subset of CLDR weekData.
143/// See CLDR-JSON's weekData.json for more context.
144///
145/// <div class="stab unstable">
146/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
147/// including in SemVer minor releases. While the serde representation of data structs is guaranteed
148/// to be stable, their Rust representation might not be. Use with caution.
149/// </div>
150#[derive(Clone, Copy, Debug, PartialEq, yoke::Yokeable, zerofrom::ZeroFrom)]
151#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
152#[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider))]
153#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
154#[allow(clippy::exhaustive_structs)] // used in data provider
155pub struct WeekData {
156    /// The first day of a week.
157    pub first_weekday: Weekday,
158    /// Bitset representing weekdays that are part of the 'weekend', for calendar purposes.
159    /// The number of days can be different between locales, and may not be contiguous.
160    pub weekend: WeekdaySet,
161}
162
163icu_provider::data_struct!(
164    WeekData,
165    #[cfg(feature = "datagen")]
166);
167
168/// Bitset representing weekdays.
169//
170// This Bitset uses an [u8] to represent the weekend, thus leaving one bit free.
171// Each bit represents a day in the following order:
172//
173//   β”Œβ–·Mon
174//   β”‚β”Œβ–·Tue
175//   β”‚β”‚β”Œβ–·Wed
176//   β”‚β”‚β”‚β”Œβ–·Thu
177//   β”‚β”‚β”‚β”‚ β”Œβ–·Fri
178//   β”‚β”‚β”‚β”‚ β”‚β”Œβ–·Sat
179//   β”‚β”‚β”‚β”‚ β”‚β”‚β”Œβ–·Sun
180//   β”‚β”‚β”‚β”‚ β”‚β”‚β”‚
181// 0b0000_1010
182//
183// Please note that this is not a range, this are the discrete days representing a weekend. Other examples:
184// 0b0101_1000 -> Tue, Thu, Fri
185// 0b0000_0110 -> Sat, Sun
186#[derive(Clone, Copy, Debug, PartialEq)]
187pub struct WeekdaySet(u8);
188
189impl WeekdaySet {
190    /// Returns whether the set contains the day.
191    pub const fn contains(&self, day: Weekday) -> bool {
192        self.0 & day.bit_value() != 0
193    }
194}
195
196impl WeekdaySet {
197    /// Creates a new [WeekdaySet] using the provided days.
198    pub const fn new(days: &[Weekday]) -> Self {
199        let mut i = 0;
200        let mut w = 0;
201        #[allow(clippy::indexing_slicing)]
202        while i < days.len() {
203            w |= days[i].bit_value();
204            i += 1;
205        }
206        Self(w)
207    }
208}
209
210impl Weekday {
211    /// Defines the bit order used for encoding and reading weekend days.
212    const fn bit_value(self) -> u8 {
213        match self {
214            Weekday::Monday => 1 << 6,
215            Weekday::Tuesday => 1 << 5,
216            Weekday::Wednesday => 1 << 4,
217            Weekday::Thursday => 1 << 3,
218            Weekday::Friday => 1 << 2,
219            Weekday::Saturday => 1 << 1,
220            Weekday::Sunday => 1 << 0,
221        }
222    }
223}
224
225#[cfg(feature = "datagen")]
226impl databake::Bake for WeekdaySet {
227    fn bake(&self, ctx: &databake::CrateEnv) -> databake::TokenStream {
228        ctx.insert("icu_calendar");
229        let days =
230            crate::week::WeekdaySetIterator::new(Weekday::Monday, *self).map(|d| d.bake(ctx));
231        databake::quote! {
232            icu_calendar::provider::WeekdaySet::new(&[#(#days),*])
233        }
234    }
235}
236
237#[cfg(feature = "datagen")]
238impl databake::BakeSize for WeekdaySet {
239    fn borrows_size(&self) -> usize {
240        0
241    }
242}
243
244#[cfg(feature = "datagen")]
245impl serde::Serialize for WeekdaySet {
246    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
247    where
248        S: serde::Serializer,
249    {
250        if serializer.is_human_readable() {
251            use serde::ser::SerializeSeq;
252
253            let mut seq = serializer.serialize_seq(None)?;
254            for day in crate::week::WeekdaySetIterator::new(Weekday::Monday, *self) {
255                seq.serialize_element(&day)?;
256            }
257            seq.end()
258        } else {
259            self.0.serialize(serializer)
260        }
261    }
262}
263
264#[cfg(feature = "serde")]
265impl<'de> serde::Deserialize<'de> for WeekdaySet {
266    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
267    where
268        D: serde::Deserializer<'de>,
269    {
270        if deserializer.is_human_readable() {
271            use core::marker::PhantomData;
272
273            struct Visitor<'de>(PhantomData<&'de ()>);
274            impl<'de> serde::de::Visitor<'de> for Visitor<'de> {
275                type Value = WeekdaySet;
276                fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
277                    core::write!(f, "a sequence of Weekdays")
278                }
279                fn visit_seq<A: serde::de::SeqAccess<'de>>(
280                    self,
281                    mut seq: A,
282                ) -> Result<Self::Value, A::Error> {
283                    let mut set = WeekdaySet::new(&[]);
284                    while let Some(day) = seq.next_element::<Weekday>()? {
285                        set.0 |= day.bit_value();
286                    }
287                    Ok(set)
288                }
289            }
290            deserializer.deserialize_seq(Visitor(PhantomData))
291        } else {
292            u8::deserialize(deserializer).map(Self)
293        }
294    }
295}
296
297#[test]
298fn test_weekdayset_bake() {
299    databake::test_bake!(
300        WeekdaySet,
301        const,
302        crate::provider::WeekdaySet::new(&[
303            crate::types::Weekday::Monday,
304            crate::types::Weekday::Wednesday,
305            crate::types::Weekday::Friday
306        ]),
307        icu_calendar
308    );
309}
310
311#[test]
312fn test_weekdayset_new() {
313    use Weekday::*;
314
315    let sat_sun_bitmap = Saturday.bit_value() | Sunday.bit_value();
316    let sat_sun_weekend = WeekdaySet::new(&[Saturday, Sunday]);
317    assert_eq!(sat_sun_bitmap, sat_sun_weekend.0);
318
319    let fri_sat_bitmap = Friday.bit_value() | Saturday.bit_value();
320    let fri_sat_weekend = WeekdaySet::new(&[Friday, Saturday]);
321    assert_eq!(fri_sat_bitmap, fri_sat_weekend.0);
322
323    let fri_sun_bitmap = Friday.bit_value() | Sunday.bit_value();
324    let fri_sun_weekend = WeekdaySet::new(&[Friday, Sunday]);
325    assert_eq!(fri_sun_bitmap, fri_sun_weekend.0);
326
327    let fri_bitmap = Friday.bit_value();
328    let fri_weekend = WeekdaySet::new(&[Friday, Friday]);
329    assert_eq!(fri_bitmap, fri_weekend.0);
330
331    let sun_mon_bitmap = Sunday.bit_value() | Monday.bit_value();
332    let sun_mon_weekend = WeekdaySet::new(&[Sunday, Monday]);
333    assert_eq!(sun_mon_bitmap, sun_mon_weekend.0);
334
335    let mon_sun_bitmap = Monday.bit_value() | Sunday.bit_value();
336    let mon_sun_weekend = WeekdaySet::new(&[Monday, Sunday]);
337    assert_eq!(mon_sun_bitmap, mon_sun_weekend.0);
338
339    let mon_bitmap = Monday.bit_value();
340    let mon_weekend = WeekdaySet::new(&[Monday]);
341    assert_eq!(mon_bitmap, mon_weekend.0);
342}