1#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)]
7
8use crate::size_test_macro::size_test;
9use alloc::borrow::Cow;
10use icu_calendar::types::MonthCode;
11use icu_provider::prelude::*;
12use potential_utf::PotentialUtf8;
13use tinystr::{tinystr, TinyStr4};
14use zerovec::ZeroMap;
15
16size_test!(DateSymbols, date_symbols_v1_size, 3792);
17
18#[doc = date_symbols_v1_size!()]
22#[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
29#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
30#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::calendar))]
31#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
32#[yoke(prove_covariance_manually)]
33pub struct DateSymbols<'data> {
34    #[cfg_attr(feature = "serde", serde(borrow))]
36    pub months: months::Contexts<'data>,
37    #[cfg_attr(feature = "serde", serde(borrow))]
39    pub weekdays: weekdays::Contexts<'data>,
40    #[cfg_attr(feature = "serde", serde(borrow))]
42    pub eras: Eras<'data>,
43}
44
45icu_provider::data_struct!(
46    DateSymbols<'_>,
47    #[cfg(feature = "datagen")]
48);
49
50size_test!(TimeSymbols, time_symbols_v1_size, 768);
51
52#[doc = time_symbols_v1_size!()]
56#[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
63#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
64#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::calendar))]
65#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
66#[yoke(prove_covariance_manually)]
67pub struct TimeSymbols<'data> {
68    #[cfg_attr(feature = "serde", serde(borrow))]
70    pub day_periods: day_periods::Contexts<'data>,
71}
72
73icu_provider::data_struct!(
74    TimeSymbols<'_>,
75    #[cfg(feature = "datagen")]
76);
77
78#[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
95#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
96#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::calendar))]
97#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
98#[yoke(prove_covariance_manually)]
99pub struct Eras<'data> {
100    #[cfg_attr(feature = "serde", serde(borrow))]
104    pub names: ZeroMap<'data, PotentialUtf8, str>,
105    #[cfg_attr(feature = "serde", serde(borrow))]
109    pub abbr: ZeroMap<'data, PotentialUtf8, str>,
110    #[cfg_attr(feature = "serde", serde(borrow))]
114    pub narrow: ZeroMap<'data, PotentialUtf8, str>,
115}
116
117macro_rules! symbols {
120    ($(#[$symbols_attr:meta])*  $name: ident, $field_id: ident, $symbols: item) => {
121
122        $(#[$symbols_attr])*
123        #[doc = concat!("Formatting symbols for [`",
124                stringify!($field_id),
125                "`](crate::provider::fields::FieldSymbol::",
126                stringify!($field_id),
127                ").\n\n",
128                "For more information on date time symbols, see [`FieldSymbol`](crate::provider::fields::FieldSymbol).")]
129        pub mod $name {
130            use super::*;
131
132            #[derive(Debug, PartialEq, Clone, zerofrom::ZeroFrom, yoke::Yokeable)]
133            #[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
134            #[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::calendar::$name))]
135            #[cfg_attr(feature = "serde", derive(serde::Deserialize))]
136            #[yoke(prove_covariance_manually)]
137            #[doc = concat!("Locale data for ", stringify!($field_id), " corresponding to the symbols.")]
138            $symbols
145
146            #[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
149            #[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
150            #[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::calendar::$name))]
151            #[cfg_attr(feature = "serde", derive(serde::Deserialize))]
152            #[yoke(prove_covariance_manually)]
153            #[doc = concat!("Symbol data for the \"format\" style formatting of ", stringify!($field_id),
154                ".\n\nThe format style is used in contexts where it is different from the stand-alone form, ex: ",
155                "a case inflected form where the stand-alone form is the nominative case.")]
156            pub struct FormatWidths<'data> {
163                #[doc = concat!("Abbreviated length symbol for \"format\" style symbol for ", stringify!($name), ".")]
164                #[cfg_attr(feature = "serde", serde(borrow))]
165                pub abbreviated: Symbols<'data>,
166                #[doc = concat!("Narrow length symbol for \"format\" style symbol for ", stringify!($name), ".")]
167                #[cfg_attr(feature = "serde", serde(borrow))]
168                pub narrow: Symbols<'data>,
169                #[doc = concat!("Short length symbol for \"format\" style symbol for ", stringify!($name), ", if present.")]
170                #[cfg_attr(feature = "serde", serde(borrow))]
171                pub short: Option<Symbols<'data>>,
172                #[doc = concat!("Wide length symbol for \"format\" style symbol for ", stringify!($name), ".")]
173                #[cfg_attr(feature = "serde", serde(borrow))]
174                pub wide: Symbols<'data>,
175            }
176
177            #[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
179            #[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
180            #[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::calendar::$name))]
181            #[cfg_attr(feature = "serde", derive(serde::Deserialize))]
182            #[yoke(prove_covariance_manually)]
183            #[doc = concat!("Symbol data for the \"stand-alone\" style formatting of ", stringify!($field_id),
184                ".\n\nThe stand-alone style is used in contexts where the field is displayed by itself.")]
185            pub struct StandAloneWidths<'data> {
192                #[doc = concat!("Abbreviated length symbol for \"stand-alone\" style symbol for ", stringify!($name), ".")]
193                #[cfg_attr(feature = "serde", serde(borrow))]
194                pub abbreviated: Option<Symbols<'data>>,
195                #[doc = concat!("Narrow length symbol for \"stand-alone\" style symbol for ", stringify!($name), ".")]
196                #[cfg_attr(feature = "serde", serde(borrow))]
197                pub narrow: Option<Symbols<'data>>,
198                #[doc = concat!("Short length symbol for \"stand-alone\" style symbol for ", stringify!($name), ".")]
199                #[cfg_attr(feature = "serde", serde(borrow))]
200                pub short: Option<Symbols<'data>>,
201                #[doc = concat!("Wide length symbol for \"stand-alone\" style symbol for ", stringify!($name), ".")]
202                #[cfg_attr(feature = "serde", serde(borrow))]
203                pub wide: Option<Symbols<'data>>,
204            }
205
206            #[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
207            #[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
208            #[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::calendar::$name))]
209            #[cfg_attr(feature = "serde", derive(serde::Deserialize))]
210            #[yoke(prove_covariance_manually)]
211            #[doc = concat!("The struct containing the symbol data for ", stringify!($field_id),
212                " that contains the \"format\" style symbol data ([`FormatWidths`]) and \"stand-alone\" style symbol data ([`StandAloneWidths`]).")]
213            pub struct Contexts<'data> {
220                #[cfg_attr(feature = "serde", serde(borrow))]
222                pub format: FormatWidths<'data>,
223                #[cfg_attr(feature = "serde", serde(borrow))]
225                pub stand_alone: Option<StandAloneWidths<'data>>,
226            }
227        }
228    };
229}
230
231symbols!(
232    months,
233    Month,
234    #[allow(clippy::large_enum_variant)]
235    pub enum Symbols<'data> {
236        SolarTwelve(
240            #[cfg_attr(
241                feature = "serde",
242                serde(
243                    borrow,
244                    deserialize_with = "icu_provider::serde_borrow_de_utils::array_of_cow"
245                )
246            )]
247            [Cow<'data, str>; 12],
248        ),
249        #[cfg_attr(feature = "serde", serde(borrow))]
251        Other(ZeroMap<'data, MonthCode, str>),
252    }
253);
254
255impl months::Symbols<'_> {
256    pub fn get(&self, code: MonthCode) -> Option<&str> {
258        match *self {
259            Self::SolarTwelve(ref arr) => {
260                const CODE_1: TinyStr4 = tinystr!(4, "M01");
263                const CODE_2: TinyStr4 = tinystr!(4, "M02");
264                const CODE_3: TinyStr4 = tinystr!(4, "M03");
265                const CODE_4: TinyStr4 = tinystr!(4, "M04");
266                const CODE_5: TinyStr4 = tinystr!(4, "M05");
267                const CODE_6: TinyStr4 = tinystr!(4, "M06");
268                const CODE_7: TinyStr4 = tinystr!(4, "M07");
269                const CODE_8: TinyStr4 = tinystr!(4, "M08");
270                const CODE_9: TinyStr4 = tinystr!(4, "M09");
271                const CODE_10: TinyStr4 = tinystr!(4, "M10");
272                const CODE_11: TinyStr4 = tinystr!(4, "M11");
273                const CODE_12: TinyStr4 = tinystr!(4, "M12");
274                let idx = match code.0 {
275                    CODE_1 => 0,
276                    CODE_2 => 1,
277                    CODE_3 => 2,
278                    CODE_4 => 3,
279                    CODE_5 => 4,
280                    CODE_6 => 5,
281                    CODE_7 => 6,
282                    CODE_8 => 7,
283                    CODE_9 => 8,
284                    CODE_10 => 9,
285                    CODE_11 => 10,
286                    CODE_12 => 11,
287                    _ => return None,
288                };
289                arr.get(idx).map(|x| &**x)
290            }
291            Self::Other(ref map) => map.get(&code),
292        }
293    }
294}
295
296impl Default for months::Symbols<'_> {
297    fn default() -> Self {
298        Self::Other(Default::default())
299    }
300}
301
302symbols!(
303    weekdays,
304    Weekday,
305    #[derive(Default)]
306    pub struct Symbols<'data>(
307        #[cfg_attr(
308            feature = "serde",
309            serde(
310                borrow,
311                deserialize_with = "icu_provider::serde_borrow_de_utils::array_of_cow"
312            )
313        )]
314        pub [Cow<'data, str>; 7],
315    );
316);
317
318symbols!(
319    day_periods,
320    DayPeriod,
321    #[derive(Default)]
322    pub struct Symbols<'data> {
323        #[cfg_attr(feature = "serde", serde(borrow))]
325        pub am: Cow<'data, str>,
326        #[cfg_attr(feature = "serde", serde(borrow))]
328        pub pm: Cow<'data, str>,
329        #[cfg_attr(
330            feature = "serde",
331            serde(
332                borrow,
333                deserialize_with = "icu_provider::serde_borrow_de_utils::option_of_cow"
334            )
335        )]
336        pub noon: Option<Cow<'data, str>>,
338        #[cfg_attr(
339            feature = "serde",
340            serde(
341                borrow,
342                deserialize_with = "icu_provider::serde_borrow_de_utils::option_of_cow"
343            )
344        )]
345        pub midnight: Option<Cow<'data, str>>,
347    }
348);
349
350#[cfg(all(test, feature = "datagen"))]
351mod test {
352    use super::*;
353    use tinystr::tinystr;
354
355    fn serialize_date() -> Vec<u8> {
356        let months = [
357            (&MonthCode(tinystr!(4, "M01")), "January"),
358            (&MonthCode(tinystr!(4, "M02")), "February"),
359            (&MonthCode(tinystr!(4, "M03")), "March"),
360            (&MonthCode(tinystr!(4, "M04")), "April"),
361            (&MonthCode(tinystr!(4, "M05")), "May"),
362            (&MonthCode(tinystr!(4, "M06")), "June"),
363            (&MonthCode(tinystr!(4, "M07")), "July"),
364            (&MonthCode(tinystr!(4, "M08")), "August"),
365            (&MonthCode(tinystr!(4, "M09")), "September"),
366            (&MonthCode(tinystr!(4, "M10")), "October"),
367            (&MonthCode(tinystr!(4, "M11")), "November"),
368            (&MonthCode(tinystr!(4, "M12")), "December"),
369        ];
370        let months = months::Symbols::Other(months.iter().copied().collect());
371
372        let weekdays = weekdays::Symbols([
373            Cow::Borrowed("Monday"),
374            Cow::Borrowed("Tuesday"),
375            Cow::Borrowed("Wednesday"),
376            Cow::Borrowed("Thursday"),
377            Cow::Borrowed("Friday"),
378            Cow::Borrowed("Saturday"),
379            Cow::Borrowed("Sunday"),
380        ]);
381
382        bincode::serialize(&DateSymbols {
383            months: months::Contexts {
384                format: months::FormatWidths {
385                    abbreviated: months.clone(),
386                    narrow: months.clone(),
387                    short: Some(months.clone()),
388                    wide: months.clone(),
389                },
390                stand_alone: Some(months::StandAloneWidths {
391                    abbreviated: Some(months.clone()),
392                    narrow: Some(months.clone()),
393                    short: Some(months.clone()),
394                    wide: Some(months.clone()),
395                }),
396            },
397            weekdays: weekdays::Contexts {
398                format: weekdays::FormatWidths {
399                    abbreviated: weekdays.clone(),
400                    narrow: weekdays.clone(),
401                    short: Some(weekdays.clone()),
402                    wide: weekdays.clone(),
403                },
404                stand_alone: Some(weekdays::StandAloneWidths {
405                    abbreviated: Some(weekdays.clone()),
406                    narrow: Some(weekdays.clone()),
407                    short: Some(weekdays.clone()),
408                    wide: Some(weekdays.clone()),
409                }),
410            },
411            eras: Eras {
412                names: ZeroMap::new(),
413                abbr: ZeroMap::new(),
414                narrow: ZeroMap::new(),
415            },
416        })
417        .unwrap()
418    }
419
420    fn serialize_time() -> Vec<u8> {
421        let day_periods = day_periods::Symbols {
422            am: Cow::Borrowed("am"),
423            pm: Cow::Borrowed("pm"),
424            noon: Some(Cow::Borrowed("noon")),
425            midnight: None,
426        };
427
428        bincode::serialize(&TimeSymbols {
429            day_periods: day_periods::Contexts {
430                format: day_periods::FormatWidths {
431                    abbreviated: day_periods.clone(),
432                    narrow: day_periods.clone(),
433                    short: Some(day_periods.clone()),
434                    wide: day_periods.clone(),
435                },
436                stand_alone: Some(day_periods::StandAloneWidths {
437                    abbreviated: Some(day_periods.clone()),
438                    narrow: Some(day_periods.clone()),
439                    short: Some(day_periods.clone()),
440                    wide: Some(day_periods.clone()),
441                }),
442            },
443        })
444        .unwrap()
445    }
446
447    #[test]
448    fn weekdays_borrows() {
449        let bytes = serialize_date();
450        let de = bincode::deserialize::<DateSymbols>(&bytes).unwrap();
451
452        assert!(matches!(de.weekdays.format.narrow.0[2], Cow::Borrowed(_)));
453        assert!(matches!(
454            de.weekdays.format.short.as_ref().unwrap().0[4],
455            Cow::Borrowed(_)
456        ));
457    }
458
459    #[test]
460    fn day_periods_borrows() {
461        let bytes = serialize_time();
462        let de = bincode::deserialize::<TimeSymbols>(&bytes).unwrap();
463
464        assert!(matches!(
465            de.day_periods.format.narrow.noon,
466            Some(Cow::Borrowed(_))
467        ));
468        assert!(matches!(
469            de.day_periods.format.short.as_ref().unwrap().noon,
470            Some(Cow::Borrowed(_))
471        ));
472
473        assert!(matches!(de.day_periods.format.narrow.am, Cow::Borrowed(_)));
474        assert!(matches!(
475            de.day_periods.format.short.as_ref().unwrap().am,
476            Cow::Borrowed(_)
477        ));
478    }
479}