1#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)]
17
18pub mod chinese_based;
19pub mod islamic;
20pub use chinese_based::{ChineseCacheV1Marker, DangiCacheV1Marker};
21pub use islamic::{IslamicObservationalCacheV1Marker, IslamicUmmAlQuraCacheV1Marker};
22
23use crate::types::IsoWeekday;
24use core::str::FromStr;
25use icu_provider::prelude::*;
26use tinystr::TinyStr16;
27use zerovec::ZeroVec;
28
29#[cfg(feature = "compiled_data")]
30#[derive(Debug)]
31pub struct Baked;
39
40#[cfg(feature = "compiled_data")]
41const _: () = {
42 pub mod icu {
43 pub use crate as calendar;
44 #[allow(unused_imports)] pub use icu_locid_transform as locid_transform;
46 }
47 icu_calendar_data::make_provider!(Baked);
48 icu_calendar_data::impl_calendar_chinesecache_v1!(Baked);
49 icu_calendar_data::impl_calendar_dangicache_v1!(Baked);
50 icu_calendar_data::impl_calendar_islamicobservationalcache_v1!(Baked);
51 icu_calendar_data::impl_calendar_islamicummalquracache_v1!(Baked);
52 icu_calendar_data::impl_calendar_japanese_v1!(Baked);
53 icu_calendar_data::impl_calendar_japanext_v1!(Baked);
54 icu_calendar_data::impl_datetime_week_data_v1!(Baked);
55 icu_calendar_data::impl_datetime_week_data_v2!(Baked);
56};
57
58#[cfg(feature = "datagen")]
59pub const KEYS: &[DataKey] = &[
61 ChineseCacheV1Marker::KEY,
62 DangiCacheV1Marker::KEY,
63 IslamicObservationalCacheV1Marker::KEY,
64 IslamicUmmAlQuraCacheV1Marker::KEY,
65 JapaneseErasV1Marker::KEY,
66 JapaneseExtendedErasV1Marker::KEY,
67 WeekDataV2Marker::KEY,
68 WeekDataV1Marker::KEY,
71];
72
73#[zerovec::make_ule(EraStartDateULE)]
83#[derive(
84 Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, yoke::Yokeable, zerofrom::ZeroFrom,
85)]
86#[cfg_attr(
87 feature = "datagen",
88 derive(serde::Serialize, databake::Bake),
89 databake(path = icu_calendar::provider),
90)]
91#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
92pub struct EraStartDate {
93 pub year: i32,
95 pub month: u8,
97 pub day: u8,
99}
100
101#[icu_provider::data_struct(
110 marker(JapaneseErasV1Marker, "calendar/japanese@1", singleton),
111 marker(JapaneseExtendedErasV1Marker, "calendar/japanext@1", singleton)
112)]
113#[derive(Debug, PartialEq, Clone, Default)]
114#[cfg_attr(
115 feature = "datagen",
116 derive(serde::Serialize, databake::Bake),
117 databake(path = icu_calendar::provider),
118)]
119#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
120pub struct JapaneseErasV1<'data> {
121 #[cfg_attr(feature = "serde", serde(borrow))]
123 pub dates_to_eras: ZeroVec<'data, (EraStartDate, TinyStr16)>,
124}
125
126impl FromStr for EraStartDate {
127 type Err = ();
128 fn from_str(mut s: &str) -> Result<Self, Self::Err> {
129 let sign = if let Some(suffix) = s.strip_prefix('-') {
130 s = suffix;
131 -1
132 } else {
133 1
134 };
135
136 let mut split = s.split('-');
137 let year = split.next().ok_or(())?.parse::<i32>().map_err(|_| ())? * sign;
138 let month = split.next().ok_or(())?.parse().map_err(|_| ())?;
139 let day = split.next().ok_or(())?.parse().map_err(|_| ())?;
140
141 Ok(EraStartDate { year, month, day })
142 }
143}
144
145#[icu_provider::data_struct(marker(
154 WeekDataV1Marker,
155 "datetime/week_data@1",
156 fallback_by = "region"
157))]
158#[derive(Clone, Copy, Debug, PartialEq)]
159#[cfg_attr(
160 feature = "datagen",
161 derive(serde::Serialize, databake::Bake),
162 databake(path = icu_calendar::provider),
163)]
164#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
165#[allow(clippy::exhaustive_structs)] pub struct WeekDataV1 {
167 pub first_weekday: IsoWeekday,
169 pub min_week_days: u8,
171}
172
173#[icu_provider::data_struct(marker(
182 WeekDataV2Marker,
183 "datetime/week_data@2",
184 fallback_by = "region"
185))]
186#[derive(Clone, Copy, Debug, PartialEq)]
187#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake), databake(path = icu_calendar::provider))]
188#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
189#[allow(clippy::exhaustive_structs)] pub struct WeekDataV2 {
191 pub first_weekday: IsoWeekday,
193 pub min_week_days: u8,
195 pub weekend: WeekdaySet,
198}
199
200#[derive(Clone, Copy, Debug, PartialEq)]
219pub struct WeekdaySet(u8);
220
221impl WeekdaySet {
222 pub const fn contains(&self, day: IsoWeekday) -> bool {
224 self.0 & day.bit_value() != 0
225 }
226}
227
228impl WeekdaySet {
229 pub const fn new(days: &[IsoWeekday]) -> Self {
231 let mut i = 0;
232 let mut w = 0;
233 #[allow(clippy::indexing_slicing)]
234 while i < days.len() {
235 w |= days[i].bit_value();
236 i += 1;
237 }
238 Self(w)
239 }
240}
241
242impl IsoWeekday {
243 const fn bit_value(&self) -> u8 {
245 match self {
246 IsoWeekday::Monday => 1 << 6,
247 IsoWeekday::Tuesday => 1 << 5,
248 IsoWeekday::Wednesday => 1 << 4,
249 IsoWeekday::Thursday => 1 << 3,
250 IsoWeekday::Friday => 1 << 2,
251 IsoWeekday::Saturday => 1 << 1,
252 IsoWeekday::Sunday => 1 << 0,
253 }
254 }
255}
256
257#[cfg(feature = "datagen")]
258impl databake::Bake for WeekdaySet {
259 fn bake(&self, ctx: &databake::CrateEnv) -> databake::TokenStream {
260 ctx.insert("icu_calendar");
261 let days =
262 crate::week_of::WeekdaySetIterator::new(IsoWeekday::Monday, *self).map(|d| d.bake(ctx));
263 databake::quote! {
264 icu_calendar::provider::WeekdaySet::new(&[#(#days),*])
265 }
266 }
267}
268
269#[cfg(feature = "datagen")]
270impl serde::Serialize for WeekdaySet {
271 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
272 where
273 S: serde::Serializer,
274 {
275 if serializer.is_human_readable() {
276 crate::week_of::WeekdaySetIterator::new(IsoWeekday::Monday, *self)
277 .collect::<alloc::vec::Vec<_>>()
278 .serialize(serializer)
279 } else {
280 self.0.serialize(serializer)
281 }
282 }
283}
284
285#[cfg(feature = "serde")]
286impl<'de> serde::Deserialize<'de> for WeekdaySet {
287 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
288 where
289 D: serde::Deserializer<'de>,
290 {
291 if deserializer.is_human_readable() {
292 alloc::vec::Vec::<IsoWeekday>::deserialize(deserializer).map(|s| Self::new(&s))
293 } else {
294 u8::deserialize(deserializer).map(Self)
295 }
296 }
297}
298
299#[test]
300fn test_weekdayset_bake() {
301 databake::test_bake!(
302 WeekdaySet,
303 const: crate::provider::WeekdaySet::new(
304 &[crate::types::IsoWeekday::Monday, crate::types::IsoWeekday::Wednesday, crate::types::IsoWeekday::Friday]),
305 icu_calendar
306 );
307}
308
309#[test]
310fn test_weekdayset_new() {
311 use IsoWeekday::*;
312
313 let sat_sun_bitmap = Saturday.bit_value() | Sunday.bit_value();
314 let sat_sun_weekend = WeekdaySet::new(&[Saturday, Sunday]);
315 assert_eq!(sat_sun_bitmap, sat_sun_weekend.0);
316
317 let fri_sat_bitmap = Friday.bit_value() | Saturday.bit_value();
318 let fri_sat_weekend = WeekdaySet::new(&[Friday, Saturday]);
319 assert_eq!(fri_sat_bitmap, fri_sat_weekend.0);
320
321 let fri_sun_bitmap = Friday.bit_value() | Sunday.bit_value();
322 let fri_sun_weekend = WeekdaySet::new(&[Friday, Sunday]);
323 assert_eq!(fri_sun_bitmap, fri_sun_weekend.0);
324
325 let fri_bitmap = Friday.bit_value();
326 let fri_weekend = WeekdaySet::new(&[Friday, Friday]);
327 assert_eq!(fri_bitmap, fri_weekend.0);
328
329 let sun_mon_bitmap = Sunday.bit_value() | Monday.bit_value();
330 let sun_mon_weekend = WeekdaySet::new(&[Sunday, Monday]);
331 assert_eq!(sun_mon_bitmap, sun_mon_weekend.0);
332
333 let mon_sun_bitmap = Monday.bit_value() | Sunday.bit_value();
334 let mon_sun_weekend = WeekdaySet::new(&[Monday, Sunday]);
335 assert_eq!(mon_sun_bitmap, mon_sun_weekend.0);
336
337 let mon_bitmap = Monday.bit_value();
338 let mon_weekend = WeekdaySet::new(&[Monday]);
339 assert_eq!(mon_bitmap, mon_weekend.0);
340}